roks-rjsc 0.1.0
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/LICENSE +21 -0
- package/README.md +105 -0
- package/dist/index.cjs.js +54 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.esm.js +309 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 rokku
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# roks-rjsc
|
|
2
|
+
|
|
3
|
+
A small React component library exposing a few UI helpers and modal/loading utilities.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install from npm (after publishing):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install roks-rjsc
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
During development you can also install directly from GitHub:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install github:rokku-x/roks-rjsc
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Import named exports from the package root. Examples below assume React 18.
|
|
22
|
+
|
|
23
|
+
Basic component:
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import React from 'react';
|
|
27
|
+
import { Button } from 'roks-rjsc';
|
|
28
|
+
|
|
29
|
+
export default function App() {
|
|
30
|
+
return <Button onClick={() => alert('clicked')}>Click me</Button>;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Loading provider and hook:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import React from 'react';
|
|
38
|
+
import { LoadingProvider, useLoading } from 'roks-rjsc';
|
|
39
|
+
|
|
40
|
+
function Example() {
|
|
41
|
+
const { startLoading, stopLoading, asyncUseLoading } = useLoading();
|
|
42
|
+
|
|
43
|
+
const handle = async () => {
|
|
44
|
+
startLoading();
|
|
45
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
46
|
+
stopLoading();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return <button onClick={handle}>Load</button>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default function AppWrapper() {
|
|
53
|
+
return (
|
|
54
|
+
<LoadingProvider>
|
|
55
|
+
<Example />
|
|
56
|
+
</LoadingProvider>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Modal helpers (BaseModalProvider + hooks):
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import React from 'react';
|
|
65
|
+
import { BaseModalProvider, useStaticModal, useDynamicModal } from 'roks-rjsc';
|
|
66
|
+
|
|
67
|
+
function StaticExample() {
|
|
68
|
+
const [show, close, id] = useStaticModal();
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<button onClick={() => show(<div>Static content</div>)}>Open static modal</button>
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function DynamicExample() {
|
|
78
|
+
const [render, show, close, focus] = useDynamicModal();
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<>
|
|
82
|
+
<button onClick={() => show()}>Open dynamic modal</button>
|
|
83
|
+
{render(<div>Rendered into dynamic modal</div>)}
|
|
84
|
+
</>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default function App() {
|
|
89
|
+
return (
|
|
90
|
+
<BaseModalProvider>
|
|
91
|
+
<StaticExample />
|
|
92
|
+
<DynamicExample />
|
|
93
|
+
</BaseModalProvider>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
API (top-level exports)
|
|
99
|
+
- `Button` - basic button component
|
|
100
|
+
- `LoadingProvider`, `useLoading`, `Loading`, `AnimationType` - loading utilities
|
|
101
|
+
- `BaseModalProvider`, `useBaseModal`, `useStaticModal`, `useDynamicModal`, `RenderMode` - modal system
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),a=require("react"),N=require("react-dom"),F=({children:o,onClick:e})=>c.jsx("button",{onClick:e,children:o});class T extends EventTarget{constructor(){super(...arguments),this.controller=new AbortController}on(e,n){return this.addEventListener(e,f=>n(f.detail),{signal:this.controller.signal}),this}once(e,n){return this.addEventListener(e,f=>n(f.detail),{signal:this.controller.signal,once:!0}),this}emit(e,n){return this.dispatchEvent(new CustomEvent(e,{detail:n}))}removeAllListeners(){this.controller.abort(),this.controller=new AbortController}}const C=new T,w={Spin:"spin",FadeInOut:"fadeInOut",None:"none"},I=({animationType:o=w.Spin,animationDuration:e,children:n,style:f,className:g,id:r})=>{const u=o,h=o===w.Spin?1:o===w.FadeInOut?2:0,d=e||h,s=o===w.Spin?"linear":o===w.FadeInOut?"ease-in-out":"linear",m=o===w.None?"none":`${u} ${d}s ${s} infinite`;return c.jsx("div",{style:{animation:m,...f},className:g,id:r,children:n})},$=()=>c.jsx("div",{id:"loading-circle",style:{width:"60px",height:"60px",border:"10px solid #f3f3f3",borderTop:"10px solid #009b4bff",borderRadius:"50%"}}),U=()=>c.jsx("div",{style:{padding:"20px",fontSize:"25px",color:"#333",fontFamily:"system-ui, sans-serif"},children:"Please wait..."}),P=a.createContext(void 0),W=({children:o,loadingComponent:e,animationType:n=w.FadeInOut,animationDuration:f,wrapperStyle:g,wrapperClassName:r,wrapperId:u,animationWrapperStyle:h,animationWrapperClassName:d,animationWrapperId:s})=>{e=e||(n===w.Spin?$:U);const[m,p]=a.useState(0),[R,E]=a.useState(null),b=R??m>0,j=M=>E(M),k=()=>p(M=>M+1),A=()=>p(M=>Math.max(0,M-1)),L=a.useRef(null);a.useEffect(()=>{C.emit("change",{isLoading:b}),C.emit(b?"start":"stop",null),b?(L.current?.showModal(),document.body.setAttribute("inert","")):b||document.body.removeAttribute("inert")},[m]),a.useEffect(()=>()=>{p(0),C.removeAllListeners()},[]);const y=u||"loading-dialog";return c.jsxs(P.Provider,{value:{get isLoading(){return b},startLoading:k,stopLoading:A,loadingEventTarget:C,overrideLoading:j},children:[o,b&&N.createPortal(c.jsxs(c.Fragment,{children:[c.jsx("style",{children:`
|
|
2
|
+
dialog#${y}[open] {
|
|
3
|
+
display: flex !important;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
align-items: center;
|
|
6
|
+
width: 100vw;
|
|
7
|
+
height: 100vh;
|
|
8
|
+
max-width: 100%;
|
|
9
|
+
max-height: 100%;
|
|
10
|
+
}
|
|
11
|
+
@keyframes spin {
|
|
12
|
+
0% { transform: rotate(0deg); }
|
|
13
|
+
100% { transform: rotate(360deg); }
|
|
14
|
+
}
|
|
15
|
+
@keyframes fadeInOut {
|
|
16
|
+
0%, 100% { opacity: 0.2; }
|
|
17
|
+
50% { opacity: 1; }
|
|
18
|
+
}
|
|
19
|
+
body:has(dialog#${y}[open]) {
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
}
|
|
22
|
+
body {
|
|
23
|
+
scrollbar-gutter: stable;
|
|
24
|
+
}
|
|
25
|
+
`}),c.jsx("dialog",{ref:L,style:{border:"none",padding:0,backgroundColor:"rgba(0, 0, 0, 0.5)",backdropFilter:"blur(2px)",...g},className:r,id:y,children:c.jsx(I,{animationType:n,animationDuration:f,style:h,className:d,id:s,children:a.isValidElement(e)?e:a.createElement(e)})})]}),document.body)]})},B=()=>{const o=a.useContext(P);if(!o)throw new Error("useLoading must be used within a LoadingProvider");const e=a.useRef(0),{startLoading:n,stopLoading:f,isLoading:g,...r}=o,u=()=>{n(),e.current+=1},h=()=>{e.current>0&&(f(),e.current-=1)};return{startLoading:u,stopLoading:h,get isLocalLoading(){return e.current>0},...r,asyncUseLoading:async s=>{u();try{return await s}finally{h()}},isLoading:g}};function _({isLoading:o=!1}){const e=B();return a.useEffect(()=>(o?e.startLoading():e.stopLoading(),()=>{o&&e.stopLoading()}),[o]),null}const S=a.createContext(void 0),x={STACKED:0,CURRENT_ONLY:1,CURRENT_HIDDEN_STACK:2};function K({children:o,wrapperId:e,renderMode:n=x.STACKED,wrapperStyle:f}){const g=a.useRef(null),r=a.useRef(new Map),[u,h]=a.useState(r.current),d=Array.from(u.values()),s=Array.from(u.keys()),m=a.useRef(new Map),[p,R]=a.useState(void 0),E=(t,i=Math.random().toString(36).substring(2,6),l=!1)=>{if(s.indexOf(i)!==-1)return console.warn(`Modal with id ${i} already exists. Choose a different id.`),i;let D=[t,l];return r.current=new Map(r.current),r.current.set(i,D),h(new Map(r.current)),i},b=t=>{let i="";if(typeof t!="string"){for(let[l,v]of r.current.entries())if(v[0]===t){i=l;break}}else typeof t=="string"&&(i=t);return r.current.has(i)?(r.current=new Map(r.current),r.current.delete(i),h(new Map(r.current)),!0):!1},j=(t,i)=>{if(r.current.has(t)){let l=r.current.get(t);if(l[1]===!1){console.warn(`Modal with id ${t} is dynamic. Cannot update content.`);return}l[0]=i,r.current.set(t,l),h(new Map(r.current))}},k=t=>{if(!u.has(t))return!1;let i=r.current.get(t);return r.current.delete(t),r.current.set(t,i),h(new Map(r.current)),!0},A=t=>s.indexOf(t),L=t=>m.current.get(t);a.useEffect(()=>{const t=s[s.length-1];t!==void 0?(g.current?.showModal(),document.body.setAttribute("inert","")):t===void 0&&(g.current?.close(),document.body.removeAttribute("inert")),R(t)},[u]);const y=e||"base-modal-wrapper",M=a.useCallback((t,i)=>{t?m.current.set(i,t):m.current.delete(i)},[]),O=()=>{switch(n){case x.STACKED:return d.map(([t,i],l)=>c.jsx("div",{ref:v=>M(v,s[l]),className:"modal-window",id:s[l],style:{display:"block",zIndex:s[l]===p?1e3:100},...p!==s[l]?{inert:""}:{},children:i?null:t},s[l]));case x.CURRENT_ONLY:return d.length>0?c.jsx("div",{id:s[d.length-1],ref:t=>M(t,s[d.length-1]),className:"modal-window",style:{display:"block"},children:d[d.length-1][1]?null:d[d.length-1][0]},s[d.length-1]):null;case x.CURRENT_HIDDEN_STACK:return d.length>0?d.map(([t,i],l)=>c.jsx("div",{ref:v=>M(v,s[l]),id:s[l],className:"modal-window",style:{display:p===s[l]?"block":"none"},...p!==s[l]?{inert:""}:{},children:i?null:t},s[l])):null}};return c.jsxs(S.Provider,{value:{modalCount:0,get renderMode(){return n},pushModal:E,popModal:b,currentModalId:p,updateModalContent:j,getModalWindowRef:L,focusModal:k,getModalOrderIndex:A},children:[o,s.length===0?null:N.createPortal(c.jsxs(c.Fragment,{children:[c.jsx("style",{children:`
|
|
26
|
+
dialog#${y}[open] {
|
|
27
|
+
display: flex !important;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
align-items: center;
|
|
30
|
+
width: 100vw;
|
|
31
|
+
height: 100vh;
|
|
32
|
+
max-width: 100%;
|
|
33
|
+
max-height: 100%;
|
|
34
|
+
}
|
|
35
|
+
body:has(dialog#${y}[open]) {
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
}
|
|
38
|
+
body {
|
|
39
|
+
scrollbar-gutter: stable;
|
|
40
|
+
}
|
|
41
|
+
.modal-wrapper{
|
|
42
|
+
border: none;
|
|
43
|
+
padding: 0;
|
|
44
|
+
background: unset;
|
|
45
|
+
}
|
|
46
|
+
.modal-window {
|
|
47
|
+
position: absolute;
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 100%;
|
|
50
|
+
display: none;
|
|
51
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
52
|
+
backdrop-filter: blur(2px);
|
|
53
|
+
}
|
|
54
|
+
`}),c.jsx("dialog",{className:"modal-wrapper",ref:g,id:y,style:f,children:O()})]}),document.body)]})}function q(){const o=a.useContext(S);if(!o)throw new Error("useBaseModal must be used within a BaseModalProvider");return o}function z(o=Math.random().toString(36).substring(2,6)){const e=a.useContext(S);if(!e)throw new Error("useBaseModal must be used within a BaseModalProvider");let n=a.useRef(o);const f=u=>(e.pushModal(u,n.current),g),g=()=>e.popModal(n.current),r=u=>{e.updateModalContent(n.current,u)};return[f,g,n.current,e.currentModalId===n.current,r]}function H(o=Math.random().toString(36).substring(2,6)){const e=a.useContext(S);if(!e)throw new Error("useBaseModal must be used within a BaseModalProvider");let n=a.useRef(o);const f=e.currentModalId===n.current;return[d=>e.getModalWindowRef(n.current)?N.createPortal(d,e.getModalWindowRef(n.current)):null,()=>{e.pushModal(null,n.current,!0)[1]},()=>{e.popModal(n.current)},()=>{e.focusModal(n.current)},n.current,f]}exports.AnimationType=w;exports.BaseModalProvider=K;exports.Button=F;exports.Loading=_;exports.LoadingProvider=W;exports.RenderMode=x;exports.useBaseModal=q;exports.useDynamicModal=H;exports.useLoading=B;exports.useStaticModal=z;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { default as default_2 } from 'react';
|
|
2
|
+
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
export declare const AnimationType: {
|
|
6
|
+
readonly Spin: "spin";
|
|
7
|
+
readonly FadeInOut: "fadeInOut";
|
|
8
|
+
readonly None: "none";
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export declare type AnimationType = (typeof AnimationType)[keyof typeof AnimationType];
|
|
12
|
+
|
|
13
|
+
declare interface BaseModalContextType {
|
|
14
|
+
modalCount: number;
|
|
15
|
+
renderMode?: RenderMode;
|
|
16
|
+
currentModalId?: string;
|
|
17
|
+
pushModal: (el: default_2.ReactNode, modalId?: string, isDynamic?: boolean) => string;
|
|
18
|
+
popModal: (idEl: string | default_2.ReactNode) => boolean;
|
|
19
|
+
updateModalContent: (modalId: string, newContent: default_2.ReactNode) => void;
|
|
20
|
+
getModalWindowRef: (modalId: string) => HTMLDivElement | undefined;
|
|
21
|
+
focusModal: (modalId: string) => boolean;
|
|
22
|
+
getModalOrderIndex: (modalId: string) => number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export declare function BaseModalProvider({ children, wrapperId, renderMode, wrapperStyle }: {
|
|
26
|
+
children: default_2.ReactNode;
|
|
27
|
+
wrapperId?: string;
|
|
28
|
+
renderMode?: RenderMode;
|
|
29
|
+
wrapperStyle?: default_2.CSSProperties;
|
|
30
|
+
}): JSX_2.Element;
|
|
31
|
+
|
|
32
|
+
export declare const Button: ({ children, onClick }: ButtonProps) => JSX_2.Element;
|
|
33
|
+
|
|
34
|
+
declare interface ButtonProps {
|
|
35
|
+
children: default_2.ReactNode;
|
|
36
|
+
onClick?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare class EventEmitter<T extends EventMap> extends EventTarget {
|
|
40
|
+
private controller;
|
|
41
|
+
on<K extends keyof T>(type: K, callback: (detail: T[K]) => void): this;
|
|
42
|
+
once<K extends keyof T>(type: K, callback: (detail: T[K]) => void): this;
|
|
43
|
+
emit<K extends keyof T>(type: K, detail: T[K]): boolean;
|
|
44
|
+
removeAllListeners(): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
declare type EventMap = Record<string, any>;
|
|
48
|
+
|
|
49
|
+
export declare function Loading({ isLoading }: {
|
|
50
|
+
isLoading: boolean;
|
|
51
|
+
}): null;
|
|
52
|
+
|
|
53
|
+
export declare const LoadingProvider: default_2.FC<{
|
|
54
|
+
children: ReactNode;
|
|
55
|
+
loadingComponent?: default_2.ComponentType | default_2.ReactElement;
|
|
56
|
+
animationType?: AnimationType;
|
|
57
|
+
animationDuration?: number;
|
|
58
|
+
wrapperStyle?: default_2.CSSProperties;
|
|
59
|
+
wrapperClassName?: string;
|
|
60
|
+
wrapperId?: string;
|
|
61
|
+
animationWrapperStyle?: default_2.CSSProperties;
|
|
62
|
+
animationWrapperClassName?: string;
|
|
63
|
+
animationWrapperId?: string;
|
|
64
|
+
}>;
|
|
65
|
+
|
|
66
|
+
export declare const RenderMode: {
|
|
67
|
+
STACKED: number;
|
|
68
|
+
CURRENT_ONLY: number;
|
|
69
|
+
CURRENT_HIDDEN_STACK: number;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export declare type RenderMode = (typeof RenderMode)[keyof typeof RenderMode];
|
|
73
|
+
|
|
74
|
+
export declare function useBaseModal(): BaseModalContextType;
|
|
75
|
+
|
|
76
|
+
export declare function useDynamicModal(id?: string): [(el: JSX.Element) => ReactNode, () => void, () => void, () => void, string, boolean];
|
|
77
|
+
|
|
78
|
+
export declare const useLoading: () => {
|
|
79
|
+
asyncUseLoading: <R, _ extends any[]>(asyncFunction: Promise<R>) => Promise<R>;
|
|
80
|
+
isLoading: boolean;
|
|
81
|
+
loadingEventTarget: EventEmitter< {
|
|
82
|
+
change: {
|
|
83
|
+
isLoading: boolean;
|
|
84
|
+
} | null;
|
|
85
|
+
start: null;
|
|
86
|
+
stop: null;
|
|
87
|
+
}>;
|
|
88
|
+
overrideLoading: (state: boolean) => void;
|
|
89
|
+
startLoading: () => void;
|
|
90
|
+
stopLoading: () => void;
|
|
91
|
+
isLocalLoading: boolean;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export declare function useStaticModal(id?: string): [(el: React.ReactNode) => () => boolean, () => boolean, string, boolean, (newContent: React.ReactNode) => void];
|
|
95
|
+
|
|
96
|
+
export { }
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { jsx as f, jsxs as S, Fragment as $ } from "react/jsx-runtime";
|
|
2
|
+
import I, { useState as E, useRef as y, useEffect as R, createContext as T, useContext as k, useCallback as K } from "react";
|
|
3
|
+
import { createPortal as D } from "react-dom";
|
|
4
|
+
const Q = ({ children: o, onClick: e }) => /* @__PURE__ */ f("button", { onClick: e, children: o });
|
|
5
|
+
class j extends EventTarget {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments), this.controller = new AbortController();
|
|
8
|
+
}
|
|
9
|
+
on(e, n) {
|
|
10
|
+
return this.addEventListener(
|
|
11
|
+
e,
|
|
12
|
+
(c) => n(c.detail),
|
|
13
|
+
{ signal: this.controller.signal }
|
|
14
|
+
), this;
|
|
15
|
+
}
|
|
16
|
+
once(e, n) {
|
|
17
|
+
return this.addEventListener(
|
|
18
|
+
e,
|
|
19
|
+
(c) => n(c.detail),
|
|
20
|
+
{
|
|
21
|
+
signal: this.controller.signal,
|
|
22
|
+
once: !0
|
|
23
|
+
}
|
|
24
|
+
), this;
|
|
25
|
+
}
|
|
26
|
+
emit(e, n) {
|
|
27
|
+
return this.dispatchEvent(new CustomEvent(e, { detail: n }));
|
|
28
|
+
}
|
|
29
|
+
removeAllListeners() {
|
|
30
|
+
this.controller.abort(), this.controller = new AbortController();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const C = new j(), M = {
|
|
34
|
+
Spin: "spin",
|
|
35
|
+
FadeInOut: "fadeInOut",
|
|
36
|
+
None: "none"
|
|
37
|
+
}, z = ({ animationType: o = M.Spin, animationDuration: e, children: n, style: c, className: u, id: r }) => {
|
|
38
|
+
const d = o, g = o === M.Spin ? 1 : o === M.FadeInOut ? 2 : 0, l = e || g, a = o === M.Spin ? "linear" : o === M.FadeInOut ? "ease-in-out" : "linear", w = o === M.None ? "none" : `${d} ${l}s ${a} infinite`;
|
|
39
|
+
return /* @__PURE__ */ f("div", { style: { animation: w, ...c }, className: u, id: r, children: n });
|
|
40
|
+
}, H = () => /* @__PURE__ */ f("div", { id: "loading-circle", style: { width: "60px", height: "60px", border: "10px solid #f3f3f3", borderTop: "10px solid #009b4bff", borderRadius: "50%" } }), Y = () => /* @__PURE__ */ f("div", { style: { padding: "20px", fontSize: "25px", color: "#333", fontFamily: "system-ui, sans-serif" }, children: "Please wait..." }), U = T(void 0), X = ({ children: o, loadingComponent: e, animationType: n = M.FadeInOut, animationDuration: c, wrapperStyle: u, wrapperClassName: r, wrapperId: d, animationWrapperStyle: g, animationWrapperClassName: l, animationWrapperId: a }) => {
|
|
41
|
+
e = e || (n === M.Spin ? H : Y);
|
|
42
|
+
const [w, h] = E(0), [N, O] = E(null), m = N ?? w > 0, P = (p) => O(p), B = () => h((p) => p + 1), F = () => h((p) => Math.max(0, p - 1)), L = y(null);
|
|
43
|
+
R(() => {
|
|
44
|
+
C.emit("change", { isLoading: m }), C.emit(m ? "start" : "stop", null), m ? (L.current?.showModal(), document.body.setAttribute("inert", "")) : m || document.body.removeAttribute("inert");
|
|
45
|
+
}, [w]), R(() => () => {
|
|
46
|
+
h(0), C.removeAllListeners();
|
|
47
|
+
}, []);
|
|
48
|
+
const b = d || "loading-dialog";
|
|
49
|
+
return /* @__PURE__ */ S(U.Provider, { value: { get isLoading() {
|
|
50
|
+
return m;
|
|
51
|
+
}, startLoading: B, stopLoading: F, loadingEventTarget: C, overrideLoading: P }, children: [
|
|
52
|
+
o,
|
|
53
|
+
m && D(
|
|
54
|
+
/* @__PURE__ */ S($, { children: [
|
|
55
|
+
/* @__PURE__ */ f("style", { children: `
|
|
56
|
+
dialog#${b}[open] {
|
|
57
|
+
display: flex !important;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
align-items: center;
|
|
60
|
+
width: 100vw;
|
|
61
|
+
height: 100vh;
|
|
62
|
+
max-width: 100%;
|
|
63
|
+
max-height: 100%;
|
|
64
|
+
}
|
|
65
|
+
@keyframes spin {
|
|
66
|
+
0% { transform: rotate(0deg); }
|
|
67
|
+
100% { transform: rotate(360deg); }
|
|
68
|
+
}
|
|
69
|
+
@keyframes fadeInOut {
|
|
70
|
+
0%, 100% { opacity: 0.2; }
|
|
71
|
+
50% { opacity: 1; }
|
|
72
|
+
}
|
|
73
|
+
body:has(dialog#${b}[open]) {
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
}
|
|
76
|
+
body {
|
|
77
|
+
scrollbar-gutter: stable;
|
|
78
|
+
}
|
|
79
|
+
` }),
|
|
80
|
+
/* @__PURE__ */ f(
|
|
81
|
+
"dialog",
|
|
82
|
+
{
|
|
83
|
+
ref: L,
|
|
84
|
+
style: {
|
|
85
|
+
border: "none",
|
|
86
|
+
padding: 0,
|
|
87
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
88
|
+
backdropFilter: "blur(2px)",
|
|
89
|
+
...u
|
|
90
|
+
},
|
|
91
|
+
className: r,
|
|
92
|
+
id: b,
|
|
93
|
+
children: /* @__PURE__ */ f(z, { animationType: n, animationDuration: c, style: g, className: l, id: a, children: I.isValidElement(e) ? e : I.createElement(e) })
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
] }),
|
|
97
|
+
document.body
|
|
98
|
+
)
|
|
99
|
+
] });
|
|
100
|
+
}, V = () => {
|
|
101
|
+
const o = k(U);
|
|
102
|
+
if (!o) throw new Error("useLoading must be used within a LoadingProvider");
|
|
103
|
+
const e = y(0), { startLoading: n, stopLoading: c, isLoading: u, ...r } = o, d = () => {
|
|
104
|
+
n(), e.current += 1;
|
|
105
|
+
}, g = () => {
|
|
106
|
+
e.current > 0 && (c(), e.current -= 1);
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
startLoading: d,
|
|
110
|
+
stopLoading: g,
|
|
111
|
+
get isLocalLoading() {
|
|
112
|
+
return e.current > 0;
|
|
113
|
+
},
|
|
114
|
+
...r,
|
|
115
|
+
asyncUseLoading: async (a) => {
|
|
116
|
+
d();
|
|
117
|
+
try {
|
|
118
|
+
return await a;
|
|
119
|
+
} finally {
|
|
120
|
+
g();
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
isLoading: u
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
function Z({ isLoading: o = !1 }) {
|
|
127
|
+
const e = V();
|
|
128
|
+
return R(() => (o ? e.startLoading() : e.stopLoading(), () => {
|
|
129
|
+
o && e.stopLoading();
|
|
130
|
+
}), [o]), null;
|
|
131
|
+
}
|
|
132
|
+
const A = T(void 0), x = {
|
|
133
|
+
STACKED: 0,
|
|
134
|
+
CURRENT_ONLY: 1,
|
|
135
|
+
CURRENT_HIDDEN_STACK: 2
|
|
136
|
+
};
|
|
137
|
+
function ee({ children: o, wrapperId: e, renderMode: n = x.STACKED, wrapperStyle: c }) {
|
|
138
|
+
const u = y(null), r = y(/* @__PURE__ */ new Map()), [d, g] = E(r.current), l = Array.from(d.values()), a = Array.from(d.keys()), w = y(/* @__PURE__ */ new Map()), [h, N] = E(void 0), O = (t, s = Math.random().toString(36).substring(2, 6), i = !1) => {
|
|
139
|
+
if (a.indexOf(s) !== -1)
|
|
140
|
+
return console.warn(`Modal with id ${s} already exists. Choose a different id.`), s;
|
|
141
|
+
let _ = [t, i];
|
|
142
|
+
return r.current = new Map(r.current), r.current.set(s, _), g(new Map(r.current)), s;
|
|
143
|
+
}, m = (t) => {
|
|
144
|
+
let s = "";
|
|
145
|
+
if (typeof t != "string") {
|
|
146
|
+
for (let [i, v] of r.current.entries())
|
|
147
|
+
if (v[0] === t) {
|
|
148
|
+
s = i;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
} else typeof t == "string" && (s = t);
|
|
152
|
+
return r.current.has(s) ? (r.current = new Map(r.current), r.current.delete(s), g(new Map(r.current)), !0) : !1;
|
|
153
|
+
}, P = (t, s) => {
|
|
154
|
+
if (r.current.has(t)) {
|
|
155
|
+
let i = r.current.get(t);
|
|
156
|
+
if (i[1] === !1) {
|
|
157
|
+
console.warn(`Modal with id ${t} is dynamic. Cannot update content.`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
i[0] = s, r.current.set(t, i), g(new Map(r.current));
|
|
161
|
+
}
|
|
162
|
+
}, B = (t) => {
|
|
163
|
+
if (!d.has(t)) return !1;
|
|
164
|
+
let s = r.current.get(t);
|
|
165
|
+
return r.current.delete(t), r.current.set(t, s), g(new Map(r.current)), !0;
|
|
166
|
+
}, F = (t) => a.indexOf(t), L = (t) => w.current.get(t);
|
|
167
|
+
R(() => {
|
|
168
|
+
const t = a[a.length - 1];
|
|
169
|
+
t !== void 0 ? (u.current?.showModal(), document.body.setAttribute("inert", "")) : t === void 0 && (u.current?.close(), document.body.removeAttribute("inert")), N(t);
|
|
170
|
+
}, [d]);
|
|
171
|
+
const b = e || "base-modal-wrapper", p = K((t, s) => {
|
|
172
|
+
t ? w.current.set(s, t) : w.current.delete(s);
|
|
173
|
+
}, []), W = () => {
|
|
174
|
+
switch (n) {
|
|
175
|
+
case x.STACKED:
|
|
176
|
+
return l.map(([t, s], i) => /* @__PURE__ */ f(
|
|
177
|
+
"div",
|
|
178
|
+
{
|
|
179
|
+
ref: (v) => p(v, a[i]),
|
|
180
|
+
className: "modal-window",
|
|
181
|
+
id: a[i],
|
|
182
|
+
style: { display: "block", zIndex: a[i] === h ? 1e3 : 100 },
|
|
183
|
+
...h !== a[i] ? { inert: "" } : {},
|
|
184
|
+
children: s ? null : t
|
|
185
|
+
},
|
|
186
|
+
a[i]
|
|
187
|
+
));
|
|
188
|
+
case x.CURRENT_ONLY:
|
|
189
|
+
return l.length > 0 ? /* @__PURE__ */ f(
|
|
190
|
+
"div",
|
|
191
|
+
{
|
|
192
|
+
id: a[l.length - 1],
|
|
193
|
+
ref: (t) => p(t, a[l.length - 1]),
|
|
194
|
+
className: "modal-window",
|
|
195
|
+
style: { display: "block" },
|
|
196
|
+
children: l[l.length - 1][1] ? null : l[l.length - 1][0]
|
|
197
|
+
},
|
|
198
|
+
a[l.length - 1]
|
|
199
|
+
) : null;
|
|
200
|
+
case x.CURRENT_HIDDEN_STACK:
|
|
201
|
+
return l.length > 0 ? l.map(([t, s], i) => /* @__PURE__ */ f(
|
|
202
|
+
"div",
|
|
203
|
+
{
|
|
204
|
+
ref: (v) => p(v, a[i]),
|
|
205
|
+
id: a[i],
|
|
206
|
+
className: "modal-window",
|
|
207
|
+
style: {
|
|
208
|
+
display: h === a[i] ? "block" : "none"
|
|
209
|
+
},
|
|
210
|
+
...h !== a[i] ? { inert: "" } : {},
|
|
211
|
+
children: s ? null : t
|
|
212
|
+
},
|
|
213
|
+
a[i]
|
|
214
|
+
)) : null;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
return /* @__PURE__ */ S(A.Provider, { value: { modalCount: 0, get renderMode() {
|
|
218
|
+
return n;
|
|
219
|
+
}, pushModal: O, popModal: m, currentModalId: h, updateModalContent: P, getModalWindowRef: L, focusModal: B, getModalOrderIndex: F }, children: [
|
|
220
|
+
o,
|
|
221
|
+
a.length === 0 ? null : D(
|
|
222
|
+
/* @__PURE__ */ S($, { children: [
|
|
223
|
+
/* @__PURE__ */ f("style", { children: `
|
|
224
|
+
dialog#${b}[open] {
|
|
225
|
+
display: flex !important;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
align-items: center;
|
|
228
|
+
width: 100vw;
|
|
229
|
+
height: 100vh;
|
|
230
|
+
max-width: 100%;
|
|
231
|
+
max-height: 100%;
|
|
232
|
+
}
|
|
233
|
+
body:has(dialog#${b}[open]) {
|
|
234
|
+
overflow: hidden;
|
|
235
|
+
}
|
|
236
|
+
body {
|
|
237
|
+
scrollbar-gutter: stable;
|
|
238
|
+
}
|
|
239
|
+
.modal-wrapper{
|
|
240
|
+
border: none;
|
|
241
|
+
padding: 0;
|
|
242
|
+
background: unset;
|
|
243
|
+
}
|
|
244
|
+
.modal-window {
|
|
245
|
+
position: absolute;
|
|
246
|
+
width: 100%;
|
|
247
|
+
height: 100%;
|
|
248
|
+
display: none;
|
|
249
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
250
|
+
backdrop-filter: blur(2px);
|
|
251
|
+
}
|
|
252
|
+
` }),
|
|
253
|
+
/* @__PURE__ */ f(
|
|
254
|
+
"dialog",
|
|
255
|
+
{
|
|
256
|
+
className: "modal-wrapper",
|
|
257
|
+
ref: u,
|
|
258
|
+
id: b,
|
|
259
|
+
style: c,
|
|
260
|
+
children: W()
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
] }),
|
|
264
|
+
document.body
|
|
265
|
+
)
|
|
266
|
+
] });
|
|
267
|
+
}
|
|
268
|
+
function te() {
|
|
269
|
+
const o = k(A);
|
|
270
|
+
if (!o) throw new Error("useBaseModal must be used within a BaseModalProvider");
|
|
271
|
+
return o;
|
|
272
|
+
}
|
|
273
|
+
function ne(o = Math.random().toString(36).substring(2, 6)) {
|
|
274
|
+
const e = k(A);
|
|
275
|
+
if (!e) throw new Error("useBaseModal must be used within a BaseModalProvider");
|
|
276
|
+
let n = y(o);
|
|
277
|
+
const c = (d) => (e.pushModal(d, n.current), u), u = () => e.popModal(n.current), r = (d) => {
|
|
278
|
+
e.updateModalContent(n.current, d);
|
|
279
|
+
};
|
|
280
|
+
return [c, u, n.current, e.currentModalId === n.current, r];
|
|
281
|
+
}
|
|
282
|
+
function re(o = Math.random().toString(36).substring(2, 6)) {
|
|
283
|
+
const e = k(A);
|
|
284
|
+
if (!e) throw new Error("useBaseModal must be used within a BaseModalProvider");
|
|
285
|
+
let n = y(o);
|
|
286
|
+
const c = e.currentModalId === n.current;
|
|
287
|
+
return [(l) => e.getModalWindowRef(n.current) ? D(
|
|
288
|
+
l,
|
|
289
|
+
e.getModalWindowRef(n.current)
|
|
290
|
+
) : null, () => {
|
|
291
|
+
e.pushModal(null, n.current, !0)[1];
|
|
292
|
+
}, () => {
|
|
293
|
+
e.popModal(n.current);
|
|
294
|
+
}, () => {
|
|
295
|
+
e.focusModal(n.current);
|
|
296
|
+
}, n.current, c];
|
|
297
|
+
}
|
|
298
|
+
export {
|
|
299
|
+
M as AnimationType,
|
|
300
|
+
ee as BaseModalProvider,
|
|
301
|
+
Q as Button,
|
|
302
|
+
Z as Loading,
|
|
303
|
+
X as LoadingProvider,
|
|
304
|
+
x as RenderMode,
|
|
305
|
+
te as useBaseModal,
|
|
306
|
+
re as useDynamicModal,
|
|
307
|
+
V as useLoading,
|
|
308
|
+
ne as useStaticModal
|
|
309
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "roks-rjsc",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A React component library",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "vite build",
|
|
14
|
+
"prepare": "npm run build",
|
|
15
|
+
"dev": "vite",
|
|
16
|
+
"preview": "vite preview",
|
|
17
|
+
"test": "vitest"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^18.0.0",
|
|
21
|
+
"react-dom": "^18.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@testing-library/jest-dom": "^6.0.0",
|
|
25
|
+
"@testing-library/react": "^14.0.0",
|
|
26
|
+
"@types/jest": "^30.0.0",
|
|
27
|
+
"@types/react": "^18.0.0",
|
|
28
|
+
"@types/react-dom": "^18.0.0",
|
|
29
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
30
|
+
"jsdom": "^27.4.0",
|
|
31
|
+
"typescript": "^5.0.0",
|
|
32
|
+
"vite": "^7.1.9",
|
|
33
|
+
"vite-plugin-dts": "^4.5.4",
|
|
34
|
+
"vitest": "^1.0.0"
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": false,
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/rokku-x/roks-rjsc.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/rokku-x/roks-rjsc/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/rokku-x/roks-rjsc#readme",
|
|
48
|
+
"exports": {
|
|
49
|
+
".": {
|
|
50
|
+
"types": "./dist/index.d.ts",
|
|
51
|
+
"import": "./dist/index.esm.js",
|
|
52
|
+
"require": "./dist/index.cjs.js"
|
|
53
|
+
},
|
|
54
|
+
"./package.json": "./package.json"
|
|
55
|
+
},
|
|
56
|
+
"keywords": [
|
|
57
|
+
"react",
|
|
58
|
+
"component",
|
|
59
|
+
"library"
|
|
60
|
+
],
|
|
61
|
+
"author": "rokku",
|
|
62
|
+
"license": "MIT"
|
|
63
|
+
}
|