axokit-react 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -34,6 +34,7 @@ function SaveButton() {
34
34
  loadingText="Saving..."
35
35
  successText="Saved ✓"
36
36
  errorText="Try again"
37
+ showSpinner // built‑in loader
37
38
  disableOnSuccess={false} // optional
38
39
  className="px-4 py-2 rounded bg-blue-600 text-white"
39
40
  >
@@ -74,6 +75,7 @@ function HookExample() {
74
75
  - `successDuration?: number` — default: `1200` ms.
75
76
  - `errorDuration?: number` — default: `3000` ms.
76
77
  - `disableOnSuccess?: boolean` — default: `true`.
78
+ - `showSpinner?: boolean` — default: `false`. When `true`, a tiny built‑in SVG spinner appears to the left of the label during loading.
77
79
  - `onSuccess?: () => void`.
78
80
  - `onActionError?: (error: Error) => void`.
79
81
  - All other native `button` props are forwarded.
package/dist/index.d.ts CHANGED
@@ -25,8 +25,10 @@ interface AsyncButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>
25
25
  onSuccess?: () => void;
26
26
  onActionError?: (error: Error) => void;
27
27
  disableOnSuccess?: boolean;
28
+ /** automatically render a small spinner next to the label when loading */
29
+ showSpinner?: boolean;
28
30
  children: React.ReactNode;
29
31
  }
30
- declare function AsyncButton({ onAction, loadingText, successText, errorText, successDuration, errorDuration, onSuccess, onActionError, disableOnSuccess, children, disabled, className, ...props }: AsyncButtonProps): react_jsx_runtime.JSX.Element;
32
+ declare function AsyncButton({ onAction, loadingText, successText, errorText, successDuration, errorDuration, onSuccess, onActionError, disableOnSuccess, showSpinner, children, disabled, className, ...props }: AsyncButtonProps): react_jsx_runtime.JSX.Element;
31
33
 
32
34
  export { AsyncButton, useAsyncAction };
package/dist/index.js CHANGED
@@ -45,6 +45,7 @@ function useAsyncAction(action, options = {}) {
45
45
  const timeoutRef = React.useRef(null);
46
46
  const mountedRef = React.useRef(true);
47
47
  React.useEffect(() => {
48
+ mountedRef.current = true;
48
49
  return () => {
49
50
  mountedRef.current = false;
50
51
  if (timeoutRef.current) {
@@ -109,6 +110,7 @@ function AsyncButton({
109
110
  onSuccess,
110
111
  onActionError,
111
112
  disableOnSuccess = true,
113
+ showSpinner = false,
112
114
  children,
113
115
  disabled,
114
116
  className = "",
@@ -132,6 +134,31 @@ function AsyncButton({
132
134
  return children;
133
135
  }
134
136
  };
137
+ const renderContent = () => {
138
+ const label = getLabel();
139
+ if (state === "loading" && showSpinner) {
140
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "0.5em", alignItems: "center" }, children: [
141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
142
+ "svg",
143
+ {
144
+ xmlns: "http://www.w3.org/2000/svg",
145
+ width: "24",
146
+ height: "24",
147
+ viewBox: "0 0 24 24",
148
+ fill: "none",
149
+ stroke: "currentColor",
150
+ "stroke-width": "2",
151
+ "stroke-linecap": "round",
152
+ "stroke-linejoin": "round",
153
+ className: "lucide lucide-loader-circle-icon lucide-loader-circle",
154
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
155
+ }
156
+ ),
157
+ label
158
+ ] }) });
159
+ }
160
+ return label;
161
+ };
135
162
  const isDisabled = disabled || state === "loading" || state === "success" && disableOnSuccess;
136
163
  const { onClick: _nativeOnClick, type: buttonType = "button", ...rest } = props;
137
164
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -144,7 +171,7 @@ function AsyncButton({
144
171
  disabled: isDisabled,
145
172
  "aria-busy": state === "loading",
146
173
  "data-state": state,
147
- children: getLabel()
174
+ children: renderContent()
148
175
  }
149
176
  );
150
177
  }
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/AsyncButton.tsx
2
2
  import * as React from "react";
3
- import { jsx } from "react/jsx-runtime";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  function useAsyncAction(action, options = {}) {
5
5
  const { successDuration = 1200, errorDuration = 3e3, onSuccess, onActionError } = options;
6
6
  const [state, setState] = React.useState("idle");
@@ -8,6 +8,7 @@ function useAsyncAction(action, options = {}) {
8
8
  const timeoutRef = React.useRef(null);
9
9
  const mountedRef = React.useRef(true);
10
10
  React.useEffect(() => {
11
+ mountedRef.current = true;
11
12
  return () => {
12
13
  mountedRef.current = false;
13
14
  if (timeoutRef.current) {
@@ -72,6 +73,7 @@ function AsyncButton({
72
73
  onSuccess,
73
74
  onActionError,
74
75
  disableOnSuccess = true,
76
+ showSpinner = false,
75
77
  children,
76
78
  disabled,
77
79
  className = "",
@@ -95,6 +97,31 @@ function AsyncButton({
95
97
  return children;
96
98
  }
97
99
  };
100
+ const renderContent = () => {
101
+ const label = getLabel();
102
+ if (state === "loading" && showSpinner) {
103
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5em", alignItems: "center" }, children: [
104
+ /* @__PURE__ */ jsx(
105
+ "svg",
106
+ {
107
+ xmlns: "http://www.w3.org/2000/svg",
108
+ width: "24",
109
+ height: "24",
110
+ viewBox: "0 0 24 24",
111
+ fill: "none",
112
+ stroke: "currentColor",
113
+ "stroke-width": "2",
114
+ "stroke-linecap": "round",
115
+ "stroke-linejoin": "round",
116
+ className: "lucide lucide-loader-circle-icon lucide-loader-circle",
117
+ children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
118
+ }
119
+ ),
120
+ label
121
+ ] }) });
122
+ }
123
+ return label;
124
+ };
98
125
  const isDisabled = disabled || state === "loading" || state === "success" && disableOnSuccess;
99
126
  const { onClick: _nativeOnClick, type: buttonType = "button", ...rest } = props;
100
127
  return /* @__PURE__ */ jsx(
@@ -107,7 +134,7 @@ function AsyncButton({
107
134
  disabled: isDisabled,
108
135
  "aria-busy": state === "loading",
109
136
  "data-state": state,
110
- children: getLabel()
137
+ children: renderContent()
111
138
  }
112
139
  );
113
140
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axokit-react",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Headless async button and hook for React",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",