dsh-modellix 0.1.0 → 0.1.1

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
@@ -911,7 +911,7 @@ const MODAL_DIALOG_SELECTOR = "[role=\"dialog\"][aria-modal=\"true\"]";
911
911
  * therefore uses only the ARIA modal contract and a marker owned by this
912
912
  * plugin; it does not depend on host classes or DOM structure.
913
913
  */
914
- function useExternalDialogGate(requestedOpen) {
914
+ function useExternalDialogGate(requestedOpen, externalDialogOwner) {
915
915
  const [decision, setDecision] = (0, react.useState)({
916
916
  requestedOpen: false,
917
917
  allowed: false
@@ -931,7 +931,7 @@ function useExternalDialogGate(requestedOpen) {
931
931
  const reconcile = () => {
932
932
  reconciliationQueued = false;
933
933
  if (disposed) return;
934
- const allowed = !hasVisibleExternalDialog(ownerDocument);
934
+ const allowed = !hasVisibleExternalDialog(ownerDocument, resolveExternalDialogOwner(externalDialogOwner));
935
935
  setDecision((current) => current.requestedOpen && current.allowed === allowed ? current : {
936
936
  requestedOpen: true,
937
937
  allowed
@@ -962,12 +962,12 @@ function useExternalDialogGate(requestedOpen) {
962
962
  disposed = true;
963
963
  observer?.disconnect();
964
964
  };
965
- }, [requestedOpen]);
965
+ }, [externalDialogOwner, requestedOpen]);
966
966
  return requestedOpen && decision.requestedOpen && decision.allowed;
967
967
  }
968
968
  /** Adds the focus behavior intentionally absent from the public Modal primitive. */
969
969
  function useDialogA11y(options) {
970
- const { open, container, initialFocusSelector, mandatory, onEscape } = options;
970
+ const { open, container, externalDialogOwner, initialFocusSelector, mandatory, onEscape } = options;
971
971
  const onEscapeRef = (0, react.useRef)(onEscape);
972
972
  const restoreTargetRef = (0, react.useRef)(null);
973
973
  onEscapeRef.current = onEscape;
@@ -1019,13 +1019,14 @@ function useDialogA11y(options) {
1019
1019
  document.removeEventListener("keydown", onKeyDown, true);
1020
1020
  unlockInert();
1021
1021
  unlockScroll();
1022
- if (!hasVisibleExternalDialog(document)) {
1022
+ if (!hasVisibleExternalDialog(document, resolveExternalDialogOwner(externalDialogOwner))) {
1023
1023
  restoreFocus(restoreTargetRef.current, dialogRoot, appRoot);
1024
1024
  restoreTargetRef.current = null;
1025
1025
  }
1026
1026
  };
1027
1027
  }, [
1028
1028
  container,
1029
+ externalDialogOwner,
1029
1030
  initialFocusSelector,
1030
1031
  mandatory,
1031
1032
  open
@@ -1111,8 +1112,11 @@ function restoreFocus(previous, dialog, appRoot) {
1111
1112
  if (fallback !== void 0 && focus(fallback)) return;
1112
1113
  }
1113
1114
  }
1114
- function hasVisibleExternalDialog(ownerDocument) {
1115
- return [...ownerDocument.querySelectorAll(MODAL_DIALOG_SELECTOR)].some((candidate) => candidate.querySelector(MODELLIX_DIALOG_SENTINEL) === null && isVisibleDialog(candidate));
1115
+ function hasVisibleExternalDialog(ownerDocument, allowedOwner = null) {
1116
+ return [...ownerDocument.querySelectorAll(MODAL_DIALOG_SELECTOR)].some((candidate) => candidate !== allowedOwner && candidate.querySelector(MODELLIX_DIALOG_SENTINEL) === null && isVisibleDialog(candidate));
1117
+ }
1118
+ function resolveExternalDialogOwner(owner) {
1119
+ return owner?.current?.closest(MODAL_DIALOG_SELECTOR) ?? null;
1116
1120
  }
1117
1121
  function isVisibleDialog(candidate) {
1118
1122
  if (candidate.tagName === "DIALOG" && !candidate.hasAttribute("open")) return false;
@@ -1276,7 +1280,7 @@ function CredentialStatus({ configured, source, verification, t }) {
1276
1280
  });
1277
1281
  }
1278
1282
  function CredentialModal(props) {
1279
- const { open, mandatory, title, description, services, onServicesChange, busy, errorCode, onSave, onSaved, onCancel, laterLabel = "cancel", t } = props;
1283
+ const { open, mandatory, title, description, services, onServicesChange, busy, errorCode, onSave, onSaved, onCancel, laterLabel = "cancel", t, externalDialogOwner } = props;
1280
1284
  const [draft, setDraft] = (0, react.useState)("");
1281
1285
  const [visible, setVisible] = (0, react.useState)(false);
1282
1286
  const [displayedErrorCode, setDisplayedErrorCode] = (0, react.useState)(errorCode);
@@ -1286,7 +1290,7 @@ function CredentialModal(props) {
1286
1290
  const helpId = `${keyId}-help`;
1287
1291
  const errorId = `${keyId}-error`;
1288
1292
  const errorPresentation = displayedErrorCode === null ? null : presentClientError(displayedErrorCode);
1289
- const surfaceOpen = useExternalDialogGate(open);
1293
+ const surfaceOpen = useExternalDialogGate(open, externalDialogOwner);
1290
1294
  const clear = (0, react.useCallback)(() => {
1291
1295
  draftRef.current = "";
1292
1296
  setDraft("");
@@ -1301,6 +1305,7 @@ function CredentialModal(props) {
1301
1305
  useDialogA11y({
1302
1306
  open: surfaceOpen,
1303
1307
  container: contentRef,
1308
+ externalDialogOwner,
1304
1309
  initialFocusSelector: "[data-mdlx-initial-focus]",
1305
1310
  mandatory,
1306
1311
  onEscape: close
@@ -1686,6 +1691,11 @@ var CredentialDialogCoordinator = class {
1686
1691
  if (this.#snapshot.activeOwner !== null) return;
1687
1692
  this.#publish({ activeOwner: owner });
1688
1693
  }
1694
+ /** Lets an explicit Credential editor adopt a queued shell recovery prompt. */
1695
+ openCredential(owner) {
1696
+ if (this.#snapshot.activeOwner !== null && this.#snapshot.activeOwner !== "shell:credential-recovery") return;
1697
+ this.#publish({ activeOwner: owner });
1698
+ }
1689
1699
  presentRecovery(token) {
1690
1700
  if (token === this.#snapshot.dismissedRecoveryToken) return;
1691
1701
  if (token === this.#snapshot.recoveryToken) {
@@ -1989,6 +1999,9 @@ function ModellixDesignView({ controller, settingsController, t }) {
1989
1999
  (0, react.useEffect)(() => {
1990
2000
  if (state.pending !== null) setOutcomeAnnouncement("");
1991
2001
  }, [state.pending]);
2002
+ (0, react.useEffect)(() => {
2003
+ setOutcomeAnnouncement("");
2004
+ }, [t]);
1992
2005
  (0, react.useEffect)(() => {
1993
2006
  if (snapshot === null) return;
1994
2007
  const transition = designOutcomeTransition(previousOutcome.current, snapshot);
@@ -2081,7 +2094,7 @@ function ModellixDesignView({ controller, settingsController, t }) {
2081
2094
  settings?.credential.writable === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2082
2095
  type: "button",
2083
2096
  variant: "primary",
2084
- onClick: () => credentialDialogs.open(credentialDialogOwner),
2097
+ onClick: () => credentialDialogs.openCredential(credentialDialogOwner),
2085
2098
  children: t("configureToContinue")
2086
2099
  }),
2087
2100
  settings?.credential.source === "env" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -3177,6 +3190,7 @@ const en = {
3177
3190
  //#region src/client/SettingsSection.tsx
3178
3191
  function ModellixSettingsSection({ controller, t }) {
3179
3192
  const state = useResourceState(controller.store);
3193
+ const settingsSectionRef = (0, react.useRef)(null);
3180
3194
  const snapshot = state.data;
3181
3195
  const [services, setServices] = (0, react.useState)(null);
3182
3196
  const [announcement, setAnnouncement] = (0, react.useState)("");
@@ -3204,6 +3218,9 @@ function ModellixSettingsSection({ controller, t }) {
3204
3218
  (0, react.useEffect)(() => {
3205
3219
  if (snapshot !== null) setServices(snapshot.services);
3206
3220
  }, [snapshot?.settingsRevision]);
3221
+ (0, react.useEffect)(() => {
3222
+ setAnnouncement("");
3223
+ }, [t]);
3207
3224
  const busy = state.pending !== null;
3208
3225
  const saveServices = (0, react.useCallback)(() => {
3209
3226
  if (snapshot === null || services === null || busy) return;
@@ -3219,6 +3236,7 @@ function ModellixSettingsSection({ controller, t }) {
3219
3236
  t
3220
3237
  ]);
3221
3238
  if (snapshot === null || services === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3239
+ ref: settingsSectionRef,
3222
3240
  className: "mdlx-settings",
3223
3241
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3224
3242
  className: "mdlx-live",
@@ -3239,6 +3257,7 @@ function ModellixSettingsSection({ controller, t }) {
3239
3257
  const canWriteCredential = credential.writable && credential.source !== "env";
3240
3258
  const llmRefreshDisabled = busy || !snapshot.services.llm || !credential.configured;
3241
3259
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3260
+ ref: settingsSectionRef,
3242
3261
  className: "mdlx-settings",
3243
3262
  children: [
3244
3263
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
@@ -3277,7 +3296,7 @@ function ModellixSettingsSection({ controller, t }) {
3277
3296
  type: "button",
3278
3297
  variant: !credential.configured || credential.verification === "invalid" ? "primary" : "outline",
3279
3298
  disabled: busy,
3280
- onClick: () => credentialDialogs.open(credentialDialogOwner),
3299
+ onClick: () => credentialDialogs.openCredential(credentialDialogOwner),
3281
3300
  children: credential.configured ? t("replaceKey") : t("configureKey")
3282
3301
  }), credential.configured && canWriteCredential && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3283
3302
  type: "button",
@@ -3356,7 +3375,8 @@ function ModellixSettingsSection({ controller, t }) {
3356
3375
  },
3357
3376
  onCancel: () => credentialDialogs.dismissCredential(credentialDialogOwner),
3358
3377
  laterLabel: credentialRecovery ? "later" : "cancel",
3359
- t
3378
+ t,
3379
+ externalDialogOwner: settingsSectionRef
3360
3380
  }),
3361
3381
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RemoveCredentialDialog, {
3362
3382
  open: removeOpen,
@@ -3371,7 +3391,8 @@ function ModellixSettingsSection({ controller, t }) {
3371
3391
  setAnnouncement(t("saved"));
3372
3392
  });
3373
3393
  },
3374
- t
3394
+ t,
3395
+ externalDialogOwner: settingsSectionRef
3375
3396
  })
3376
3397
  ]
3377
3398
  });
@@ -3426,12 +3447,13 @@ function LlmCatalogCard({ snapshot, dateLocale, busy, disabled, onRefresh, t })
3426
3447
  ]
3427
3448
  });
3428
3449
  }
3429
- function RemoveCredentialDialog({ open, busy, errorCode, onClose, onConfirm, t }) {
3450
+ function RemoveCredentialDialog({ open, busy, errorCode, onClose, onConfirm, t, externalDialogOwner }) {
3430
3451
  const contentRef = (0, react.useRef)(null);
3431
- const surfaceOpen = useExternalDialogGate(open);
3452
+ const surfaceOpen = useExternalDialogGate(open, externalDialogOwner);
3432
3453
  useDialogA11y({
3433
3454
  open: surfaceOpen,
3434
3455
  container: contentRef,
3456
+ externalDialogOwner,
3435
3457
  initialFocusSelector: "[data-mdlx-initial-focus]",
3436
3458
  mandatory: false,
3437
3459
  onEscape: onClose