@rokku-x/react-hook-loading-spinner 0.1.0 → 0.1.12
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 +21 -0
- package/dist/hooks/ssrLoading.d.ts +2 -0
- package/dist/hooks/useLoading.d.ts +2 -19
- package/dist/index.cjs.js +4 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.js +5 -4
- package/dist/mainLogic.d.ts +19 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,7 @@ npm install @rokku-x/react-hook-loading-spinner
|
|
|
20
20
|
- 📡 **Event System** - Subscribe to loading state changes
|
|
21
21
|
- ♿ **Accessibility** - Built-in inert attribute and scroll prevention
|
|
22
22
|
- 📱 **Zero Dependencies** - Only requires React and Zustand
|
|
23
|
+
- 🌐 **SSR-Compatible** - Hooks work in SSR; use `ssrLoading` helper in Server Components
|
|
23
24
|
|
|
24
25
|
## Bundle Size
|
|
25
26
|
|
|
@@ -396,6 +397,26 @@ function App() {
|
|
|
396
397
|
loadingComponentScale={1.5}
|
|
397
398
|
/>
|
|
398
399
|
</>
|
|
400
|
+
|
|
401
|
+
### SSR Usage
|
|
402
|
+
|
|
403
|
+
For Server Components, use the SSR-safe helper instead of the client hook:
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
import { ssrLoading } from '@rokku-x/react-hook-loading-spinner';
|
|
407
|
+
|
|
408
|
+
export default function ServerComponent() {
|
|
409
|
+
const { startLoading, stopLoading, isLoading } = ssrLoading();
|
|
410
|
+
|
|
411
|
+
startLoading();
|
|
412
|
+
// ...run your server-side work
|
|
413
|
+
stopLoading();
|
|
414
|
+
|
|
415
|
+
return <div>{isLoading ? 'Loading…' : 'Done'}</div>;
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
For Client Components, continue using `useLoading` as shown above.
|
|
399
420
|
);
|
|
400
421
|
}
|
|
401
422
|
```
|
|
@@ -1,19 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
change: {
|
|
4
|
-
isLoading: boolean;
|
|
5
|
-
isOverrideState: boolean;
|
|
6
|
-
} | null;
|
|
7
|
-
start: null;
|
|
8
|
-
stop: null;
|
|
9
|
-
};
|
|
10
|
-
export declare const loadingEventTarget: EventEmitter<LoadingEvents>;
|
|
11
|
-
export default function useLoading(): {
|
|
12
|
-
overrideLoading: (state: boolean | null) => void;
|
|
13
|
-
startLoading: () => void;
|
|
14
|
-
stopLoading: () => void;
|
|
15
|
-
readonly isLocalLoading: boolean;
|
|
16
|
-
asyncUseLoading: <R, _ extends any[]>(asyncFunction: Promise<R>) => Promise<R>;
|
|
17
|
-
readonly isLoading: boolean;
|
|
18
|
-
};
|
|
19
|
-
export {};
|
|
1
|
+
export { default } from '../mainLogic';
|
|
2
|
+
export * from '../mainLogic';
|
package/dist/index.cjs.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
`),o=i.findIndex(v=>v.includes("api.setState"));if(o<0)return;const l=((t=i[o+1])==null?void 0:t.trim())||"";return(e=/.+ (.+) .+/.exec(l))==null?void 0:e[1]},z=(n,t={})=>(e,i,o)=>{const{enabled:l,anonymousActionType:v,store:s,...p}=t;let f;try{f=(l??(T?"production":void 0)!=="production")&&window.__REDUX_DEVTOOLS_EXTENSION__}catch{}if(!f)return n(e,i,o);const{connection:r,...d}=$(s,f,p);let g=!0;o.setState=((c,L,a)=>{const S=e(c,L);if(!g)return S;const
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("react/jsx-runtime"),m=require("react"),N=require("react-dom"),I=n=>{let t;const e=new Set,i=(f,r)=>{const d=typeof f=="function"?f(t):f;if(!Object.is(d,t)){const g=t;t=r??(typeof d!="object"||d===null)?d:Object.assign({},t,d),e.forEach(u=>u(t,g))}},o=()=>t,s={setState:i,getState:o,getInitialState:()=>p,subscribe:f=>(e.add(f),()=>e.delete(f))},p=t=n(i,o,s);return s},D=(n=>n?I(n):I),F=n=>n;function M(n,t=F){const e=m.useSyncExternalStore(n.subscribe,m.useCallback(()=>t(n.getState()),[n,t]),m.useCallback(()=>t(n.getInitialState()),[n,t]));return m.useDebugValue(e),e}const j=n=>{const t=D(n),e=i=>M(t,i);return Object.assign(e,t),e},P=(n=>n?j(n):j),T={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},C=new Map,x=n=>{const t=C.get(n);return t?Object.fromEntries(Object.entries(t.stores).map(([e,i])=>[e,i.getState()])):{}},$=(n,t,e)=>{if(n===void 0)return{type:"untracked",connection:t.connect(e)};const i=C.get(e.name);if(i)return{type:"tracked",store:n,...i};const o={connection:t.connect(e),stores:{}};return C.set(e.name,o),{type:"tracked",store:n,...o}},J=(n,t)=>{if(t===void 0)return;const e=C.get(n);e&&(delete e.stores[t],Object.keys(e.stores).length===0&&C.delete(n))},U=n=>{var t,e;if(!n)return;const i=n.split(`
|
|
2
|
+
`),o=i.findIndex(v=>v.includes("api.setState"));if(o<0)return;const l=((t=i[o+1])==null?void 0:t.trim())||"";return(e=/.+ (.+) .+/.exec(l))==null?void 0:e[1]},z=(n,t={})=>(e,i,o)=>{const{enabled:l,anonymousActionType:v,store:s,...p}=t;let f;try{f=(l??(T?"production":void 0)!=="production")&&window.__REDUX_DEVTOOLS_EXTENSION__}catch{}if(!f)return n(e,i,o);const{connection:r,...d}=$(s,f,p);let g=!0;o.setState=((c,L,a)=>{const S=e(c,L);if(!g)return S;const _=a===void 0?{type:v||U(new Error().stack)||"anonymous"}:typeof a=="string"?{type:a}:a;return s===void 0?(r?.send(_,i()),S):(r?.send({..._,type:`${s}/${_.type}`},{...x(p.name),[s]:o.getState()}),S)}),o.devtools={cleanup:()=>{r&&typeof r.unsubscribe=="function"&&r.unsubscribe(),J(p.name,s)}};const u=(...c)=>{const L=g;g=!1,e(...c),g=L},E=n(o.setState,i,o);if(d.type==="untracked"?r?.init(E):(d.stores[d.store]=o,r?.init(Object.fromEntries(Object.entries(d.stores).map(([c,L])=>[c,c===d.store?E:L.getState()])))),o.dispatchFromDevtools&&typeof o.dispatch=="function"){let c=!1;const L=o.dispatch;o.dispatch=(...a)=>{(T?"production":void 0)!=="production"&&a[0].type==="__setState"&&!c&&(console.warn('[zustand devtools middleware] "__setState" action type is reserved to set state from the devtools. Avoid using it.'),c=!0),L(...a)}}return r.subscribe(c=>{var L;switch(c.type){case"ACTION":if(typeof c.payload!="string"){console.error("[zustand devtools middleware] Unsupported action format");return}return w(c.payload,a=>{if(a.type==="__setState"){if(s===void 0){u(a.state);return}Object.keys(a.state).length!==1&&console.error(`
|
|
3
3
|
[zustand devtools middleware] Unsupported __setState action format.
|
|
4
4
|
When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),
|
|
5
5
|
and value of this only key should be a state object. Example: { "type": "__setState", "state": { "abc123Store": { "foo": "bar" } } }
|
|
6
|
-
`);const S=a.state[s];if(S==null)return;JSON.stringify(o.getState())!==JSON.stringify(S)&&u(S);return}o.dispatchFromDevtools&&typeof o.dispatch=="function"&&o.dispatch(a)});case"DISPATCH":switch(c.payload.type){case"RESET":return u(E),s===void 0?r?.init(o.getState()):r?.init(x(p.name));case"COMMIT":if(s===void 0){r?.init(o.getState());return}return r?.init(x(p.name));case"ROLLBACK":return
|
|
6
|
+
`);const S=a.state[s];if(S==null)return;JSON.stringify(o.getState())!==JSON.stringify(S)&&u(S);return}o.dispatchFromDevtools&&typeof o.dispatch=="function"&&o.dispatch(a)});case"DISPATCH":switch(c.payload.type){case"RESET":return u(E),s===void 0?r?.init(o.getState()):r?.init(x(p.name));case"COMMIT":if(s===void 0){r?.init(o.getState());return}return r?.init(x(p.name));case"ROLLBACK":return w(c.state,a=>{if(s===void 0){u(a),r?.init(o.getState());return}u(a[s]),r?.init(x(p.name))});case"JUMP_TO_STATE":case"JUMP_TO_ACTION":return w(c.state,a=>{if(s===void 0){u(a);return}JSON.stringify(o.getState())!==JSON.stringify(a[s])&&u(a[s])});case"IMPORT_STATE":{const{nextLiftedState:a}=c.payload,S=(L=a.computedStates.slice(-1)[0])==null?void 0:L.state;if(!S)return;u(s===void 0?S:S[s]),r?.send(null,a);return}case"PAUSE_RECORDING":return g=!g}return}}),E},W=z,w=(n,t)=>{let e;try{e=JSON.parse(n)}catch(i){console.error("[zustand devtools middleware] Could not parse the received json",i)}e!==void 0&&t(e)};class R extends EventTarget{constructor(){super(...arguments),this.controller=new AbortController}on(t,e){return this.addEventListener(t,i=>e(i.detail),{signal:this.controller.signal}),this}once(t,e){return this.addEventListener(t,i=>e(i.detail),{signal:this.controller.signal,once:!0}),this}emit(t,e){return this.dispatchEvent(new CustomEvent(t,{detail:e}))}removeAllListeners(){this.controller.abort(),this.controller=new AbortController}}const b=new R,V=P()(W((n,t)=>({loadingCount:0,overrideState:null,localCounters:{},isLoading(){return t().overrideState??t().loadingCount>0},actions:{isGlobalLoading(){return t().isLoading()},startLoading:e=>{const i=t().isLoading();n(l=>({loadingCount:l.loadingCount+1})),e&&n(l=>({localCounters:{...l.localCounters,[e]:(l.localCounters[e]??0)+1}}));const o=t().isLoading();o&&!i&&b.emit("start",null),b.emit("change",{isLoading:o,isOverrideState:t().overrideState!==null})},stopLoading:e=>{const i=t().isLoading(),o=e?t().localCounters[e]??0:0;e&&o>0&&n(v=>({loadingCount:Math.max(0,v.loadingCount-1),localCounters:{...v.localCounters,[e]:Math.max(0,v.localCounters[e]-1)}}));const l=t().isLoading();!l&&i&&b.emit("stop",null),b.emit("change",{isLoading:l,isOverrideState:t().overrideState!==null})},overrideLoading:e=>{const i=t().isLoading();n({overrideState:e});const o=t().isLoading();o&&!i?b.emit("start",null):!o&&i&&b.emit("stop",null),b.emit("change",{isLoading:o,isOverrideState:e!==null})},getLocalCounter:e=>t().localCounters[e]??0,isLocalLoading:e=>(t().localCounters[e]??0)>0}})));function O(){const n=m.useId(),{actions:t}=V(l=>l),e=()=>{t.startLoading(n)},i=()=>{t.isLocalLoading(n)&&t.stopLoading(n)},o=async l=>{e();try{return await l}finally{i()}};return{overrideLoading:t.overrideLoading,startLoading:e,stopLoading:i,get isLocalLoading(){return t.isLocalLoading(n)},asyncUseLoading:o,get isLoading(){return t.isGlobalLoading()}}}const y={Spin:"spin",FadeInOut:"fadeInOut",None:"none"},q=({scale:n=1,animationType:t=y.Spin,animationDuration:e,children:i,style:o,className:l,id:v,prefix:s})=>{const p=t,f=t===y.Spin?1:t===y.FadeInOut?2:0,r=e||f,d=t===y.Spin?"linear":t===y.FadeInOut?"ease-in-out":"linear",g=t===y.None?"none":`${s}-${p} ${r}s ${d} infinite`;return h.jsx("div",{style:{animation:g,...n!==1?{zoom:n}:{},...o},className:l,id:v,children:i})},A=n=>h.jsx("div",{id:"loading-circle",style:{width:"90px",height:"90px",border:"15px solid #f3f3f3",borderTop:"15px solid #009b4bff",borderRadius:"50%",boxSizing:"border-box"},...n}),k=n=>h.jsx("div",{style:{padding:"20px",fontSize:"25px",color:"#333",fontFamily:"system-ui, sans-serif"},...n,children:"Please wait..."});function B({loadingComponent:n,loadingComponentScale:t=1,animationType:e=y.Spin,animationDuration:i,wrapperStyle:o,wrapperClassName:l,wrapperId:v,animationWrapperStyle:s,animationWrapperClassName:p,animationWrapperId:f}){n=n||(e===y.Spin?A:k);const r=m.useRef(Math.random().toString(36).substring(2,6).replace(/[0-9]/g,"")),{isLoading:d}=O(),g=m.useRef(null);m.useEffect(()=>{d?(g.current?.showModal(),document.body.setAttribute("inert","")):(g.current?.close(),document.body.removeAttribute("inert"))},[d]);const u=v||"loading-wrapper-"+r.current;return d?N.createPortal(h.jsxs(h.Fragment,{children:[h.jsx("style",{children:`
|
|
7
7
|
dialog#${u}[open] {
|
|
8
8
|
display: flex !important;
|
|
9
9
|
justify-content: center;
|
|
@@ -27,4 +27,4 @@
|
|
|
27
27
|
body {
|
|
28
28
|
scrollbar-gutter: stable;
|
|
29
29
|
}
|
|
30
|
-
`}),h.jsx("dialog",{ref:g,style:{border:"none",padding:0,backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",...o},className:l,id:u,children:h.jsx(q,{scale:t,animationType:e,animationDuration:i,style:s,className:p,id:f,prefix:r.current,children:m.isValidElement(n)?n:m.createElement(n)})})]}),document.body):null}function G({isLoading:n=!1}){const{startLoading:t,stopLoading:e}=
|
|
30
|
+
`}),h.jsx("dialog",{ref:g,style:{border:"none",padding:0,backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",...o},className:l,id:u,children:h.jsx(q,{scale:t,animationType:e,animationDuration:i,style:s,className:p,id:f,prefix:r.current,children:m.isValidElement(n)?n:m.createElement(n)})})]}),document.body):null}function G({isLoading:n=!1}){const{startLoading:t,stopLoading:e}=O();return m.useEffect(()=>(n?t():e(),()=>{n&&e()}),[n]),null}exports.AnimationType=y;exports.EventEmitter=R;exports.Loading=G;exports.LoadingCircle=A;exports.LoadingPleaseWait=k;exports.LoadingRenderer=B;exports.loadingEventTarget=b;exports.ssrLoading=O;exports.useLoading=O;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { default as useLoading } from './hooks/useLoading';
|
|
2
|
-
export {
|
|
3
|
-
export { default as LoadingRenderer } from './components/LoadingRenderer';
|
|
2
|
+
export { default as ssrLoading } from './hooks/ssrLoading';
|
|
4
3
|
export { LoadingCircle, LoadingPleaseWait, AnimationType } from './components/LoadingRenderer';
|
|
5
4
|
export type { AnimationType as AnimationTypeType } from './components/LoadingRenderer';
|
|
6
5
|
export { default as Loading } from './components/Loading';
|
|
6
|
+
export { default as LoadingRenderer } from './components/LoadingRenderer';
|
|
7
7
|
export { default as EventEmitter } from './utils/EventEmitter';
|
|
8
|
+
export { loadingEventTarget } from './mainLogic';
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { jsx as L, jsxs as N, Fragment as j } from "react/jsx-runtime";
|
|
3
|
+
import y, { useId as D, useRef as x, useEffect as k } from "react";
|
|
4
4
|
import { createPortal as F } from "react-dom";
|
|
5
5
|
const I = (n) => {
|
|
6
6
|
let t;
|
|
@@ -271,7 +271,7 @@ const b = new G(), X = J()(B((n, t) => ({
|
|
|
271
271
|
}
|
|
272
272
|
})));
|
|
273
273
|
function A() {
|
|
274
|
-
const n =
|
|
274
|
+
const n = D(), { actions: t } = X((l) => l), e = () => {
|
|
275
275
|
t.startLoading(n);
|
|
276
276
|
}, r = () => {
|
|
277
277
|
t.isLocalLoading(n) && t.stopLoading(n);
|
|
@@ -323,7 +323,7 @@ function tt({
|
|
|
323
323
|
}, [d]);
|
|
324
324
|
const u = v || "loading-wrapper-" + i.current;
|
|
325
325
|
return d ? F(
|
|
326
|
-
/* @__PURE__ */ j
|
|
326
|
+
/* @__PURE__ */ N(j, { children: [
|
|
327
327
|
/* @__PURE__ */ L("style", { children: `
|
|
328
328
|
dialog#${u}[open] {
|
|
329
329
|
display: flex !important;
|
|
@@ -383,5 +383,6 @@ export {
|
|
|
383
383
|
q as LoadingPleaseWait,
|
|
384
384
|
tt as LoadingRenderer,
|
|
385
385
|
b as loadingEventTarget,
|
|
386
|
+
A as ssrLoading,
|
|
386
387
|
A as useLoading
|
|
387
388
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { default as EventEmitter } from './utils/EventEmitter';
|
|
2
|
+
type LoadingEvents = {
|
|
3
|
+
change: {
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
isOverrideState: boolean;
|
|
6
|
+
} | null;
|
|
7
|
+
start: null;
|
|
8
|
+
stop: null;
|
|
9
|
+
};
|
|
10
|
+
export declare const loadingEventTarget: EventEmitter<LoadingEvents>;
|
|
11
|
+
export default function (): {
|
|
12
|
+
overrideLoading: (state: boolean | null) => void;
|
|
13
|
+
startLoading: () => void;
|
|
14
|
+
stopLoading: () => void;
|
|
15
|
+
readonly isLocalLoading: boolean;
|
|
16
|
+
asyncUseLoading: <R, _ extends any[]>(asyncFunction: Promise<R>) => Promise<R>;
|
|
17
|
+
readonly isLoading: boolean;
|
|
18
|
+
};
|
|
19
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokku-x/react-hook-loading-spinner",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "A lightweight and flexible React loading state hook library with built-in spinner components, global state management, and zero dependencies (except React and Zustand).",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|