@nsail/ui 0.1.334 → 0.1.338

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.
Files changed (2) hide show
  1. package/dist/dialog.js +18 -2
  2. package/package.json +5 -2
package/dist/dialog.js CHANGED
@@ -13,16 +13,32 @@ export function NsDialogHost({ children }) {
13
13
  return new Promise((resolve) => setPending({ text, danger, resolve }));
14
14
  }, []);
15
15
  useEffect(() => {
16
- if (pending && dialog.current && !dialog.current.open) {
16
+ if (!pending || !dialog.current) {
17
+ return;
18
+ }
19
+ if (!dialog.current.open) {
17
20
  dialog.current.showModal();
18
21
  }
22
+ // Which face the cursor opens on: an ordinary confirmation offers its own act, so the cursor
23
+ // stands on it and Enter takes it; one that destroys stands on the way out, so Enter alone can
24
+ // only decline (ui/forms.md, Focus on open).
25
+ //
26
+ // Placed here, after showModal(), and never by React's autoFocus: that prop focuses at the
27
+ // commit that MOUNTED the faces, which is a commit where this dialog was still closed — a
28
+ // display:none element taking no cursor — and it reaches the DOM as a focus() call, not as the
29
+ // autofocus ATTRIBUTE a native dialog's own focusing steps read when showModal() runs (React
30
+ // 19.3, read off a live DOM: neither face carries the attribute). Those steps are synchronous
31
+ // inside the call above, so the cursor is placed after them rather than racing them, and the
32
+ // placing holds whichever of the two mechanisms the browser answers.
33
+ const [wayOut, act] = dialog.current.querySelectorAll(".ns-actions button");
34
+ (pending.danger ? wayOut : act).focus();
19
35
  }, [pending]);
20
36
  function close(confirmed) {
21
37
  pending?.resolve(confirmed);
22
38
  dialog.current?.close();
23
39
  setPending(null);
24
40
  }
25
- return (_jsxs(DialogContext.Provider, { value: confirm, children: [children, _jsx("dialog", { ref: dialog, className: "ns-dialog", onCancel: () => close(false), children: pending && (_jsxs(_Fragment, { children: [_jsx("p", { children: pending.text }), _jsxs("div", { className: "ns-actions", children: [_jsx(NsButton, { text: "Actions.Cancel", onClick: () => close(false) }), _jsx(NsButton, { text: "Actions.Confirm", variant: pending.danger ? "danger" : "primary", onClick: () => close(true), autoFocus: true })] })] })) })] }));
41
+ return (_jsxs(DialogContext.Provider, { value: confirm, children: [children, _jsx("dialog", { ref: dialog, className: "ns-dialog", onCancel: () => close(false), children: pending && (_jsxs(_Fragment, { children: [_jsx("p", { children: pending.text }), _jsxs("div", { className: "ns-actions", children: [_jsx(NsButton, { text: "Actions.Cancel", onClick: () => close(false) }), _jsx(NsButton, { text: "Actions.Confirm", variant: pending.danger ? "danger" : "primary", onClick: () => close(true) })] })] })) })] }));
26
42
  }
27
43
  export function useConfirm() {
28
44
  const confirm = useContext(DialogContext);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nsail/ui",
3
- "version": "0.1.334",
3
+ "version": "0.1.338",
4
4
  "description": "The Ns* components for a React client, drawn from the descriptors an Sdk generates.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,11 +35,14 @@
35
35
  "react-dom": ">=19"
36
36
  },
37
37
  "dependencies": {
38
- "@nsail/stack": "0.1.334"
38
+ "@nsail/stack": "0.1.338"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsc -p tsconfig.build.json && node -e \"require('fs').copyFileSync('src/ns.css', 'dist/ns.css')\"",
42
42
  "test": "vitest run",
43
43
  "typecheck": "tsc --noEmit"
44
+ },
45
+ "devDependencies": {
46
+ "happy-dom": "^21.0.4"
44
47
  }
45
48
  }