@cosmoops/connect-sdk 0.24.0 → 0.24.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/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  `@cosmoops/connect-sdk` follows semver, with the 0.x convention that **minor
4
4
  versions may carry breaking changes** and patch versions never do.
5
5
 
6
+ ## 0.24.1
7
+
8
+ ### Fixed
9
+
10
+ - **`<ConnectConfirmDialog />` never opened.** Its trigger was wrapped in
11
+ `Modal.Trigger`, which renders a `div role="button"` inside React Aria's
12
+ `Pressable` and depends on a plain `onClick` bubbling up to it. A React Aria
13
+ button nested inside - which every real trigger is, including HeroUI's
14
+ `<Button>` - calls `e.stopPropagation()` in its own `usePress` click
15
+ handler, so the click never arrived. Nothing threw and nothing warned; the
16
+ press was simply eaten, and every confirmation in every app built on this
17
+ SDK was inert. Twelve of them across the two reference apps: each delete
18
+ confirmation in the CRM, and each in the club app.
19
+
20
+ The trigger is now a direct child of the `Modal` root, which is React Aria's
21
+ `DialogTrigger`. Its `PressResponder` picks the trigger up directly, so
22
+ there is no nested pressable and no propagation to lose.
23
+
24
+ No call site changes. The prop's contract is now stated the right way round:
25
+ the trigger **must** be a pressable - a HeroUI `Button`, or anything else
26
+ built on React Aria's `useButton`. A non-pressable element (a bare `<span>`)
27
+ used to be the only thing that worked and now does not; nothing shipped
28
+ passes one.
29
+
6
30
  ## 0.24.0
7
31
 
8
32
  ### Fixed
@@ -19,11 +19,19 @@ const react_2 = require("@heroui/react");
19
19
  * rejection is caught here rather than escaping - an error thrown out of an
20
20
  * async transition reaches the nearest error boundary and takes the page down.
21
21
  *
22
- * The anatomy is HeroUI's: `Modal.Backdrop` owns the open state,
23
- * `Modal.Container` the sizing, `Modal.Dialog` the focus trap. The trigger
24
- * goes inside `Modal.Trigger`, which *is* a React Aria button - so pass a
25
- * plain element, never a `<Button>`, or the nested button swallows the press
26
- * and the dialog silently never opens.
22
+ * The anatomy is HeroUI's: the `Modal` root owns the open state,
23
+ * `Modal.Container` the sizing, `Modal.Dialog` the focus trap. **The trigger
24
+ * is a direct child of the root**, never wrapped in `Modal.Trigger`.
25
+ *
26
+ * That wrapping is what this component used to do, and it meant the dialog
27
+ * never opened for any caller passing a `<Button>` - which was all of them.
28
+ * `Modal.Trigger` renders a `div role="button"` inside React Aria's
29
+ * `Pressable` and relies on a plain `onClick` bubbling up to it; a React Aria
30
+ * button nested inside calls `e.stopPropagation()` in its own `usePress`
31
+ * click handler, so the click never arrives. Nothing failed loudly - the
32
+ * press was simply eaten. The root is `DialogTrigger`, whose `PressResponder`
33
+ * the trigger registers with directly, so there is no nesting and no
34
+ * propagation to lose.
27
35
  */
28
36
  function ConnectConfirmDialog({ trigger, title, description, confirmLabel = "Confirm", cancelLabel = "Cancel", tone = "danger", onConfirm, }) {
29
37
  const [isOpen, setIsOpen] = (0, react_1.useState)(false);
@@ -36,5 +44,5 @@ function ConnectConfirmDialog({ trigger, title, description, confirmLabel = "Con
36
44
  // caller, which owns the toast and the rollback.
37
45
  });
38
46
  };
39
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_2.Modal.Trigger, { onClick: () => setIsOpen(true), children: trigger }), (0, jsx_runtime_1.jsx)(react_2.Modal.Backdrop, { isOpen: isOpen, onOpenChange: setIsOpen, children: (0, jsx_runtime_1.jsx)(react_2.Modal.Container, { size: "sm", children: (0, jsx_runtime_1.jsxs)(react_2.Modal.Dialog, { children: [(0, jsx_runtime_1.jsx)(react_2.Modal.CloseTrigger, { onPress: () => setIsOpen(false) }), (0, jsx_runtime_1.jsx)(react_2.Modal.Header, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Heading, { children: title }) }), description && ((0, jsx_runtime_1.jsx)(react_2.Modal.Body, { children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: description }) })), (0, jsx_runtime_1.jsxs)(react_2.Modal.Footer, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { variant: "secondary", onPress: () => setIsOpen(false), children: cancelLabel }), (0, jsx_runtime_1.jsx)(react_2.Button, { variant: tone === "danger" ? "danger" : "primary", onPress: confirm, children: confirmLabel })] })] }) }) })] }));
47
+ return ((0, jsx_runtime_1.jsxs)(react_2.Modal, { isOpen: isOpen, onOpenChange: setIsOpen, children: [trigger, (0, jsx_runtime_1.jsx)(react_2.Modal.Backdrop, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Container, { size: "sm", children: (0, jsx_runtime_1.jsxs)(react_2.Modal.Dialog, { children: [(0, jsx_runtime_1.jsx)(react_2.Modal.CloseTrigger, { onPress: () => setIsOpen(false) }), (0, jsx_runtime_1.jsx)(react_2.Modal.Header, { children: (0, jsx_runtime_1.jsx)(react_2.Modal.Heading, { children: title }) }), description && ((0, jsx_runtime_1.jsx)(react_2.Modal.Body, { children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-muted", children: description }) })), (0, jsx_runtime_1.jsxs)(react_2.Modal.Footer, { children: [(0, jsx_runtime_1.jsx)(react_2.Button, { variant: "secondary", onPress: () => setIsOpen(false), children: cancelLabel }), (0, jsx_runtime_1.jsx)(react_2.Button, { variant: tone === "danger" ? "danger" : "primary", onPress: confirm, children: confirmLabel })] })] }) }) })] }));
40
48
  }
@@ -161,4 +161,4 @@ class ConnectClient {
161
161
  }
162
162
  exports.ConnectClient = ConnectClient;
163
163
  /** Kept in step with `package.json` by `sdk.test.ts`. */
164
- exports.SDK_VERSION = "0.24.0";
164
+ exports.SDK_VERSION = "0.24.1";
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from "react";
4
4
  import { Button, Modal } from "@heroui/react";
5
5
  /**
@@ -16,11 +16,19 @@ import { Button, Modal } from "@heroui/react";
16
16
  * rejection is caught here rather than escaping - an error thrown out of an
17
17
  * async transition reaches the nearest error boundary and takes the page down.
18
18
  *
19
- * The anatomy is HeroUI's: `Modal.Backdrop` owns the open state,
20
- * `Modal.Container` the sizing, `Modal.Dialog` the focus trap. The trigger
21
- * goes inside `Modal.Trigger`, which *is* a React Aria button - so pass a
22
- * plain element, never a `<Button>`, or the nested button swallows the press
23
- * and the dialog silently never opens.
19
+ * The anatomy is HeroUI's: the `Modal` root owns the open state,
20
+ * `Modal.Container` the sizing, `Modal.Dialog` the focus trap. **The trigger
21
+ * is a direct child of the root**, never wrapped in `Modal.Trigger`.
22
+ *
23
+ * That wrapping is what this component used to do, and it meant the dialog
24
+ * never opened for any caller passing a `<Button>` - which was all of them.
25
+ * `Modal.Trigger` renders a `div role="button"` inside React Aria's
26
+ * `Pressable` and relies on a plain `onClick` bubbling up to it; a React Aria
27
+ * button nested inside calls `e.stopPropagation()` in its own `usePress`
28
+ * click handler, so the click never arrives. Nothing failed loudly - the
29
+ * press was simply eaten. The root is `DialogTrigger`, whose `PressResponder`
30
+ * the trigger registers with directly, so there is no nesting and no
31
+ * propagation to lose.
24
32
  */
25
33
  export function ConnectConfirmDialog({ trigger, title, description, confirmLabel = "Confirm", cancelLabel = "Cancel", tone = "danger", onConfirm, }) {
26
34
  const [isOpen, setIsOpen] = useState(false);
@@ -33,5 +41,5 @@ export function ConnectConfirmDialog({ trigger, title, description, confirmLabel
33
41
  // caller, which owns the toast and the rollback.
34
42
  });
35
43
  };
36
- return (_jsxs(_Fragment, { children: [_jsx(Modal.Trigger, { onClick: () => setIsOpen(true), children: trigger }), _jsx(Modal.Backdrop, { isOpen: isOpen, onOpenChange: setIsOpen, children: _jsx(Modal.Container, { size: "sm", children: _jsxs(Modal.Dialog, { children: [_jsx(Modal.CloseTrigger, { onPress: () => setIsOpen(false) }), _jsx(Modal.Header, { children: _jsx(Modal.Heading, { children: title }) }), description && (_jsx(Modal.Body, { children: _jsx("p", { className: "text-sm text-muted", children: description }) })), _jsxs(Modal.Footer, { children: [_jsx(Button, { variant: "secondary", onPress: () => setIsOpen(false), children: cancelLabel }), _jsx(Button, { variant: tone === "danger" ? "danger" : "primary", onPress: confirm, children: confirmLabel })] })] }) }) })] }));
44
+ return (_jsxs(Modal, { isOpen: isOpen, onOpenChange: setIsOpen, children: [trigger, _jsx(Modal.Backdrop, { children: _jsx(Modal.Container, { size: "sm", children: _jsxs(Modal.Dialog, { children: [_jsx(Modal.CloseTrigger, { onPress: () => setIsOpen(false) }), _jsx(Modal.Header, { children: _jsx(Modal.Heading, { children: title }) }), description && (_jsx(Modal.Body, { children: _jsx("p", { className: "text-sm text-muted", children: description }) })), _jsxs(Modal.Footer, { children: [_jsx(Button, { variant: "secondary", onPress: () => setIsOpen(false), children: cancelLabel }), _jsx(Button, { variant: tone === "danger" ? "danger" : "primary", onPress: confirm, children: confirmLabel })] })] }) }) })] }));
37
45
  }
@@ -157,4 +157,4 @@ export class ConnectClient {
157
157
  }
158
158
  }
159
159
  /** Kept in step with `package.json` by `sdk.test.ts`. */
160
- export const SDK_VERSION = "0.24.0";
160
+ export const SDK_VERSION = "0.24.1";
@@ -1,6 +1,13 @@
1
1
  import { type ReactNode } from "react";
2
2
  export interface ConnectConfirmDialogProps {
3
- /** The control that opens it. Rendered inside `Modal.Trigger`. */
3
+ /**
4
+ * The control that opens it, and it **must be a pressable** - a HeroUI
5
+ * `Button`, or anything else built on React Aria's `useButton`. It is
6
+ * rendered as a direct child of the `Modal` root, which is React Aria's
7
+ * `DialogTrigger`: that puts a `PressResponder` around its children and the
8
+ * trigger registers with it. A plain `<span>` never registers, and React
9
+ * Aria warns that the responder has no pressable child.
10
+ */
4
11
  trigger: ReactNode;
5
12
  title: ReactNode;
6
13
  /** What will happen, in the user's words. Name the thing being acted on. */
@@ -25,10 +32,18 @@ export interface ConnectConfirmDialogProps {
25
32
  * rejection is caught here rather than escaping - an error thrown out of an
26
33
  * async transition reaches the nearest error boundary and takes the page down.
27
34
  *
28
- * The anatomy is HeroUI's: `Modal.Backdrop` owns the open state,
29
- * `Modal.Container` the sizing, `Modal.Dialog` the focus trap. The trigger
30
- * goes inside `Modal.Trigger`, which *is* a React Aria button - so pass a
31
- * plain element, never a `<Button>`, or the nested button swallows the press
32
- * and the dialog silently never opens.
35
+ * The anatomy is HeroUI's: the `Modal` root owns the open state,
36
+ * `Modal.Container` the sizing, `Modal.Dialog` the focus trap. **The trigger
37
+ * is a direct child of the root**, never wrapped in `Modal.Trigger`.
38
+ *
39
+ * That wrapping is what this component used to do, and it meant the dialog
40
+ * never opened for any caller passing a `<Button>` - which was all of them.
41
+ * `Modal.Trigger` renders a `div role="button"` inside React Aria's
42
+ * `Pressable` and relies on a plain `onClick` bubbling up to it; a React Aria
43
+ * button nested inside calls `e.stopPropagation()` in its own `usePress`
44
+ * click handler, so the click never arrives. Nothing failed loudly - the
45
+ * press was simply eaten. The root is `DialogTrigger`, whose `PressResponder`
46
+ * the trigger registers with directly, so there is no nesting and no
47
+ * propagation to lose.
33
48
  */
34
49
  export declare function ConnectConfirmDialog({ trigger, title, description, confirmLabel, cancelLabel, tone, onConfirm, }: Readonly<ConnectConfirmDialogProps>): import("react").JSX.Element;
@@ -123,4 +123,4 @@ export declare class ConnectClient {
123
123
  constructor(options: ConnectClientOptions);
124
124
  }
125
125
  /** Kept in step with `package.json` by `sdk.test.ts`. */
126
- export declare const SDK_VERSION = "0.24.0";
126
+ export declare const SDK_VERSION = "0.24.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmoops/connect-sdk",
3
- "version": "0.24.0",
3
+ "version": "0.24.1",
4
4
  "description": "Official server-side SDK for the CosmoOps Connect platform API - Login with Connect, entitlements, billing and metering.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "commonjs",