dsh-ds-balance 2.1.1 → 2.1.2

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
@@ -198,7 +198,10 @@ var en = {
198
198
  "dev.hint": "UI development only; does not affect real configuration."
199
199
  };
200
200
  function interpolate(template, params) {
201
- return template.replace(/\{(\w+)\}/g, (whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? params[name] : whole);
201
+ return template.replace(
202
+ /\{(\w+)\}/g,
203
+ (whole, name) => Object.prototype.hasOwnProperty.call(params, name) ? params[name] : whole
204
+ );
202
205
  }
203
206
 
204
207
  // src/client/settings/fields.tsx
@@ -230,7 +233,6 @@ var fields_default = {
230
233
  groupNote: "fields_groupNote",
231
234
  fields: "fields_fields",
232
235
  details: "fields_details",
233
- detailsSummary: "fields_detailsSummary",
234
236
  detailsBody: "fields_detailsBody",
235
237
  field: "fields_field",
236
238
  row: "fields_row",
@@ -241,10 +243,10 @@ var fields_default = {
241
243
  label: "fields_label",
242
244
  badges: "fields_badges",
243
245
  reset: "fields_reset",
244
- input: "fields_input",
245
246
  inputStatic: "fields_inputStatic",
246
247
  inputInvalid: "fields_inputInvalid",
247
248
  inputWithAction: "fields_inputWithAction",
249
+ input: "fields_input",
248
250
  reveal: "fields_reveal",
249
251
  revealOn: "fields_revealOn",
250
252
  selectorAnchor: "fields_selectorAnchor",
@@ -254,7 +256,6 @@ var fields_default = {
254
256
  pairNote: "fields_pairNote",
255
257
  invalid: "fields_invalid",
256
258
  actions: "fields_actions",
257
- actionButton: "fields_actionButton",
258
259
  resultOk: "fields_resultOk",
259
260
  resultFail: "fields_resultFail"
260
261
  };
@@ -322,10 +323,10 @@ function FieldFrame(props) {
322
323
  }
323
324
  function TextControl(props) {
324
325
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
325
- "input",
326
+ import_dsh_client_ui_primitives.Input,
326
327
  {
327
328
  id: props.id,
328
- className: props.invalid ? fields_default.inputInvalid : fields_default.input,
329
+ className: props.invalid ? fields_default.inputInvalid : void 0,
329
330
  type: "text",
330
331
  ...props.numeric ? { inputMode: "numeric" } : {},
331
332
  ...props.invalid ? { "aria-invalid": true } : {},
@@ -340,10 +341,10 @@ function TextControl(props) {
340
341
  }
341
342
  function ReadOnlyControl(props) {
342
343
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
343
- "input",
344
+ import_dsh_client_ui_primitives.Input,
344
345
  {
345
346
  id: props.id,
346
- className: clsx_default(fields_default.input, fields_default.inputStatic),
347
+ className: fields_default.inputStatic,
347
348
  type: "text",
348
349
  value: "",
349
350
  readOnly: true
@@ -352,20 +353,20 @@ function ReadOnlyControl(props) {
352
353
  }
353
354
  function DetailsGroup(props) {
354
355
  const [open, setOpen] = (0, import_react.useState)(props.defaultOpen === true);
355
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
356
- "details",
356
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.details, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
357
+ import_dsh_client_ui_primitives.DisclosureRow,
357
358
  {
358
- className: fields_default.details,
359
+ icon: null,
360
+ title: props.title,
359
361
  open,
360
- onToggle: (event) => {
361
- setOpen(event.currentTarget.open);
362
+ expandable: true,
363
+ expandOnRowClick: true,
364
+ onToggle: () => {
365
+ setOpen((value) => !value);
362
366
  },
363
- children: [
364
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { className: fields_default.detailsSummary, children: props.title }),
365
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.detailsBody, children: props.children })
366
- ]
367
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.detailsBody, children: props.children })
367
368
  }
368
- );
369
+ ) });
369
370
  }
370
371
  function SelectorControl(props) {
371
372
  const [open, setOpen] = (0, import_react.useState)(false);
@@ -411,10 +412,10 @@ function SelectorControl(props) {
411
412
  function ActionRow(props) {
412
413
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
413
414
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
414
- "button",
415
+ import_dsh_client_ui_primitives.Button,
415
416
  {
416
417
  type: "button",
417
- className: fields_default.actionButton,
418
+ variant: "outline",
418
419
  disabled: props.disabled,
419
420
  onClick: props.onClick,
420
421
  children: props.label
@@ -469,7 +470,13 @@ function selectField(field) {
469
470
  var AUTO_CURRENCY = "auto";
470
471
  var KNOWN_CURRENCIES = ["CNY", "USD"];
471
472
  var THRESHOLD_PAIRS = [
472
- { currency: "CNY", warn: "cnyWarn", critical: "cnyCritical", defaultWarn: 10, defaultCritical: 5 },
473
+ {
474
+ currency: "CNY",
475
+ warn: "cnyWarn",
476
+ critical: "cnyCritical",
477
+ defaultWarn: 10,
478
+ defaultCritical: 5
479
+ },
473
480
  { currency: "USD", warn: "usdWarn", critical: "usdCritical", defaultWarn: 2, defaultCritical: 1 }
474
481
  ];
475
482
  function pairNumber(state, fallback) {
@@ -512,8 +519,10 @@ var SPEC_BY_FIELD = new Map(
512
519
  var TEST_LATENCY_MS = 800;
513
520
  function probeFailure(baseUrl, apiKey, apiKeyRef) {
514
521
  const url = baseUrl.trim();
515
- if (url !== "" && !/^https?:\/\//i.test(url)) return "base URL must start with http:// or https://";
516
- if (apiKey.trim() === "" && apiKeyRef.trim() === "") return "no API key or credential reference configured";
522
+ if (url !== "" && !/^https?:\/\//i.test(url))
523
+ return "base URL must start with http:// or https://";
524
+ if (apiKey.trim() === "" && apiKeyRef.trim() === "")
525
+ return "no API key or credential reference configured";
517
526
  return null;
518
527
  }
519
528
  function isRecord(input) {
@@ -564,16 +573,72 @@ function fieldStateOf(snapshot, spec, edit) {
564
573
  const effective = snapshot.value[spec.field];
565
574
  const stored = Object.hasOwn(snapshot.user, spec.field);
566
575
  if (edit === void 0) {
567
- return isTextSpec(spec) ? { text: spec.format(effective), value: void 0, effective, stored, overridden: stored, dirty: false, invalid: false } : { text: "", value: effective, effective, stored, overridden: stored, dirty: false, invalid: false };
576
+ return isTextSpec(spec) ? {
577
+ text: spec.format(effective),
578
+ value: void 0,
579
+ effective,
580
+ stored,
581
+ overridden: stored,
582
+ dirty: false,
583
+ invalid: false
584
+ } : {
585
+ text: "",
586
+ value: effective,
587
+ effective,
588
+ stored,
589
+ overridden: stored,
590
+ dirty: false,
591
+ invalid: false
592
+ };
568
593
  }
569
594
  if (edit.kind === "clear") {
570
- return isTextSpec(spec) ? { text: "", value: void 0, effective, stored, overridden: false, dirty: stored, invalid: false } : { text: "", value: effective, effective, stored, overridden: false, dirty: stored, invalid: false };
595
+ return isTextSpec(spec) ? {
596
+ text: "",
597
+ value: void 0,
598
+ effective,
599
+ stored,
600
+ overridden: false,
601
+ dirty: stored,
602
+ invalid: false
603
+ } : {
604
+ text: "",
605
+ value: effective,
606
+ effective,
607
+ stored,
608
+ overridden: false,
609
+ dirty: stored,
610
+ invalid: false
611
+ };
571
612
  }
572
613
  if (!isTextSpec(spec)) {
573
- return edit.kind === "value" ? { text: "", value: edit.value, effective, stored, overridden: true, dirty: edit.value !== effective, invalid: false } : { text: "", value: effective, effective, stored, overridden: stored, dirty: false, invalid: false };
614
+ return edit.kind === "value" ? {
615
+ text: "",
616
+ value: edit.value,
617
+ effective,
618
+ stored,
619
+ overridden: true,
620
+ dirty: edit.value !== effective,
621
+ invalid: false
622
+ } : {
623
+ text: "",
624
+ value: effective,
625
+ effective,
626
+ stored,
627
+ overridden: stored,
628
+ dirty: false,
629
+ invalid: false
630
+ };
574
631
  }
575
632
  if (edit.kind !== "text") {
576
- return { text: "", value: void 0, effective, stored, overridden: stored, dirty: false, invalid: false };
633
+ return {
634
+ text: "",
635
+ value: void 0,
636
+ effective,
637
+ stored,
638
+ overridden: stored,
639
+ dirty: false,
640
+ invalid: false
641
+ };
577
642
  }
578
643
  const write = spec.parse(edit.text);
579
644
  const dirty = write === void 0 ? true : write.kind === "clear" ? stored : edit.text !== spec.format(effective);
@@ -618,10 +683,7 @@ function useConfigForm(form) {
618
683
  cacheRef.current = { value, user, writable, available, snapshot: snapshot2 };
619
684
  return snapshot2;
620
685
  }, [form]);
621
- const subscribe = (0, import_react2.useCallback)(
622
- (listener) => form.subscribe(listener),
623
- [form]
624
- );
686
+ const subscribe = (0, import_react2.useCallback)((listener) => form.subscribe(listener), [form]);
625
687
  const snapshot = (0, import_react2.useSyncExternalStore)(subscribe, readSnapshot);
626
688
  const [staged, setStaged] = (0, import_react2.useState)(() => /* @__PURE__ */ new Map());
627
689
  const [saving, setSaving] = (0, import_react2.useState)(false);
@@ -631,18 +693,23 @@ function useConfigForm(form) {
631
693
  const [test, setTest] = (0, import_react2.useState)({ running: false, ok: null, message: "" });
632
694
  const testTimerRef = (0, import_react2.useRef)(null);
633
695
  const testRunningRef = (0, import_react2.useRef)(false);
634
- (0, import_react2.useEffect)(() => () => {
635
- if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
636
- testTimerRef.current = null;
637
- testRunningRef.current = false;
638
- }, []);
696
+ (0, import_react2.useEffect)(
697
+ () => () => {
698
+ if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
699
+ testTimerRef.current = null;
700
+ testRunningRef.current = false;
701
+ },
702
+ []
703
+ );
639
704
  const plan = (0, import_react2.useMemo)(() => planWrites(snapshot, staged), [snapshot, staged]);
640
705
  const pairsInvalid = (0, import_react2.useMemo)(
641
- () => THRESHOLD_PAIRS.some((pair) => !thresholdsOk(
642
- pair,
643
- fieldOf(snapshot, pair.warn, staged.get(pair.warn)),
644
- fieldOf(snapshot, pair.critical, staged.get(pair.critical))
645
- )),
706
+ () => THRESHOLD_PAIRS.some(
707
+ (pair) => !thresholdsOk(
708
+ pair,
709
+ fieldOf(snapshot, pair.warn, staged.get(pair.warn)),
710
+ fieldOf(snapshot, pair.critical, staged.get(pair.critical))
711
+ )
712
+ ),
646
713
  [snapshot, staged]
647
714
  );
648
715
  const invalid = plan.some((item) => item.write === void 0) || pairsInvalid;
@@ -659,17 +726,28 @@ function useConfigForm(form) {
659
726
  testTimerRef.current = null;
660
727
  }
661
728
  testRunningRef.current = false;
662
- setTest((current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current);
729
+ setTest(
730
+ (current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
731
+ );
663
732
  }, []);
664
- const edit = (0, import_react2.useCallback)((field2, text) => {
665
- stage(field2, { kind: "text", text });
666
- }, [stage]);
667
- const setValue = (0, import_react2.useCallback)((field2, value) => {
668
- stage(field2, { kind: "value", value });
669
- }, [stage]);
670
- const resetField = (0, import_react2.useCallback)((field2) => {
671
- stage(field2, { kind: "clear" });
672
- }, [stage]);
733
+ const edit = (0, import_react2.useCallback)(
734
+ (field2, text) => {
735
+ stage(field2, { kind: "text", text });
736
+ },
737
+ [stage]
738
+ );
739
+ const setValue = (0, import_react2.useCallback)(
740
+ (field2, value) => {
741
+ stage(field2, { kind: "value", value });
742
+ },
743
+ [stage]
744
+ );
745
+ const resetField = (0, import_react2.useCallback)(
746
+ (field2) => {
747
+ stage(field2, { kind: "clear" });
748
+ },
749
+ [stage]
750
+ );
673
751
  const discard = (0, import_react2.useCallback)(() => {
674
752
  setStaged((current) => current.size === 0 ? current : /* @__PURE__ */ new Map());
675
753
  setFailed(false);
@@ -678,7 +756,9 @@ function useConfigForm(form) {
678
756
  testTimerRef.current = null;
679
757
  }
680
758
  testRunningRef.current = false;
681
- setTest((current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current);
759
+ setTest(
760
+ (current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
761
+ );
682
762
  }, []);
683
763
  const save = (0, import_react2.useCallback)(async () => {
684
764
  if (savingRef.current) return;
@@ -692,9 +772,11 @@ function useConfigForm(form) {
692
772
  for (const item of writes) {
693
773
  const write = item.write;
694
774
  if (write === void 0) continue;
695
- ops.push(write.kind === "clear" ? { op: "unset", path: [item.field] } : { op: "set", path: [item.field], value: write.value });
775
+ ops.push(
776
+ write.kind === "clear" ? { op: "unset", path: [item.field] } : { op: "set", path: [item.field], value: write.value }
777
+ );
696
778
  }
697
- let landed = false;
779
+ let landed;
698
780
  try {
699
781
  landed = await form.mutate(ops, form.getSnapshot().revision);
700
782
  } catch {
@@ -720,7 +802,9 @@ function useConfigForm(form) {
720
802
  testTimerRef.current = setTimeout(() => {
721
803
  testTimerRef.current = null;
722
804
  testRunningRef.current = false;
723
- setTest(failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure });
805
+ setTest(
806
+ failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure }
807
+ );
724
808
  }, TEST_LATENCY_MS);
725
809
  }, [readSnapshot, staged]);
726
810
  const field = (0, import_react2.useCallback)(
@@ -871,8 +955,7 @@ var BalanceSettingsCard_default = {
871
955
  readOnly: "BalanceSettingsCard_readOnly",
872
956
  footer: "BalanceSettingsCard_footer",
873
957
  failed: "BalanceSettingsCard_failed",
874
- notice: "BalanceSettingsCard_notice",
875
- save: "BalanceSettingsCard_save"
958
+ notice: "BalanceSettingsCard_notice"
876
959
  };
877
960
 
878
961
  // src/client/settings/BalanceSettingsCard.tsx
@@ -922,7 +1005,8 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
922
1005
  const toggleGroup = (key) => {
923
1006
  setGroupOpen((current) => ({ ...current, [key]: !current[key] }));
924
1007
  };
925
- const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
1008
+ const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || // 成对校验不是字段级 invalid,得单独问一次:否则收起的阈值组会挡住「保存为什么是灰的」。
1009
+ key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
926
1010
  const { available, writable, dirty, invalid, saving, failed } = form.state;
927
1011
  const disabled = !writable || saving;
928
1012
  const credentialStatus = (name) => {
@@ -1079,7 +1163,10 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1079
1163
  {
1080
1164
  id: FIELD_IDS.apiKeyState ?? "apiKeyState",
1081
1165
  label: t("settings.field.apiKey"),
1082
- status: { label: t(CREDENTIAL_BADGE[credentialView]), tone: credentialView === "notConfigured" ? "quiet" : "neutral" },
1166
+ status: {
1167
+ label: t(CREDENTIAL_BADGE[credentialView]),
1168
+ tone: credentialView === "notConfigured" ? "quiet" : "neutral"
1169
+ },
1083
1170
  pending: false,
1084
1171
  resettable: false,
1085
1172
  pendingLabel: t("settings.unsaved"),
@@ -1089,12 +1176,7 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1089
1176
  disabled: true,
1090
1177
  onReset: () => {
1091
1178
  },
1092
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1093
- ReadOnlyControl,
1094
- {
1095
- id: FIELD_IDS.apiKeyState ?? "apiKeyState"
1096
- }
1097
- )
1179
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReadOnlyControl, { id: FIELD_IDS.apiKeyState ?? "apiKeyState" })
1098
1180
  }
1099
1181
  ),
1100
1182
  textRow("baseUrl", "settings.field.baseUrl", "settings.hint.baseUrl", false),
@@ -1153,19 +1235,31 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
1153
1235
  },
1154
1236
  last: true,
1155
1237
  children: [
1156
- numberRow("serverRefreshSeconds", "settings.field.serverRefreshSeconds", "settings.hint.serverRefreshSeconds"),
1157
- numberRow("clientPollSeconds", "settings.field.clientPollSeconds", "settings.hint.clientPollSeconds"),
1158
- numberRow("manualRefreshCooldownSeconds", "settings.field.manualRefreshCooldownSeconds", "settings.hint.manualRefreshCooldownSeconds")
1238
+ numberRow(
1239
+ "serverRefreshSeconds",
1240
+ "settings.field.serverRefreshSeconds",
1241
+ "settings.hint.serverRefreshSeconds"
1242
+ ),
1243
+ numberRow(
1244
+ "clientPollSeconds",
1245
+ "settings.field.clientPollSeconds",
1246
+ "settings.hint.clientPollSeconds"
1247
+ ),
1248
+ numberRow(
1249
+ "manualRefreshCooldownSeconds",
1250
+ "settings.field.manualRefreshCooldownSeconds",
1251
+ "settings.hint.manualRefreshCooldownSeconds"
1252
+ )
1159
1253
  ]
1160
1254
  }
1161
1255
  ),
1162
1256
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: BalanceSettingsCard_default.footer, children: [
1163
1257
  footerNote === null ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: footerNote.className, role: "status", children: footerNote.text }),
1164
1258
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1165
- "button",
1259
+ import_dsh_client_ui_primitives2.Button,
1166
1260
  {
1167
1261
  type: "button",
1168
- className: BalanceSettingsCard_default.save,
1262
+ variant: "primary",
1169
1263
  disabled: !dirty || invalid || saving || !writable,
1170
1264
  onClick: () => {
1171
1265
  void form.save();
@@ -1315,9 +1409,17 @@ var scenarios = {
1315
1409
  /** 正常。 */
1316
1410
  ok: make({}),
1317
1411
  /** 余额偏低但可用。 */
1318
- warn: make({ severity: "warn", balances: [cny("8.00000000", "0.00000000", "8.00000000")], selected: { currency: "CNY", total: "8.00000000" } }),
1412
+ warn: make({
1413
+ severity: "warn",
1414
+ balances: [cny("8.00000000", "0.00000000", "8.00000000")],
1415
+ selected: { currency: "CNY", total: "8.00000000" }
1416
+ }),
1319
1417
  /** 余额告急。 */
1320
- critical: make({ severity: "critical", balances: [cny("3.00000000", "0.00000000", "3.00000000")], selected: { currency: "CNY", total: "3.00000000" } }),
1418
+ critical: make({
1419
+ severity: "critical",
1420
+ balances: [cny("3.00000000", "0.00000000", "3.00000000")],
1421
+ selected: { currency: "CNY", total: "3.00000000" }
1422
+ }),
1321
1423
  /** 账户不可用(余额耗尽 / 欠费)。 */
1322
1424
  unavailable: make({
1323
1425
  severity: "unavailable",
@@ -1326,7 +1428,14 @@ var scenarios = {
1326
1428
  selected: { currency: "CNY", total: "0.00000000" }
1327
1429
  }),
1328
1430
  /** 有旧值但本次刷新失败。 */
1329
- stale: make({ state: "stale", stale: true, severity: "unknown", ageMs: 36e5, fetchedAt: T0 - 36e5, error: { code: "NO_NETWORK", message: "fetch failed" } }),
1431
+ stale: make({
1432
+ state: "stale",
1433
+ stale: true,
1434
+ severity: "unknown",
1435
+ ageMs: 36e5,
1436
+ fetchedAt: T0 - 36e5,
1437
+ error: { code: "NO_NETWORK", message: "fetch failed" }
1438
+ }),
1330
1439
  /** 无值失败。 */
1331
1440
  error: make({
1332
1441
  state: "error",
@@ -1339,14 +1448,35 @@ var scenarios = {
1339
1448
  error: { code: "UPSTREAM_5XX", message: "upstream returned 500" }
1340
1449
  }),
1341
1450
  /** 未配置。 */
1342
- empty: make({ state: "empty", severity: "unknown", isAvailable: false, balances: [], selected: null, ageMs: 0 }),
1451
+ empty: make({
1452
+ state: "empty",
1453
+ severity: "unknown",
1454
+ isAvailable: false,
1455
+ balances: [],
1456
+ selected: null,
1457
+ ageMs: 0
1458
+ }),
1343
1459
  /** 未配置且带 NO_KEY 错误。 */
1344
- noKey: make({ state: "empty", severity: "unknown", isAvailable: false, balances: [], selected: null, ageMs: 0, error: { code: "NO_KEY", message: "no API key configured" } }),
1460
+ noKey: make({
1461
+ state: "empty",
1462
+ severity: "unknown",
1463
+ isAvailable: false,
1464
+ balances: [],
1465
+ selected: null,
1466
+ ageMs: 0,
1467
+ error: { code: "NO_KEY", message: "no API key configured" }
1468
+ }),
1345
1469
  /** 多币种。`selected` 显式写出,不靠 `make()` 的默认值兜。 */
1346
1470
  multiCurrency: make({
1347
- balances: [cny("110.00000000", "10.00000000", "100.00000000"), { currency: "USD", total: "20.00000000", granted: "0.00000000", toppedUp: "20.00000000" }],
1471
+ balances: [
1472
+ cny("110.00000000", "10.00000000", "100.00000000"),
1473
+ { currency: "USD", total: "20.00000000", granted: "0.00000000", toppedUp: "20.00000000" }
1474
+ ],
1348
1475
  selected: { currency: "CNY", total: "110.00000000" },
1349
- thresholds: { CNY: { warn: "10.00000000", critical: "5.00000000" }, USD: { warn: "2.00000000", critical: "1.00000000" } }
1476
+ thresholds: {
1477
+ CNY: { warn: "10.00000000", critical: "5.00000000" },
1478
+ USD: { warn: "2.00000000", critical: "1.00000000" }
1479
+ }
1350
1480
  }),
1351
1481
  /**
1352
1482
  * 选定了账户里没有的币种(USD),账户只有 CNY。
@@ -1561,9 +1691,12 @@ function BalancePopover(props) {
1561
1691
  const cooling = cooldownSeconds > 0;
1562
1692
  let statusText = "";
1563
1693
  if (refreshing) statusText = t("popover.refreshing");
1564
- else if (cooling) statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
1694
+ else if (cooling)
1695
+ statusText = interpolate(t("popover.cooldown"), { value: String(cooldownSeconds) });
1565
1696
  const refreshLabel = t("sidebar.aria.refresh");
1566
- const pluginsLabel = t(pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins");
1697
+ const pluginsLabel = t(
1698
+ pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins"
1699
+ );
1567
1700
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1568
1701
  "section",
1569
1702
  {
@@ -1609,7 +1742,16 @@ function BalancePopover(props) {
1609
1742
  ] }),
1610
1743
  shown !== null && !selection.matchesPreference ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.notice, children: [
1611
1744
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: BalancePopover_default.noticeText, children: interpolate(t("popover.mismatch"), { wanted: displayCurrency, shown: shown.currency }) }),
1612
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { size: "sm", variant: "outline", disabled: useShownDisabled === true, onClick: onUseShown, children: interpolate(t("popover.action.useShown"), { shown: shown.currency }) }) })
1745
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1746
+ import_dsh_client_ui_primitives3.Button,
1747
+ {
1748
+ size: "sm",
1749
+ variant: "outline",
1750
+ disabled: useShownDisabled === true,
1751
+ onClick: onUseShown,
1752
+ children: interpolate(t("popover.action.useShown"), { shown: shown.currency })
1753
+ }
1754
+ ) })
1613
1755
  ] }) : null,
1614
1756
  configSlotWarning === null ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: BalancePopover_default.notice, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: BalancePopover_default.noticeText, children: configSlotWarning }) }),
1615
1757
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: BalancePopover_default.footer, children: [
@@ -1654,7 +1796,13 @@ var CROSS_ARM = (2 * RADIUS - STROKE) / 2 / Math.SQRT2;
1654
1796
  function round3(value) {
1655
1797
  return Math.round(value * 1e3) / 1e3;
1656
1798
  }
1657
- function PercentRing({ state, marker = null, ratio = 1, size = 18, title }) {
1799
+ function PercentRing({
1800
+ state,
1801
+ marker = null,
1802
+ ratio = 1,
1803
+ size = 18,
1804
+ title
1805
+ }) {
1658
1806
  const clamped = Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 1;
1659
1807
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1660
1808
  "svg",
@@ -1747,8 +1895,10 @@ function usePluginsNavigation(navigation) {
1747
1895
  return action;
1748
1896
  }
1749
1897
  function stateLabelKey(response, selection) {
1750
- if (response.state === "error") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
1751
- if (response.state === "empty") return response.error?.code === "NO_KEY" ? "state.noKey" : "state.empty";
1898
+ if (response.state === "error")
1899
+ return response.error?.code === "NO_KEY" ? "state.noKey" : "state.error";
1900
+ if (response.state === "empty")
1901
+ return response.error?.code === "NO_KEY" ? "state.noKey" : "state.empty";
1752
1902
  if (response.state === "stale") return "state.stale";
1753
1903
  if (!response.isAvailable) return "state.unavailable";
1754
1904
  if (selection.shown === null) return "state.noBalance";
@@ -1793,16 +1943,19 @@ function SidebarBalance({
1793
1943
  }, []);
1794
1944
  const preference = config.displayCurrency;
1795
1945
  const selection = (0, import_react5.useMemo)(() => selectionOf(response, preference), [response, preference]);
1796
- (0, import_react5.useEffect)(() => subscribeScenario((key) => {
1797
- const active = resolveScenario() !== null;
1798
- setMock(active);
1799
- if (!active || lastScenario.current === key) return;
1800
- lastScenario.current = key;
1801
- acceptBalance(currentBalance());
1802
- setRefreshing(false);
1803
- setCooldownUntil(0);
1804
- setOpen(false);
1805
- }), [acceptBalance]);
1946
+ (0, import_react5.useEffect)(
1947
+ () => subscribeScenario((key) => {
1948
+ const active = resolveScenario() !== null;
1949
+ setMock(active);
1950
+ if (!active || lastScenario.current === key) return;
1951
+ lastScenario.current = key;
1952
+ acceptBalance(currentBalance());
1953
+ setRefreshing(false);
1954
+ setCooldownUntil(0);
1955
+ setOpen(false);
1956
+ }),
1957
+ [acceptBalance]
1958
+ );
1806
1959
  (0, import_react5.useEffect)(() => {
1807
1960
  if (mock) return;
1808
1961
  let cancelled = false;
@@ -1818,17 +1971,30 @@ function SidebarBalance({
1818
1971
  }
1819
1972
  };
1820
1973
  void load();
1821
- const id = window.setInterval(() => {
1822
- void load();
1823
- }, Math.max(5, config.clientPollSeconds) * MS_PER_SECOND);
1974
+ const id = window.setInterval(
1975
+ () => {
1976
+ void load();
1977
+ },
1978
+ Math.max(5, config.clientPollSeconds) * MS_PER_SECOND
1979
+ );
1824
1980
  return () => {
1825
1981
  cancelled = true;
1826
1982
  window.clearInterval(id);
1827
1983
  };
1828
- }, [mock, preference, config.clientPollSeconds, config.configSignature, acceptBalance, showUnreachable]);
1829
- (0, import_react5.useEffect)(() => () => {
1830
- if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
1831
- }, []);
1984
+ }, [
1985
+ mock,
1986
+ preference,
1987
+ config.clientPollSeconds,
1988
+ config.configSignature,
1989
+ acceptBalance,
1990
+ showUnreachable
1991
+ ]);
1992
+ (0, import_react5.useEffect)(
1993
+ () => () => {
1994
+ if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
1995
+ },
1996
+ []
1997
+ );
1832
1998
  const closeNow = (0, import_react5.useCallback)(() => {
1833
1999
  setOpen(false);
1834
2000
  }, []);
@@ -1870,7 +2036,9 @@ function SidebarBalance({
1870
2036
  setRefreshing(true);
1871
2037
  const finish = () => {
1872
2038
  setRefreshing(false);
1873
- setCooldownUntil(Date.now() + Math.max(0, config.manualRefreshCooldownSeconds) * MS_PER_SECOND);
2039
+ setCooldownUntil(
2040
+ Date.now() + Math.max(0, config.manualRefreshCooldownSeconds) * MS_PER_SECOND
2041
+ );
1874
2042
  };
1875
2043
  if (mock) {
1876
2044
  refreshTimer.current = window.setTimeout(() => {
@@ -1892,7 +2060,16 @@ function SidebarBalance({
1892
2060
  finish();
1893
2061
  }
1894
2062
  })();
1895
- }, [cooldownUntil, config.manualRefreshCooldownSeconds, mock, preference, refreshing, acceptBalance, showUnreachable, markFresh]);
2063
+ }, [
2064
+ cooldownUntil,
2065
+ config.manualRefreshCooldownSeconds,
2066
+ mock,
2067
+ preference,
2068
+ refreshing,
2069
+ acceptBalance,
2070
+ showUnreachable,
2071
+ markFresh
2072
+ ]);
1896
2073
  const handleUseShown = (0, import_react5.useCallback)(() => {
1897
2074
  const current = selection.shown;
1898
2075
  if (current === null) return;
@@ -1949,42 +2126,42 @@ function SidebarBalance({
1949
2126
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.icon, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 16 }) }),
1950
2127
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.label, children: t("sidebar.label") }),
1951
2128
  markerLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: markerHint, side: "bottom", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SidebarBalance_default.marker, role: "img", "aria-label": markerLabel, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.IconWarningOutlineRegular, { size: 12 }) }) })
1952
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 18, title: ringTitle })
1953
- }
1954
- );
1955
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1956
- "div",
1957
- {
1958
- ref: rootRef,
1959
- className: SidebarBalance_default.root,
1960
- "data-mode": wide ? "wide" : "rail",
1961
- tabIndex: -1,
1962
- children: [
1963
- wide && hoverLabel !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverLabel, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
1964
- open ? (0, import_react_dom.createPortal)(
1965
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1966
- BalancePopover,
1967
- {
1968
- t,
1969
- selection,
1970
- displayCurrency: preference,
1971
- ageMs,
1972
- refreshing,
1973
- cooldownSeconds,
1974
- configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
1975
- panelRef,
1976
- style: pos ?? MEASURE_STYLE,
1977
- onRefresh: handleRefresh,
1978
- onUseShown: handleUseShown,
1979
- useShownDisabled: !config.writable,
1980
- pluginsAction: popoverPluginsAction
1981
- }
1982
- ),
1983
- document.body
1984
- ) : null
1985
- ]
2129
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2130
+ PercentRing,
2131
+ {
2132
+ state: ring.state,
2133
+ marker: ring.marker,
2134
+ ratio: ringRatio,
2135
+ size: 18,
2136
+ title: ringTitle
2137
+ }
2138
+ )
1986
2139
  }
1987
2140
  );
2141
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: rootRef, className: SidebarBalance_default.root, "data-mode": wide ? "wide" : "rail", tabIndex: -1, children: [
2142
+ wide && hoverLabel !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: hoverLabel, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
2143
+ open ? (0, import_react_dom.createPortal)(
2144
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2145
+ BalancePopover,
2146
+ {
2147
+ t,
2148
+ selection,
2149
+ displayCurrency: preference,
2150
+ ageMs,
2151
+ refreshing,
2152
+ cooldownSeconds,
2153
+ configSlotWarning: configSlotState === "missing" ? CONFIG_SLOT_WARNING : null,
2154
+ panelRef,
2155
+ style: pos ?? MEASURE_STYLE,
2156
+ onRefresh: handleRefresh,
2157
+ onUseShown: handleUseShown,
2158
+ useShownDisabled: !config.writable,
2159
+ pluginsAction: popoverPluginsAction
2160
+ }
2161
+ ),
2162
+ document.body
2163
+ ) : null
2164
+ ] });
1988
2165
  }
1989
2166
 
1990
2167
  // src/client/index.tsx
@@ -2142,7 +2319,10 @@ function apply(ctx) {
2142
2319
  const candidate = face["openBundle"];
2143
2320
  if (typeof candidate !== "function") return;
2144
2321
  const openBundle = candidate.bind(face);
2145
- navCtx.effect(() => pluginsNavigation.attachDeepLink(openBundle), "ds-balance: bundle config deep link");
2322
+ navCtx.effect(
2323
+ () => pluginsNavigation.attachDeepLink(openBundle),
2324
+ "ds-balance: bundle config deep link"
2325
+ );
2146
2326
  });
2147
2327
  ctx.inject(["layout"], (layoutCtx) => {
2148
2328
  if (!("layout" in layoutCtx)) return;
@@ -2160,25 +2340,31 @@ function apply(ctx) {
2160
2340
  ctx.inject(["configForms"], (configCtx) => {
2161
2341
  configSlotProbe.markDeclared();
2162
2342
  const form = configCtx.configForms.get(ENTRY_ID);
2163
- ctx.slots.inject(CONFIG_SLOT, () => ctx.slots.register(
2164
- { name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
2165
- (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsSeatComponent, { seat, form })
2166
- ));
2167
- ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register(
2168
- { name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
2169
- (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2170
- SidebarSeatComponent,
2171
- {
2172
- seat,
2173
- form,
2174
- configSlotProbe,
2175
- pluginsNavigation
2176
- }
2343
+ ctx.slots.inject(
2344
+ CONFIG_SLOT,
2345
+ () => ctx.slots.register(
2346
+ { name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
2347
+ (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SettingsSeatComponent, { seat, form })
2177
2348
  )
2178
- ));
2349
+ );
2350
+ ctx.slots.inject(
2351
+ "sidebar.footer.action",
2352
+ () => ctx.slots.register(
2353
+ { name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
2354
+ (seat) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2355
+ SidebarSeatComponent,
2356
+ {
2357
+ seat,
2358
+ form,
2359
+ configSlotProbe,
2360
+ pluginsNavigation
2361
+ }
2362
+ )
2363
+ )
2364
+ );
2179
2365
  });
2180
2366
  }
2181
- var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsSummary {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n list-style: none;\n}\n.fields_detailsSummary::-webkit-details-marker {\n display: none;\n}\n.fields_detailsSummary::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-right: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n transform: translate(-0.5px, -1px) rotate(-45deg);\n transition: transform 120ms ease;\n}\n.fields_details[open] > .fields_detailsSummary::before {\n transform: translate(-0.5px, -1px) rotate(45deg);\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_input {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_input:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_input:disabled {\n color: var(--dsw-alias-label-tertiary);\n opacity: 0.6;\n cursor: default;\n}\ninput.fields_inputStatic,\ninput.fields_inputStatic:hover,\ninput.fields_inputStatic:focus,\ninput.fields_inputStatic:focus-visible,\ninput.fields_inputStatic:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n pointer-events: none;\n}\n.fields_inputInvalid {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-3);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_inputInvalid:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputInvalid:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 999px;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_actionButton {\n appearance: none;\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: none;\n color: var(--dsw-alias-label-secondary);\n}\n.fields_actionButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n.fields_actionButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.fields_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_save {\n appearance: none;\n border: 0.5px solid transparent;\n border-radius: 8px;\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n.BalanceSettingsCard_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalanceSettingsCard_save:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: 12px;\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_cross {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: 12px;\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: 12px;\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
2367
+ var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_inputStatic,\n.fields_inputStatic:hover {\n pointer-events: none;\n}\n.fields_inputStatic input,\n.fields_inputStatic input:hover,\n.fields_inputStatic input:focus,\n.fields_inputStatic input:focus-visible,\n.fields_inputStatic input:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n}\n.fields_inputInvalid input {\n border: 1px solid var(--dsw-alias-state-error-primary);\n}\n.fields_inputInvalid input:focus-visible {\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 999px;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: 12px;\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: 999px;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_cross {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: 12px;\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: 12px;\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
2182
2368
  var __dsbTagId = "dsh-ds-balance/client.css";
2183
2369
  if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="' + __dsbTagId + '"]') === null) {
2184
2370
  var __dsbTag = document.createElement('style');