@promise-inc/ui-states 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 +161 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +98 -0
- package/dist/index.d.ts +98 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Promise Codes
|
|
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,161 @@
|
|
|
1
|
+
# @promise-inc/ui-states
|
|
2
|
+
|
|
3
|
+
Auto-generated skeleton loading states from real DOM — zero config React component.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Auto-skeleton**: Generates skeleton loading states based on your actual component DOM structure
|
|
8
|
+
- **Zero config**: Just wrap your component — no manual skeleton building
|
|
9
|
+
- **TanStack Query support**: Pass query objects directly
|
|
10
|
+
- **Smart caching**: Cache skeleton trees in sessionStorage with viewport-aware invalidation
|
|
11
|
+
- **Dark mode**: Built-in dark mode support via Tailwind `dark:` variants
|
|
12
|
+
- **Accessible**: Proper `aria-busy`, `role="status"`, and `aria-label` attributes
|
|
13
|
+
- **Tree-shakeable**: Import only what you need
|
|
14
|
+
- **Lightweight**: No dependencies besides React
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @promise-inc/ui-states
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Peer dependencies**: `react >= 18`, `react-dom >= 18`
|
|
23
|
+
|
|
24
|
+
**Note**: This library outputs Tailwind CSS classes (`animate-pulse`, `bg-neutral-200/60`, `rounded-*`, `flex`, `grid`, etc). Make sure your Tailwind config scans this package:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
// tailwind.config.js
|
|
28
|
+
content: [
|
|
29
|
+
// ...your paths
|
|
30
|
+
'./node_modules/@promise-inc/ui-states/dist/**/*.{js,cjs}',
|
|
31
|
+
]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { UIStates } from '@promise-inc/ui-states';
|
|
38
|
+
|
|
39
|
+
function ProductsPage() {
|
|
40
|
+
const [products, setProducts] = useState(null);
|
|
41
|
+
const [loading, setLoading] = useState(true);
|
|
42
|
+
const [error, setError] = useState(null);
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
fetchProducts()
|
|
46
|
+
.then(setProducts)
|
|
47
|
+
.catch(setError)
|
|
48
|
+
.finally(() => setLoading(false));
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<UIStates data={products} loading={loading} error={error}>
|
|
53
|
+
<ProductList products={products} />
|
|
54
|
+
</UIStates>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage with TanStack Query
|
|
60
|
+
|
|
61
|
+
```tsx
|
|
62
|
+
import { UIStates } from '@promise-inc/ui-states';
|
|
63
|
+
import { useQuery } from '@tanstack/react-query';
|
|
64
|
+
|
|
65
|
+
function ProductsPage() {
|
|
66
|
+
const query = useQuery({ queryKey: ['products'], queryFn: fetchProducts });
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<UIStates query={query}>
|
|
70
|
+
<ProductList products={query.data} />
|
|
71
|
+
</UIStates>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Custom Empty and Error States
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<UIStates
|
|
80
|
+
data={data}
|
|
81
|
+
loading={isLoading}
|
|
82
|
+
error={error}
|
|
83
|
+
emptyState={<MyCustomEmptyView />}
|
|
84
|
+
errorState={(error, retry) => (
|
|
85
|
+
<MyCustomError error={error} onRetry={retry} />
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
<ProductList />
|
|
89
|
+
</UIStates>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Caching
|
|
93
|
+
|
|
94
|
+
Enable skeleton caching to avoid re-measuring the DOM on subsequent loads:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<UIStates
|
|
98
|
+
query={query}
|
|
99
|
+
enableCache
|
|
100
|
+
cacheKey="products-page"
|
|
101
|
+
>
|
|
102
|
+
<ProductList products={query.data} />
|
|
103
|
+
</UIStates>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Cache is stored in `sessionStorage` and auto-invalidates when:
|
|
107
|
+
- TTL expires (5 minutes)
|
|
108
|
+
- Viewport size changes significantly (> 50px difference)
|
|
109
|
+
|
|
110
|
+
## API Reference
|
|
111
|
+
|
|
112
|
+
### `<UIStates>` Props
|
|
113
|
+
|
|
114
|
+
| Prop | Type | Description |
|
|
115
|
+
|------|------|-------------|
|
|
116
|
+
| `children` | `ReactNode` | The content to render on success |
|
|
117
|
+
| `data` | `unknown` | Data to check for empty state |
|
|
118
|
+
| `loading` | `boolean` | Manual loading flag |
|
|
119
|
+
| `error` | `unknown` | Manual error value |
|
|
120
|
+
| `query` | `QueryLike` | TanStack Query result object |
|
|
121
|
+
| `emptyState` | `ReactNode` | Custom empty state component |
|
|
122
|
+
| `errorState` | `ReactNode \| (error, retry?) => ReactNode` | Custom error state |
|
|
123
|
+
| `emptyCheck` | `(data: unknown) => boolean` | Custom empty data checker |
|
|
124
|
+
| `enableCache` | `boolean` | Enable skeleton caching (default: `false`) |
|
|
125
|
+
| `cacheKey` | `string` | Cache key for sessionStorage |
|
|
126
|
+
| `className` | `string` | Class for the wrapper div |
|
|
127
|
+
| `skeletonClassName` | `string` | Class for the skeleton container |
|
|
128
|
+
|
|
129
|
+
### Exported Hooks
|
|
130
|
+
|
|
131
|
+
| Hook | Description |
|
|
132
|
+
|------|-------------|
|
|
133
|
+
| `useUIState` | Resolves current UI state from props or query |
|
|
134
|
+
| `useSkeletonTree` | Coordinates DOM measurement and skeleton generation |
|
|
135
|
+
| `useResizeObserver` | ResizeObserver with debounce |
|
|
136
|
+
|
|
137
|
+
### Exported Components
|
|
138
|
+
|
|
139
|
+
| Component | Description |
|
|
140
|
+
|-----------|-------------|
|
|
141
|
+
| `UIStates` | Main orchestrator component |
|
|
142
|
+
| `SkeletonRenderer` | Renders a skeleton tree |
|
|
143
|
+
| `ErrorRenderer` | Default error state |
|
|
144
|
+
| `EmptyRenderer` | Default empty state |
|
|
145
|
+
| `FallbackSkeleton` | Generic fallback skeleton |
|
|
146
|
+
|
|
147
|
+
## How It Works
|
|
148
|
+
|
|
149
|
+
1. When `loading` is active, children are rendered with `visibility: hidden` and `position: absolute` for DOM measurement
|
|
150
|
+
2. The **DOM Walker** recursively traverses the hidden tree, measuring each element's bounding rect and computed styles
|
|
151
|
+
3. The **Skeleton Generator** maps the measured tree into `SkeletonNode[]` with dimensions, layout info (flex/grid), gaps, and border-radius
|
|
152
|
+
4. The **Skeleton Renderer** renders the tree as `div` elements with Tailwind classes (`animate-pulse`, `bg-neutral-200/60`)
|
|
153
|
+
5. When loading ends, the skeleton is removed and real children are shown
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
Developed by [Promise Inc.](https://promise.codes)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');function H(e,t){return t?t(e):!!(e==null||Array.isArray(e)&&e.length===0)}function b(e){let{data:t,loading:o,error:n,query:r,emptyCheck:s}=e;return react.useMemo(()=>r?r.isLoading??r.isPending??false?{state:"loading",error:null}:r.isError?{state:"error",error:r.error,retry:r.refetch}:H(r.data,s)?{state:"empty",error:null}:{state:"success",error:null}:o?{state:"loading",error:null}:n?{state:"error",error:n}:H(t,s)?{state:"empty",error:null}:{state:"success",error:null},[t,o,n,r,s])}var M="ui-states:",P={"0px":"rounded-none","2px":"rounded-sm","4px":"rounded","6px":"rounded-md","8px":"rounded-lg","12px":"rounded-xl","16px":"rounded-2xl","24px":"rounded-3xl","9999px":"rounded-full"},U=new Set(["SCRIPT","STYLE","LINK","META","NOSCRIPT","BR","HR","WBR"]),_=new Set(["IMG","VIDEO","CANVAS","SVG","INPUT","TEXTAREA","SELECT","BUTTON","A","SPAN","P","H1","H2","H3","H4","H5","H6","LABEL"]);function G(e){if(U.has(e.tagName)||e instanceof HTMLElement&&e.hidden)return true;let t=window.getComputedStyle(e);return t.display==="none"||t.visibility==="hidden"||t.opacity==="0"}function W(e){return e.width<8||e.height<8}function E(e){let t=e.getBoundingClientRect();return {width:t.width,height:t.height,top:t.top,left:t.left}}function ee(e){let t=parseFloat(e);return Number.isNaN(t)?0:t}function te(e){if(!e||e==="0px")return "rounded-none";let o=e.split(" ")[0]??"0px",n=P[o];if(n)return n;let r=parseFloat(o);return Number.isNaN(r)?"rounded":r>=9999?"rounded-full":r>=24?"rounded-3xl":r>=16?"rounded-2xl":r>=12?"rounded-xl":r>=8?"rounded-lg":r>=6?"rounded-md":r>=4?"rounded":r>=2?"rounded-sm":"rounded-none"}function re(e){if(e.display!=="grid")return;let t=e.gridTemplateColumns;if(!t||t==="none")return;let o=t.split(/\s+/).filter(n=>n!=="none"&&n.length>0);return o.length>0?o.length:void 0}function ne(e){return e.includes("flex")?"flex":e.includes("grid")?"grid":e.includes("inline-block")?"inline-block":e.includes("inline")?"inline":"block"}function R(e){let t=window.getComputedStyle(e),o=ne(t.display);return {display:o,flexDirection:o==="flex"?t.flexDirection==="column"?"column":"row":void 0,gridCols:re(t),gap:ee(t.gap),borderRadius:te(t.borderRadius)}}var w=0;function y(){return w+=1,`sk-${w}`}function ie(e){return _.has(e.tagName)?true:e.childNodes.length>0&&Array.from(e.childNodes).every(o=>o.nodeType===Node.TEXT_NODE)?(e.textContent?.trim()??"").length>0:e.children.length===0}function z(e,t,o){if(t>o.maxDepth||G(e))return null;let n=E(e);if(W(n))return null;let r=R(e);if(ie(e))return {id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,gap:0,isLeaf:true,children:[],tagName:e.tagName};let i=[];for(let u of Array.from(e.children)){let l=z(u,t+1,o);l&&i.push(l);}return i.length===0?{id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,gap:0,isLeaf:true,children:[],tagName:e.tagName}:{id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,flexDirection:r.flexDirection,gridCols:r.gridCols,gap:r.gap,isLeaf:false,children:i,tagName:e.tagName}}function F(e){w=0;let t={maxDepth:10},o=[];for(let n of Array.from(e.children)){let r=z(n,0,t);r&&o.push(r);}if(o.length===0){let n=E(e),r=R(e);return [{id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,gap:0,isLeaf:true,children:[],tagName:e.tagName}]}return o}function S(e){return `${M}${e}`}function V(e){try{let t=sessionStorage.getItem(S(e));if(!t)return null;let o=JSON.parse(t);if(Date.now()-o.timestamp>3e5)return sessionStorage.removeItem(S(e)),null;let r=Math.abs(window.innerWidth-o.viewportWidth),s=Math.abs(window.innerHeight-o.viewportHeight);return r>50||s>50?(sessionStorage.removeItem(S(e)),null):o.tree}catch{return null}}function X(e,t){try{let o={tree:t,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,timestamp:Date.now()};sessionStorage.setItem(S(e),JSON.stringify(o));}catch{}}function v(e){let[t,o]=react.useState(null),n=react.useRef(null),r=react.useCallback(s=>{n.current&&clearTimeout(n.current),n.current=setTimeout(()=>{let i=s[0];i&&o({width:i.contentRect.width,height:i.contentRect.height});},200);},[]);return react.useEffect(()=>{let s=e.current;if(!s)return;let i=new ResizeObserver(r);return i.observe(s),()=>{i.disconnect(),n.current&&clearTimeout(n.current);}},[e,r]),t}function I(e){let{isLoading:t,enableCache:o,cacheKey:n}=e,r=react.useRef(null),[s,i]=react.useState(()=>o&&n?V(n):null),[u,l]=react.useState(s!==null),p=v(r),c=react.useCallback(()=>{let f=r.current;if(!f)return;let h=F(f);i(h),l(true),o&&n&&X(n,h);},[o,n]);return react.useEffect(()=>{if(!t||u)return;let f=requestAnimationFrame(()=>{c();});return ()=>cancelAnimationFrame(f)},[t,u,c]),react.useEffect(()=>{t&&p&&c();},[t,p,c]),react.useEffect(()=>{t||l(false);},[t]),{tree:s,measureRef:r,hasMeasured:u}}function a(...e){return e.filter(Boolean).join(" ")}function me(e){if(e.isLeaf)return "";let t=[];return e.display==="flex"?(t.push("flex"),e.flexDirection==="column"&&t.push("flex-col")):e.display==="grid"&&e.gridCols?(t.push("grid"),t.push(`grid-cols-${e.gridCols}`)):e.display==="inline"||e.display==="inline-block"?t.push("inline-flex"):t.push("flex flex-col"),a(...t)}function pe(e){return e.isLeaf?a("animate-pulse","bg-neutral-200/60 dark:bg-neutral-700/60",e.borderRadius):""}function Z(e){let t={width:e.width,height:e.isLeaf?e.height:"auto"};e.gap>0&&!e.isLeaf&&(t.gap=e.gap);let o=me(e),n=pe(e),r=a(o,n),s=e.isLeaf?[]:e.children.map(i=>Z(i));return {node:e,className:r,style:t,children:s}}function j(e){return e.map(t=>Z(t))}function $({skeleton:e}){return jsxRuntime.jsx("div",{className:e.className,style:e.style,"aria-hidden":"true",children:e.children.map(t=>jsxRuntime.jsx($,{skeleton:t},t.node.id))})}function C({tree:e,className:t}){let o=j(e);return jsxRuntime.jsx("div",{className:a("relative",t),role:"status","aria-busy":"true","aria-label":"Loading content",children:o.map(n=>jsxRuntime.jsx($,{skeleton:n},n.node.id))})}function ge(e){return e instanceof Error?e.message:typeof e=="string"?e:"An unexpected error occurred"}function L({error:e,retry:t,className:o}){return jsxRuntime.jsxs("div",{className:a("flex flex-col items-center justify-center gap-3 p-6 text-center",o),role:"alert",children:[jsxRuntime.jsx("div",{className:"flex h-12 w-12 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30",children:jsxRuntime.jsx("svg",{className:"h-6 w-6 text-red-600 dark:text-red-400",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor","aria-hidden":"true",children:jsxRuntime.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"})})}),jsxRuntime.jsx("p",{className:"text-sm text-neutral-600 dark:text-neutral-400",children:ge(e)}),t&&jsxRuntime.jsx("button",{type:"button",onClick:t,className:"rounded-md bg-neutral-100 px-3 py-1.5 text-sm font-medium text-neutral-700 transition-colors hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700",children:"Try again"})]})}function A({className:e}){return jsxRuntime.jsxs("div",{className:a("flex flex-col items-center justify-center gap-3 p-6 text-center",e),children:[jsxRuntime.jsx("div",{className:"flex h-12 w-12 items-center justify-center rounded-full bg-neutral-100 dark:bg-neutral-800",children:jsxRuntime.jsx("svg",{className:"h-6 w-6 text-neutral-400 dark:text-neutral-500",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor","aria-hidden":"true",children:jsxRuntime.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M20.25 7.5l-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5m6 4.125l2.25 2.25m0 0l2.25 2.25M12 13.875l2.25-2.25M12 13.875l-2.25 2.25M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z"})})}),jsxRuntime.jsx("p",{className:"text-sm text-neutral-500 dark:text-neutral-400",children:"No data found"})]})}function O({className:e}){return jsxRuntime.jsxs("div",{className:a("flex flex-col gap-4 w-full animate-pulse",e),children:[jsxRuntime.jsx("div",{className:"h-6 w-3/4 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxRuntime.jsx("div",{className:"h-4 w-full rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxRuntime.jsx("div",{className:"h-4 w-5/6 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxRuntime.jsxs("div",{className:"flex gap-3",children:[jsxRuntime.jsx("div",{className:"h-10 w-10 rounded-full bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxRuntime.jsxs("div",{className:"flex flex-col gap-2 flex-1",children:[jsxRuntime.jsx("div",{className:"h-4 w-1/2 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxRuntime.jsx("div",{className:"h-4 w-1/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"})]})]}),jsxRuntime.jsx("div",{className:"h-4 w-2/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"})]})}function Se(e){let{children:t,emptyState:o,errorState:n,enableCache:r=false,cacheKey:s,className:i,skeletonClassName:u}=e,{state:l,error:p,retry:c}=b(e),{tree:f,measureRef:h,hasMeasured:q}=I({isLoading:l==="loading",enableCache:r,cacheKey:s});return l==="error"?n?typeof n=="function"?jsxRuntime.jsx(jsxRuntime.Fragment,{children:n(p,c)}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:n}):jsxRuntime.jsx(L,{error:p,retry:c,className:i}):l==="empty"?o?jsxRuntime.jsx(jsxRuntime.Fragment,{children:o}):jsxRuntime.jsx(A,{className:i}):l==="loading"?jsxRuntime.jsxs("div",{className:a("relative",i),children:[jsxRuntime.jsx("div",{ref:h,"aria-hidden":"true",style:{visibility:"hidden",position:"absolute",top:0,left:0,right:0,pointerEvents:"none",overflow:"hidden",height:0},children:t}),q&&f?jsxRuntime.jsx(C,{tree:f,className:u}):jsxRuntime.jsx(O,{className:u})]}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:t})}exports.EmptyRenderer=A;exports.ErrorRenderer=L;exports.FallbackSkeleton=O;exports.SkeletonRenderer=C;exports.UIStates=Se;exports.useResizeObserver=v;exports.useSkeletonTree=I;exports.useUIState=b;//# sourceMappingURL=index.cjs.map
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-ui-state.ts","../src/constants.ts","../src/utils/element-filters.ts","../src/core/layout-detector.ts","../src/core/dom-walker.ts","../src/utils/storage.ts","../src/hooks/use-resize-observer.ts","../src/hooks/use-skeleton-tree.ts","../src/utils/cn.ts","../src/core/skeleton-generator.ts","../src/renderers/skeleton-renderer.tsx","../src/renderers/error-renderer.tsx","../src/renderers/empty-renderer.tsx","../src/utils/fallback-skeleton.tsx","../src/components/ui-states.tsx"],"names":["isEmptyData","data","emptyCheck","useUIState","props","loading","error","query","useMemo","STORAGE_PREFIX","RADIUS_MAP","IGNORED_TAGS","LEAF_TAGS","shouldIgnoreElement","element","style","isElementTooSmall","rect","getElementRect","domRect","parseGap","gapValue","parsed","normalizeRadius","computed","first","mapped","px","detectGridCols","template","cols","part","normalizeDisplay","display","detectLayout","nodeCounter","generateId","isLeafElement","node","walkElement","depth","options","layout","children","child","childNode","walkDom","root","results","getStorageKey","key","getCachedTree","raw","entry","widthDiff","heightDiff","setCachedTree","tree","useResizeObserver","ref","size","setSize","useState","timeoutRef","useRef","handleResize","useCallback","entries","useEffect","observer","useSkeletonTree","isLoading","enableCache","cacheKey","measureRef","setTree","hasMeasured","setHasMeasured","measure","newTree","frame","cn","classes","getLayoutClasses","getSkeletonClasses","generateNode","layoutClass","skeletonClass","className","generateSkeletonTree","nodes","SkeletonNodeView","skeleton","jsx","SkeletonRenderer","generated","getErrorMessage","ErrorRenderer","retry","jsxs","EmptyRenderer","FallbackSkeleton","UIStates","emptyState","errorState","skeletonClassName","state","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useMemo } from \"react\";\nimport type { UIState, UIStatesProps } from \"../types\";\n\ninterface UIStateResult {\n readonly state: UIState;\n readonly error: unknown;\n readonly retry?: () => void;\n}\n\nfunction isEmptyData(data: unknown, emptyCheck?: (data: unknown) => boolean): boolean {\n if (emptyCheck) return emptyCheck(data);\n if (data === null || data === undefined) return true;\n if (Array.isArray(data) && data.length === 0) return true;\n return false;\n}\n\nexport function useUIState(props: UIStatesProps): UIStateResult {\n const { data, loading, error, query, emptyCheck } = props;\n\n return useMemo(() => {\n if (query) {\n const isLoading = query.isLoading ?? query.isPending ?? false;\n if (isLoading) {\n return { state: \"loading\" as const, error: null };\n }\n if (query.isError) {\n return { state: \"error\" as const, error: query.error, retry: query.refetch };\n }\n if (isEmptyData(query.data, emptyCheck)) {\n return { state: \"empty\" as const, error: null };\n }\n return { state: \"success\" as const, error: null };\n }\n\n if (loading) {\n return { state: \"loading\" as const, error: null };\n }\n if (error) {\n return { state: \"error\" as const, error };\n }\n if (isEmptyData(data, emptyCheck)) {\n return { state: \"empty\" as const, error: null };\n }\n return { state: \"success\" as const, error: null };\n }, [data, loading, error, query, emptyCheck]);\n}\n","export const MIN_WIDTH = 8;\nexport const MIN_HEIGHT = 8;\nexport const MAX_DEPTH = 10;\nexport const CACHE_TTL = 5 * 60 * 1000;\nexport const RESIZE_DEBOUNCE_MS = 200;\nexport const VIEWPORT_TOLERANCE = 50;\nexport const STORAGE_PREFIX = \"ui-states:\";\n\nexport const RADIUS_MAP = {\n \"0px\": \"rounded-none\",\n \"2px\": \"rounded-sm\",\n \"4px\": \"rounded\",\n \"6px\": \"rounded-md\",\n \"8px\": \"rounded-lg\",\n \"12px\": \"rounded-xl\",\n \"16px\": \"rounded-2xl\",\n \"24px\": \"rounded-3xl\",\n \"9999px\": \"rounded-full\",\n} as const;\n\nexport const IGNORED_TAGS = new Set([\n \"SCRIPT\",\n \"STYLE\",\n \"LINK\",\n \"META\",\n \"NOSCRIPT\",\n \"BR\",\n \"HR\",\n \"WBR\",\n]);\n\nexport const LEAF_TAGS = new Set([\n \"IMG\",\n \"VIDEO\",\n \"CANVAS\",\n \"SVG\",\n \"INPUT\",\n \"TEXTAREA\",\n \"SELECT\",\n \"BUTTON\",\n \"A\",\n \"SPAN\",\n \"P\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n \"LABEL\",\n]);\n","import { IGNORED_TAGS, MIN_WIDTH, MIN_HEIGHT } from \"../constants\";\nimport type { ElementRect } from \"../types\";\n\nexport function shouldIgnoreElement(element: Element): boolean {\n if (IGNORED_TAGS.has(element.tagName)) {\n return true;\n }\n\n if (element instanceof HTMLElement && element.hidden) {\n return true;\n }\n\n const style = window.getComputedStyle(element);\n if (style.display === \"none\" || style.visibility === \"hidden\" || style.opacity === \"0\") {\n return true;\n }\n\n return false;\n}\n\nexport function isElementTooSmall(rect: ElementRect): boolean {\n return rect.width < MIN_WIDTH || rect.height < MIN_HEIGHT;\n}\n\nexport function getElementRect(element: Element): ElementRect {\n const domRect = element.getBoundingClientRect();\n return {\n width: domRect.width,\n height: domRect.height,\n top: domRect.top,\n left: domRect.left,\n };\n}\n","import { RADIUS_MAP } from \"../constants\";\nimport type { LayoutInfo, SkeletonNode } from \"../types\";\n\nfunction parseGap(gapValue: string): number {\n const parsed = parseFloat(gapValue);\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\nfunction normalizeRadius(computed: string): string {\n if (!computed || computed === \"0px\") return \"rounded-none\";\n\n const parts = computed.split(\" \");\n const first = parts[0] ?? \"0px\";\n\n const mapped = RADIUS_MAP[first as keyof typeof RADIUS_MAP];\n if (mapped) return mapped;\n\n const px = parseFloat(first);\n if (Number.isNaN(px)) return \"rounded\";\n\n if (px >= 9999) return \"rounded-full\";\n if (px >= 24) return \"rounded-3xl\";\n if (px >= 16) return \"rounded-2xl\";\n if (px >= 12) return \"rounded-xl\";\n if (px >= 8) return \"rounded-lg\";\n if (px >= 6) return \"rounded-md\";\n if (px >= 4) return \"rounded\";\n if (px >= 2) return \"rounded-sm\";\n return \"rounded-none\";\n}\n\nfunction detectGridCols(style: CSSStyleDeclaration): number | undefined {\n if (style.display !== \"grid\") return undefined;\n\n const template = style.gridTemplateColumns;\n if (!template || template === \"none\") return undefined;\n\n const cols = template.split(/\\s+/).filter((part) => part !== \"none\" && part.length > 0);\n return cols.length > 0 ? cols.length : undefined;\n}\n\nfunction normalizeDisplay(display: string): SkeletonNode[\"display\"] {\n if (display.includes(\"flex\")) return \"flex\";\n if (display.includes(\"grid\")) return \"grid\";\n if (display.includes(\"inline-block\")) return \"inline-block\";\n if (display.includes(\"inline\")) return \"inline\";\n return \"block\";\n}\n\nexport function detectLayout(element: Element): LayoutInfo {\n const style = window.getComputedStyle(element);\n const display = normalizeDisplay(style.display);\n\n return {\n display,\n flexDirection:\n display === \"flex\"\n ? (style.flexDirection as \"row\" | \"column\") === \"column\"\n ? \"column\"\n : \"row\"\n : undefined,\n gridCols: detectGridCols(style),\n gap: parseGap(style.gap),\n borderRadius: normalizeRadius(style.borderRadius),\n };\n}\n","import { MAX_DEPTH, LEAF_TAGS } from \"../constants\";\nimport type { DomWalkerOptions, SkeletonNode } from \"../types\";\nimport { shouldIgnoreElement, isElementTooSmall, getElementRect } from \"../utils/element-filters\";\nimport { detectLayout } from \"./layout-detector\";\n\nlet nodeCounter = 0;\n\nfunction generateId(): string {\n nodeCounter += 1;\n return `sk-${nodeCounter}`;\n}\n\nfunction isLeafElement(element: Element): boolean {\n if (LEAF_TAGS.has(element.tagName)) return true;\n\n const hasTextOnly =\n element.childNodes.length > 0 &&\n Array.from(element.childNodes).every((node) => node.nodeType === Node.TEXT_NODE);\n\n if (hasTextOnly) {\n const text = element.textContent?.trim() ?? \"\";\n return text.length > 0;\n }\n\n return element.children.length === 0;\n}\n\nfunction walkElement(\n element: Element,\n depth: number,\n options: DomWalkerOptions,\n): SkeletonNode | null {\n if (depth > options.maxDepth) return null;\n if (shouldIgnoreElement(element)) return null;\n\n const rect = getElementRect(element);\n if (isElementTooSmall(rect)) return null;\n\n const layout = detectLayout(element);\n const isLeaf = isLeafElement(element);\n\n if (isLeaf) {\n return {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n gap: 0,\n isLeaf: true,\n children: [],\n tagName: element.tagName,\n };\n }\n\n const children: SkeletonNode[] = [];\n for (const child of Array.from(element.children)) {\n const childNode = walkElement(child, depth + 1, options);\n if (childNode) {\n children.push(childNode);\n }\n }\n\n if (children.length === 0) {\n return {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n gap: 0,\n isLeaf: true,\n children: [],\n tagName: element.tagName,\n };\n }\n\n return {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n flexDirection: layout.flexDirection,\n gridCols: layout.gridCols,\n gap: layout.gap,\n isLeaf: false,\n children,\n tagName: element.tagName,\n };\n}\n\nexport function walkDom(root: Element): readonly SkeletonNode[] {\n nodeCounter = 0;\n\n const options: DomWalkerOptions = {\n maxDepth: MAX_DEPTH,\n minWidth: 8,\n minHeight: 8,\n };\n\n const results: SkeletonNode[] = [];\n\n for (const child of Array.from(root.children)) {\n const node = walkElement(child, 0, options);\n if (node) {\n results.push(node);\n }\n }\n\n if (results.length === 0) {\n const rect = getElementRect(root);\n const layout = detectLayout(root);\n return [\n {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n gap: 0,\n isLeaf: true,\n children: [],\n tagName: root.tagName,\n },\n ];\n }\n\n return results;\n}\n","import { CACHE_TTL, STORAGE_PREFIX, VIEWPORT_TOLERANCE } from \"../constants\";\nimport type { CacheEntry, SkeletonNode } from \"../types\";\n\nfunction getStorageKey(key: string): string {\n return `${STORAGE_PREFIX}${key}`;\n}\n\nexport function getCachedTree(key: string): readonly SkeletonNode[] | null {\n try {\n const raw = sessionStorage.getItem(getStorageKey(key));\n if (!raw) return null;\n\n const entry: CacheEntry = JSON.parse(raw);\n const now = Date.now();\n\n if (now - entry.timestamp > CACHE_TTL) {\n sessionStorage.removeItem(getStorageKey(key));\n return null;\n }\n\n const widthDiff = Math.abs(window.innerWidth - entry.viewportWidth);\n const heightDiff = Math.abs(window.innerHeight - entry.viewportHeight);\n if (widthDiff > VIEWPORT_TOLERANCE || heightDiff > VIEWPORT_TOLERANCE) {\n sessionStorage.removeItem(getStorageKey(key));\n return null;\n }\n\n return entry.tree;\n } catch {\n return null;\n }\n}\n\nexport function setCachedTree(key: string, tree: readonly SkeletonNode[]): void {\n try {\n const entry: CacheEntry = {\n tree,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n timestamp: Date.now(),\n };\n sessionStorage.setItem(getStorageKey(key), JSON.stringify(entry));\n } catch {\n /* empty */\n }\n}\n","import { useEffect, useRef, useCallback, useState } from \"react\";\nimport { RESIZE_DEBOUNCE_MS } from \"../constants\";\n\ninterface Size {\n readonly width: number;\n readonly height: number;\n}\n\nexport function useResizeObserver(\n ref: React.RefObject<Element>,\n): Size | null {\n const [size, setSize] = useState<Size | null>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const handleResize = useCallback((entries: ResizeObserverEntry[]) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n const entry = entries[0];\n if (entry) {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n }, RESIZE_DEBOUNCE_MS);\n }, []);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const observer = new ResizeObserver(handleResize);\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [ref, handleResize]);\n\n return size;\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { SkeletonNode } from \"../types\";\nimport { walkDom } from \"../core/dom-walker\";\nimport { getCachedTree, setCachedTree } from \"../utils/storage\";\nimport { useResizeObserver } from \"./use-resize-observer\";\n\ninterface UseSkeletonTreeOptions {\n readonly isLoading: boolean;\n readonly enableCache: boolean;\n readonly cacheKey?: string;\n}\n\ninterface UseSkeletonTreeResult {\n readonly tree: readonly SkeletonNode[] | null;\n readonly measureRef: React.RefObject<HTMLDivElement>;\n readonly hasMeasured: boolean;\n}\n\nexport function useSkeletonTree(options: UseSkeletonTreeOptions): UseSkeletonTreeResult {\n const { isLoading, enableCache, cacheKey } = options;\n const measureRef = useRef<HTMLDivElement>(null);\n const [tree, setTree] = useState<readonly SkeletonNode[] | null>(() => {\n if (enableCache && cacheKey) {\n return getCachedTree(cacheKey);\n }\n return null;\n });\n const [hasMeasured, setHasMeasured] = useState(tree !== null);\n\n const size = useResizeObserver(measureRef);\n\n const measure = useCallback(() => {\n const element = measureRef.current;\n if (!element) return;\n\n const newTree = walkDom(element);\n setTree(newTree);\n setHasMeasured(true);\n\n if (enableCache && cacheKey) {\n setCachedTree(cacheKey, newTree);\n }\n }, [enableCache, cacheKey]);\n\n useEffect(() => {\n if (!isLoading || hasMeasured) return;\n\n const frame = requestAnimationFrame(() => {\n measure();\n });\n\n return () => cancelAnimationFrame(frame);\n }, [isLoading, hasMeasured, measure]);\n\n useEffect(() => {\n if (isLoading && size) {\n measure();\n }\n }, [isLoading, size, measure]);\n\n useEffect(() => {\n if (!isLoading) {\n setHasMeasured(false);\n }\n }, [isLoading]);\n\n return { tree, measureRef, hasMeasured };\n}\n","type ClassValue = string | boolean | null | undefined;\n\nexport function cn(...classes: ClassValue[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n","import type { SkeletonNode } from \"../types\";\nimport { cn } from \"../utils/cn\";\n\nfunction getLayoutClasses(node: SkeletonNode): string {\n if (node.isLeaf) return \"\";\n\n const classes: string[] = [];\n\n if (node.display === \"flex\") {\n classes.push(\"flex\");\n if (node.flexDirection === \"column\") {\n classes.push(\"flex-col\");\n }\n } else if (node.display === \"grid\" && node.gridCols) {\n classes.push(\"grid\");\n classes.push(`grid-cols-${node.gridCols}`);\n } else if (node.display === \"inline\" || node.display === \"inline-block\") {\n classes.push(\"inline-flex\");\n } else {\n classes.push(\"flex flex-col\");\n }\n\n return cn(...classes);\n}\n\nfunction getSkeletonClasses(node: SkeletonNode): string {\n if (!node.isLeaf) return \"\";\n return cn(\n \"animate-pulse\",\n \"bg-neutral-200/60 dark:bg-neutral-700/60\",\n node.borderRadius,\n );\n}\n\nexport interface GeneratedSkeleton {\n readonly node: SkeletonNode;\n readonly className: string;\n readonly style: Record<string, string | number>;\n readonly children: readonly GeneratedSkeleton[];\n}\n\nfunction generateNode(node: SkeletonNode): GeneratedSkeleton {\n const style: Record<string, string | number> = {\n width: node.width,\n height: node.isLeaf ? node.height : \"auto\",\n };\n\n if (node.gap > 0 && !node.isLeaf) {\n style.gap = node.gap;\n }\n\n const layoutClass = getLayoutClasses(node);\n const skeletonClass = getSkeletonClasses(node);\n const className = cn(layoutClass, skeletonClass);\n\n const children = node.isLeaf\n ? []\n : node.children.map((child) => generateNode(child));\n\n return { node, className, style, children };\n}\n\nexport function generateSkeletonTree(\n nodes: readonly SkeletonNode[],\n): readonly GeneratedSkeleton[] {\n return nodes.map((node) => generateNode(node));\n}\n","import type { SkeletonNode } from \"../types\";\nimport { generateSkeletonTree, type GeneratedSkeleton } from \"../core/skeleton-generator\";\nimport { cn } from \"../utils/cn\";\n\ninterface SkeletonRendererProps {\n readonly tree: readonly SkeletonNode[];\n readonly className?: string;\n}\n\nfunction SkeletonNodeView({ skeleton }: { readonly skeleton: GeneratedSkeleton }) {\n return (\n <div\n className={skeleton.className}\n style={skeleton.style}\n aria-hidden=\"true\"\n >\n {skeleton.children.map((child) => (\n <SkeletonNodeView key={child.node.id} skeleton={child} />\n ))}\n </div>\n );\n}\n\nexport function SkeletonRenderer({ tree, className }: SkeletonRendererProps) {\n const generated = generateSkeletonTree(tree);\n\n return (\n <div\n className={cn(\"relative\", className)}\n role=\"status\"\n aria-busy=\"true\"\n aria-label=\"Loading content\"\n >\n {generated.map((skeleton) => (\n <SkeletonNodeView key={skeleton.node.id} skeleton={skeleton} />\n ))}\n </div>\n );\n}\n","import { cn } from \"../utils/cn\";\n\ninterface ErrorRendererProps {\n readonly error: unknown;\n readonly retry?: () => void;\n readonly className?: string;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return \"An unexpected error occurred\";\n}\n\nexport function ErrorRenderer({ error, retry, className }: ErrorRendererProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 p-6 text-center\",\n className,\n )}\n role=\"alert\"\n >\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30\">\n <svg\n className=\"h-6 w-6 text-red-600 dark:text-red-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z\"\n />\n </svg>\n </div>\n <p className=\"text-sm text-neutral-600 dark:text-neutral-400\">\n {getErrorMessage(error)}\n </p>\n {retry && (\n <button\n type=\"button\"\n onClick={retry}\n className=\"rounded-md bg-neutral-100 px-3 py-1.5 text-sm font-medium text-neutral-700 transition-colors hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n >\n Try again\n </button>\n )}\n </div>\n );\n}\n","import { cn } from \"../utils/cn\";\n\ninterface EmptyRendererProps {\n readonly className?: string;\n}\n\nexport function EmptyRenderer({ className }: EmptyRendererProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 p-6 text-center\",\n className,\n )}\n >\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-neutral-100 dark:bg-neutral-800\">\n <svg\n className=\"h-6 w-6 text-neutral-400 dark:text-neutral-500\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5m6 4.125l2.25 2.25m0 0l2.25 2.25M12 13.875l2.25-2.25M12 13.875l-2.25 2.25M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z\"\n />\n </svg>\n </div>\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400\">\n No data found\n </p>\n </div>\n );\n}\n","import { cn } from \"./cn\";\n\ninterface FallbackSkeletonProps {\n readonly className?: string;\n}\n\nexport function FallbackSkeleton({ className }: FallbackSkeletonProps) {\n return (\n <div className={cn(\"flex flex-col gap-4 w-full animate-pulse\", className)}>\n <div className=\"h-6 w-3/4 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"h-4 w-full rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"h-4 w-5/6 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"flex gap-3\">\n <div className=\"h-10 w-10 rounded-full bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"flex flex-col gap-2 flex-1\">\n <div className=\"h-4 w-1/2 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"h-4 w-1/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n </div>\n </div>\n <div className=\"h-4 w-2/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n </div>\n );\n}\n","import type { UIStatesProps } from \"../types\";\nimport { useUIState } from \"../hooks/use-ui-state\";\nimport { useSkeletonTree } from \"../hooks/use-skeleton-tree\";\nimport { SkeletonRenderer } from \"../renderers/skeleton-renderer\";\nimport { ErrorRenderer } from \"../renderers/error-renderer\";\nimport { EmptyRenderer } from \"../renderers/empty-renderer\";\nimport { FallbackSkeleton } from \"../utils/fallback-skeleton\";\nimport { cn } from \"../utils/cn\";\n\nexport function UIStates(props: UIStatesProps) {\n const {\n children,\n emptyState,\n errorState,\n enableCache = false,\n cacheKey,\n className,\n skeletonClassName,\n } = props;\n\n const { state, error, retry } = useUIState(props);\n const { tree, measureRef, hasMeasured } = useSkeletonTree({\n isLoading: state === \"loading\",\n enableCache,\n cacheKey,\n });\n\n if (state === \"error\") {\n if (errorState) {\n if (typeof errorState === \"function\") {\n return <>{errorState(error, retry)}</>;\n }\n return <>{errorState}</>;\n }\n return <ErrorRenderer error={error} retry={retry} className={className} />;\n }\n\n if (state === \"empty\") {\n if (emptyState) {\n return <>{emptyState}</>;\n }\n return <EmptyRenderer className={className} />;\n }\n\n if (state === \"loading\") {\n return (\n <div className={cn(\"relative\", className)}>\n {/* Hidden children for DOM measurement */}\n <div\n ref={measureRef}\n aria-hidden=\"true\"\n style={{\n visibility: \"hidden\",\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n height: 0,\n }}\n >\n {children}\n </div>\n\n {/* Skeleton overlay */}\n {hasMeasured && tree ? (\n <SkeletonRenderer tree={tree} className={skeletonClassName} />\n ) : (\n <FallbackSkeleton className={skeletonClassName} />\n )}\n </div>\n );\n }\n\n return <>{children}</>;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type UIState = "loading" | "error" | "empty" | "success";
|
|
5
|
+
interface SkeletonNode {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly width: number;
|
|
8
|
+
readonly height: number;
|
|
9
|
+
readonly borderRadius: string;
|
|
10
|
+
readonly display: "block" | "flex" | "grid" | "inline" | "inline-block";
|
|
11
|
+
readonly flexDirection?: "row" | "column";
|
|
12
|
+
readonly gridCols?: number;
|
|
13
|
+
readonly gap: number;
|
|
14
|
+
readonly isLeaf: boolean;
|
|
15
|
+
readonly children: readonly SkeletonNode[];
|
|
16
|
+
readonly tagName: string;
|
|
17
|
+
}
|
|
18
|
+
interface QueryLike {
|
|
19
|
+
readonly isLoading?: boolean;
|
|
20
|
+
readonly isPending?: boolean;
|
|
21
|
+
readonly isError?: boolean;
|
|
22
|
+
readonly error?: unknown;
|
|
23
|
+
readonly data?: unknown;
|
|
24
|
+
readonly refetch?: () => void;
|
|
25
|
+
}
|
|
26
|
+
interface UIStatesProps {
|
|
27
|
+
readonly children: ReactNode;
|
|
28
|
+
readonly data?: unknown;
|
|
29
|
+
readonly loading?: boolean;
|
|
30
|
+
readonly error?: unknown;
|
|
31
|
+
readonly query?: QueryLike;
|
|
32
|
+
readonly emptyState?: ReactNode;
|
|
33
|
+
readonly errorState?: ReactNode | ((error: unknown, retry?: () => void) => ReactNode);
|
|
34
|
+
readonly emptyCheck?: (data: unknown) => boolean;
|
|
35
|
+
readonly enableCache?: boolean;
|
|
36
|
+
readonly cacheKey?: string;
|
|
37
|
+
readonly className?: string;
|
|
38
|
+
readonly skeletonClassName?: string;
|
|
39
|
+
readonly minLoadingMs?: number;
|
|
40
|
+
}
|
|
41
|
+
interface CacheEntry {
|
|
42
|
+
readonly tree: readonly SkeletonNode[];
|
|
43
|
+
readonly viewportWidth: number;
|
|
44
|
+
readonly viewportHeight: number;
|
|
45
|
+
readonly timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare function UIStates(props: UIStatesProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
|
|
50
|
+
interface SkeletonRendererProps {
|
|
51
|
+
readonly tree: readonly SkeletonNode[];
|
|
52
|
+
readonly className?: string;
|
|
53
|
+
}
|
|
54
|
+
declare function SkeletonRenderer({ tree, className }: SkeletonRendererProps): react_jsx_runtime.JSX.Element;
|
|
55
|
+
|
|
56
|
+
interface ErrorRendererProps {
|
|
57
|
+
readonly error: unknown;
|
|
58
|
+
readonly retry?: () => void;
|
|
59
|
+
readonly className?: string;
|
|
60
|
+
}
|
|
61
|
+
declare function ErrorRenderer({ error, retry, className }: ErrorRendererProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
interface EmptyRendererProps {
|
|
64
|
+
readonly className?: string;
|
|
65
|
+
}
|
|
66
|
+
declare function EmptyRenderer({ className }: EmptyRendererProps): react_jsx_runtime.JSX.Element;
|
|
67
|
+
|
|
68
|
+
interface FallbackSkeletonProps {
|
|
69
|
+
readonly className?: string;
|
|
70
|
+
}
|
|
71
|
+
declare function FallbackSkeleton({ className }: FallbackSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
72
|
+
|
|
73
|
+
interface UIStateResult {
|
|
74
|
+
readonly state: UIState;
|
|
75
|
+
readonly error: unknown;
|
|
76
|
+
readonly retry?: () => void;
|
|
77
|
+
}
|
|
78
|
+
declare function useUIState(props: UIStatesProps): UIStateResult;
|
|
79
|
+
|
|
80
|
+
interface UseSkeletonTreeOptions {
|
|
81
|
+
readonly isLoading: boolean;
|
|
82
|
+
readonly enableCache: boolean;
|
|
83
|
+
readonly cacheKey?: string;
|
|
84
|
+
}
|
|
85
|
+
interface UseSkeletonTreeResult {
|
|
86
|
+
readonly tree: readonly SkeletonNode[] | null;
|
|
87
|
+
readonly measureRef: React.RefObject<HTMLDivElement>;
|
|
88
|
+
readonly hasMeasured: boolean;
|
|
89
|
+
}
|
|
90
|
+
declare function useSkeletonTree(options: UseSkeletonTreeOptions): UseSkeletonTreeResult;
|
|
91
|
+
|
|
92
|
+
interface Size {
|
|
93
|
+
readonly width: number;
|
|
94
|
+
readonly height: number;
|
|
95
|
+
}
|
|
96
|
+
declare function useResizeObserver(ref: React.RefObject<Element>): Size | null;
|
|
97
|
+
|
|
98
|
+
export { type CacheEntry, EmptyRenderer, ErrorRenderer, FallbackSkeleton, type QueryLike, type SkeletonNode, SkeletonRenderer, type UIState, UIStates, type UIStatesProps, useResizeObserver, useSkeletonTree, useUIState };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type UIState = "loading" | "error" | "empty" | "success";
|
|
5
|
+
interface SkeletonNode {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly width: number;
|
|
8
|
+
readonly height: number;
|
|
9
|
+
readonly borderRadius: string;
|
|
10
|
+
readonly display: "block" | "flex" | "grid" | "inline" | "inline-block";
|
|
11
|
+
readonly flexDirection?: "row" | "column";
|
|
12
|
+
readonly gridCols?: number;
|
|
13
|
+
readonly gap: number;
|
|
14
|
+
readonly isLeaf: boolean;
|
|
15
|
+
readonly children: readonly SkeletonNode[];
|
|
16
|
+
readonly tagName: string;
|
|
17
|
+
}
|
|
18
|
+
interface QueryLike {
|
|
19
|
+
readonly isLoading?: boolean;
|
|
20
|
+
readonly isPending?: boolean;
|
|
21
|
+
readonly isError?: boolean;
|
|
22
|
+
readonly error?: unknown;
|
|
23
|
+
readonly data?: unknown;
|
|
24
|
+
readonly refetch?: () => void;
|
|
25
|
+
}
|
|
26
|
+
interface UIStatesProps {
|
|
27
|
+
readonly children: ReactNode;
|
|
28
|
+
readonly data?: unknown;
|
|
29
|
+
readonly loading?: boolean;
|
|
30
|
+
readonly error?: unknown;
|
|
31
|
+
readonly query?: QueryLike;
|
|
32
|
+
readonly emptyState?: ReactNode;
|
|
33
|
+
readonly errorState?: ReactNode | ((error: unknown, retry?: () => void) => ReactNode);
|
|
34
|
+
readonly emptyCheck?: (data: unknown) => boolean;
|
|
35
|
+
readonly enableCache?: boolean;
|
|
36
|
+
readonly cacheKey?: string;
|
|
37
|
+
readonly className?: string;
|
|
38
|
+
readonly skeletonClassName?: string;
|
|
39
|
+
readonly minLoadingMs?: number;
|
|
40
|
+
}
|
|
41
|
+
interface CacheEntry {
|
|
42
|
+
readonly tree: readonly SkeletonNode[];
|
|
43
|
+
readonly viewportWidth: number;
|
|
44
|
+
readonly viewportHeight: number;
|
|
45
|
+
readonly timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare function UIStates(props: UIStatesProps): react_jsx_runtime.JSX.Element;
|
|
49
|
+
|
|
50
|
+
interface SkeletonRendererProps {
|
|
51
|
+
readonly tree: readonly SkeletonNode[];
|
|
52
|
+
readonly className?: string;
|
|
53
|
+
}
|
|
54
|
+
declare function SkeletonRenderer({ tree, className }: SkeletonRendererProps): react_jsx_runtime.JSX.Element;
|
|
55
|
+
|
|
56
|
+
interface ErrorRendererProps {
|
|
57
|
+
readonly error: unknown;
|
|
58
|
+
readonly retry?: () => void;
|
|
59
|
+
readonly className?: string;
|
|
60
|
+
}
|
|
61
|
+
declare function ErrorRenderer({ error, retry, className }: ErrorRendererProps): react_jsx_runtime.JSX.Element;
|
|
62
|
+
|
|
63
|
+
interface EmptyRendererProps {
|
|
64
|
+
readonly className?: string;
|
|
65
|
+
}
|
|
66
|
+
declare function EmptyRenderer({ className }: EmptyRendererProps): react_jsx_runtime.JSX.Element;
|
|
67
|
+
|
|
68
|
+
interface FallbackSkeletonProps {
|
|
69
|
+
readonly className?: string;
|
|
70
|
+
}
|
|
71
|
+
declare function FallbackSkeleton({ className }: FallbackSkeletonProps): react_jsx_runtime.JSX.Element;
|
|
72
|
+
|
|
73
|
+
interface UIStateResult {
|
|
74
|
+
readonly state: UIState;
|
|
75
|
+
readonly error: unknown;
|
|
76
|
+
readonly retry?: () => void;
|
|
77
|
+
}
|
|
78
|
+
declare function useUIState(props: UIStatesProps): UIStateResult;
|
|
79
|
+
|
|
80
|
+
interface UseSkeletonTreeOptions {
|
|
81
|
+
readonly isLoading: boolean;
|
|
82
|
+
readonly enableCache: boolean;
|
|
83
|
+
readonly cacheKey?: string;
|
|
84
|
+
}
|
|
85
|
+
interface UseSkeletonTreeResult {
|
|
86
|
+
readonly tree: readonly SkeletonNode[] | null;
|
|
87
|
+
readonly measureRef: React.RefObject<HTMLDivElement>;
|
|
88
|
+
readonly hasMeasured: boolean;
|
|
89
|
+
}
|
|
90
|
+
declare function useSkeletonTree(options: UseSkeletonTreeOptions): UseSkeletonTreeResult;
|
|
91
|
+
|
|
92
|
+
interface Size {
|
|
93
|
+
readonly width: number;
|
|
94
|
+
readonly height: number;
|
|
95
|
+
}
|
|
96
|
+
declare function useResizeObserver(ref: React.RefObject<Element>): Size | null;
|
|
97
|
+
|
|
98
|
+
export { type CacheEntry, EmptyRenderer, ErrorRenderer, FallbackSkeleton, type QueryLike, type SkeletonNode, SkeletonRenderer, type UIState, UIStates, type UIStatesProps, useResizeObserver, useSkeletonTree, useUIState };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {useMemo,useState,useRef,useCallback,useEffect}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';function H(e,t){return t?t(e):!!(e==null||Array.isArray(e)&&e.length===0)}function b(e){let{data:t,loading:o,error:n,query:r,emptyCheck:s}=e;return useMemo(()=>r?r.isLoading??r.isPending??false?{state:"loading",error:null}:r.isError?{state:"error",error:r.error,retry:r.refetch}:H(r.data,s)?{state:"empty",error:null}:{state:"success",error:null}:o?{state:"loading",error:null}:n?{state:"error",error:n}:H(t,s)?{state:"empty",error:null}:{state:"success",error:null},[t,o,n,r,s])}var M="ui-states:",P={"0px":"rounded-none","2px":"rounded-sm","4px":"rounded","6px":"rounded-md","8px":"rounded-lg","12px":"rounded-xl","16px":"rounded-2xl","24px":"rounded-3xl","9999px":"rounded-full"},U=new Set(["SCRIPT","STYLE","LINK","META","NOSCRIPT","BR","HR","WBR"]),_=new Set(["IMG","VIDEO","CANVAS","SVG","INPUT","TEXTAREA","SELECT","BUTTON","A","SPAN","P","H1","H2","H3","H4","H5","H6","LABEL"]);function G(e){if(U.has(e.tagName)||e instanceof HTMLElement&&e.hidden)return true;let t=window.getComputedStyle(e);return t.display==="none"||t.visibility==="hidden"||t.opacity==="0"}function W(e){return e.width<8||e.height<8}function E(e){let t=e.getBoundingClientRect();return {width:t.width,height:t.height,top:t.top,left:t.left}}function ee(e){let t=parseFloat(e);return Number.isNaN(t)?0:t}function te(e){if(!e||e==="0px")return "rounded-none";let o=e.split(" ")[0]??"0px",n=P[o];if(n)return n;let r=parseFloat(o);return Number.isNaN(r)?"rounded":r>=9999?"rounded-full":r>=24?"rounded-3xl":r>=16?"rounded-2xl":r>=12?"rounded-xl":r>=8?"rounded-lg":r>=6?"rounded-md":r>=4?"rounded":r>=2?"rounded-sm":"rounded-none"}function re(e){if(e.display!=="grid")return;let t=e.gridTemplateColumns;if(!t||t==="none")return;let o=t.split(/\s+/).filter(n=>n!=="none"&&n.length>0);return o.length>0?o.length:void 0}function ne(e){return e.includes("flex")?"flex":e.includes("grid")?"grid":e.includes("inline-block")?"inline-block":e.includes("inline")?"inline":"block"}function R(e){let t=window.getComputedStyle(e),o=ne(t.display);return {display:o,flexDirection:o==="flex"?t.flexDirection==="column"?"column":"row":void 0,gridCols:re(t),gap:ee(t.gap),borderRadius:te(t.borderRadius)}}var w=0;function y(){return w+=1,`sk-${w}`}function ie(e){return _.has(e.tagName)?true:e.childNodes.length>0&&Array.from(e.childNodes).every(o=>o.nodeType===Node.TEXT_NODE)?(e.textContent?.trim()??"").length>0:e.children.length===0}function z(e,t,o){if(t>o.maxDepth||G(e))return null;let n=E(e);if(W(n))return null;let r=R(e);if(ie(e))return {id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,gap:0,isLeaf:true,children:[],tagName:e.tagName};let i=[];for(let u of Array.from(e.children)){let l=z(u,t+1,o);l&&i.push(l);}return i.length===0?{id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,gap:0,isLeaf:true,children:[],tagName:e.tagName}:{id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,flexDirection:r.flexDirection,gridCols:r.gridCols,gap:r.gap,isLeaf:false,children:i,tagName:e.tagName}}function F(e){w=0;let t={maxDepth:10},o=[];for(let n of Array.from(e.children)){let r=z(n,0,t);r&&o.push(r);}if(o.length===0){let n=E(e),r=R(e);return [{id:y(),width:n.width,height:n.height,borderRadius:r.borderRadius,display:r.display,gap:0,isLeaf:true,children:[],tagName:e.tagName}]}return o}function S(e){return `${M}${e}`}function V(e){try{let t=sessionStorage.getItem(S(e));if(!t)return null;let o=JSON.parse(t);if(Date.now()-o.timestamp>3e5)return sessionStorage.removeItem(S(e)),null;let r=Math.abs(window.innerWidth-o.viewportWidth),s=Math.abs(window.innerHeight-o.viewportHeight);return r>50||s>50?(sessionStorage.removeItem(S(e)),null):o.tree}catch{return null}}function X(e,t){try{let o={tree:t,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,timestamp:Date.now()};sessionStorage.setItem(S(e),JSON.stringify(o));}catch{}}function v(e){let[t,o]=useState(null),n=useRef(null),r=useCallback(s=>{n.current&&clearTimeout(n.current),n.current=setTimeout(()=>{let i=s[0];i&&o({width:i.contentRect.width,height:i.contentRect.height});},200);},[]);return useEffect(()=>{let s=e.current;if(!s)return;let i=new ResizeObserver(r);return i.observe(s),()=>{i.disconnect(),n.current&&clearTimeout(n.current);}},[e,r]),t}function I(e){let{isLoading:t,enableCache:o,cacheKey:n}=e,r=useRef(null),[s,i]=useState(()=>o&&n?V(n):null),[u,l]=useState(s!==null),p=v(r),c=useCallback(()=>{let f=r.current;if(!f)return;let h=F(f);i(h),l(true),o&&n&&X(n,h);},[o,n]);return useEffect(()=>{if(!t||u)return;let f=requestAnimationFrame(()=>{c();});return ()=>cancelAnimationFrame(f)},[t,u,c]),useEffect(()=>{t&&p&&c();},[t,p,c]),useEffect(()=>{t||l(false);},[t]),{tree:s,measureRef:r,hasMeasured:u}}function a(...e){return e.filter(Boolean).join(" ")}function me(e){if(e.isLeaf)return "";let t=[];return e.display==="flex"?(t.push("flex"),e.flexDirection==="column"&&t.push("flex-col")):e.display==="grid"&&e.gridCols?(t.push("grid"),t.push(`grid-cols-${e.gridCols}`)):e.display==="inline"||e.display==="inline-block"?t.push("inline-flex"):t.push("flex flex-col"),a(...t)}function pe(e){return e.isLeaf?a("animate-pulse","bg-neutral-200/60 dark:bg-neutral-700/60",e.borderRadius):""}function Z(e){let t={width:e.width,height:e.isLeaf?e.height:"auto"};e.gap>0&&!e.isLeaf&&(t.gap=e.gap);let o=me(e),n=pe(e),r=a(o,n),s=e.isLeaf?[]:e.children.map(i=>Z(i));return {node:e,className:r,style:t,children:s}}function j(e){return e.map(t=>Z(t))}function $({skeleton:e}){return jsx("div",{className:e.className,style:e.style,"aria-hidden":"true",children:e.children.map(t=>jsx($,{skeleton:t},t.node.id))})}function C({tree:e,className:t}){let o=j(e);return jsx("div",{className:a("relative",t),role:"status","aria-busy":"true","aria-label":"Loading content",children:o.map(n=>jsx($,{skeleton:n},n.node.id))})}function ge(e){return e instanceof Error?e.message:typeof e=="string"?e:"An unexpected error occurred"}function L({error:e,retry:t,className:o}){return jsxs("div",{className:a("flex flex-col items-center justify-center gap-3 p-6 text-center",o),role:"alert",children:[jsx("div",{className:"flex h-12 w-12 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30",children:jsx("svg",{className:"h-6 w-6 text-red-600 dark:text-red-400",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor","aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"})})}),jsx("p",{className:"text-sm text-neutral-600 dark:text-neutral-400",children:ge(e)}),t&&jsx("button",{type:"button",onClick:t,className:"rounded-md bg-neutral-100 px-3 py-1.5 text-sm font-medium text-neutral-700 transition-colors hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700",children:"Try again"})]})}function A({className:e}){return jsxs("div",{className:a("flex flex-col items-center justify-center gap-3 p-6 text-center",e),children:[jsx("div",{className:"flex h-12 w-12 items-center justify-center rounded-full bg-neutral-100 dark:bg-neutral-800",children:jsx("svg",{className:"h-6 w-6 text-neutral-400 dark:text-neutral-500",fill:"none",viewBox:"0 0 24 24",strokeWidth:1.5,stroke:"currentColor","aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M20.25 7.5l-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5m6 4.125l2.25 2.25m0 0l2.25 2.25M12 13.875l2.25-2.25M12 13.875l-2.25 2.25M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z"})})}),jsx("p",{className:"text-sm text-neutral-500 dark:text-neutral-400",children:"No data found"})]})}function O({className:e}){return jsxs("div",{className:a("flex flex-col gap-4 w-full animate-pulse",e),children:[jsx("div",{className:"h-6 w-3/4 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsx("div",{className:"h-4 w-full rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsx("div",{className:"h-4 w-5/6 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxs("div",{className:"flex gap-3",children:[jsx("div",{className:"h-10 w-10 rounded-full bg-neutral-200/60 dark:bg-neutral-700/60"}),jsxs("div",{className:"flex flex-col gap-2 flex-1",children:[jsx("div",{className:"h-4 w-1/2 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"}),jsx("div",{className:"h-4 w-1/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"})]})]}),jsx("div",{className:"h-4 w-2/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60"})]})}function Se(e){let{children:t,emptyState:o,errorState:n,enableCache:r=false,cacheKey:s,className:i,skeletonClassName:u}=e,{state:l,error:p,retry:c}=b(e),{tree:f,measureRef:h,hasMeasured:q}=I({isLoading:l==="loading",enableCache:r,cacheKey:s});return l==="error"?n?typeof n=="function"?jsx(Fragment,{children:n(p,c)}):jsx(Fragment,{children:n}):jsx(L,{error:p,retry:c,className:i}):l==="empty"?o?jsx(Fragment,{children:o}):jsx(A,{className:i}):l==="loading"?jsxs("div",{className:a("relative",i),children:[jsx("div",{ref:h,"aria-hidden":"true",style:{visibility:"hidden",position:"absolute",top:0,left:0,right:0,pointerEvents:"none",overflow:"hidden",height:0},children:t}),q&&f?jsx(C,{tree:f,className:u}):jsx(O,{className:u})]}):jsx(Fragment,{children:t})}export{A as EmptyRenderer,L as ErrorRenderer,O as FallbackSkeleton,C as SkeletonRenderer,Se as UIStates,v as useResizeObserver,I as useSkeletonTree,b as useUIState};//# sourceMappingURL=index.js.map
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-ui-state.ts","../src/constants.ts","../src/utils/element-filters.ts","../src/core/layout-detector.ts","../src/core/dom-walker.ts","../src/utils/storage.ts","../src/hooks/use-resize-observer.ts","../src/hooks/use-skeleton-tree.ts","../src/utils/cn.ts","../src/core/skeleton-generator.ts","../src/renderers/skeleton-renderer.tsx","../src/renderers/error-renderer.tsx","../src/renderers/empty-renderer.tsx","../src/utils/fallback-skeleton.tsx","../src/components/ui-states.tsx"],"names":["isEmptyData","data","emptyCheck","useUIState","props","loading","error","query","useMemo","STORAGE_PREFIX","RADIUS_MAP","IGNORED_TAGS","LEAF_TAGS","shouldIgnoreElement","element","style","isElementTooSmall","rect","getElementRect","domRect","parseGap","gapValue","parsed","normalizeRadius","computed","first","mapped","px","detectGridCols","template","cols","part","normalizeDisplay","display","detectLayout","nodeCounter","generateId","isLeafElement","node","walkElement","depth","options","layout","children","child","childNode","walkDom","root","results","getStorageKey","key","getCachedTree","raw","entry","widthDiff","heightDiff","setCachedTree","tree","useResizeObserver","ref","size","setSize","useState","timeoutRef","useRef","handleResize","useCallback","entries","useEffect","observer","useSkeletonTree","isLoading","enableCache","cacheKey","measureRef","setTree","hasMeasured","setHasMeasured","measure","newTree","frame","cn","classes","getLayoutClasses","getSkeletonClasses","generateNode","layoutClass","skeletonClass","className","generateSkeletonTree","nodes","SkeletonNodeView","skeleton","jsx","SkeletonRenderer","generated","getErrorMessage","ErrorRenderer","retry","jsxs","EmptyRenderer","FallbackSkeleton","UIStates","emptyState","errorState","skeletonClassName","state","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["import { useMemo } from \"react\";\nimport type { UIState, UIStatesProps } from \"../types\";\n\ninterface UIStateResult {\n readonly state: UIState;\n readonly error: unknown;\n readonly retry?: () => void;\n}\n\nfunction isEmptyData(data: unknown, emptyCheck?: (data: unknown) => boolean): boolean {\n if (emptyCheck) return emptyCheck(data);\n if (data === null || data === undefined) return true;\n if (Array.isArray(data) && data.length === 0) return true;\n return false;\n}\n\nexport function useUIState(props: UIStatesProps): UIStateResult {\n const { data, loading, error, query, emptyCheck } = props;\n\n return useMemo(() => {\n if (query) {\n const isLoading = query.isLoading ?? query.isPending ?? false;\n if (isLoading) {\n return { state: \"loading\" as const, error: null };\n }\n if (query.isError) {\n return { state: \"error\" as const, error: query.error, retry: query.refetch };\n }\n if (isEmptyData(query.data, emptyCheck)) {\n return { state: \"empty\" as const, error: null };\n }\n return { state: \"success\" as const, error: null };\n }\n\n if (loading) {\n return { state: \"loading\" as const, error: null };\n }\n if (error) {\n return { state: \"error\" as const, error };\n }\n if (isEmptyData(data, emptyCheck)) {\n return { state: \"empty\" as const, error: null };\n }\n return { state: \"success\" as const, error: null };\n }, [data, loading, error, query, emptyCheck]);\n}\n","export const MIN_WIDTH = 8;\nexport const MIN_HEIGHT = 8;\nexport const MAX_DEPTH = 10;\nexport const CACHE_TTL = 5 * 60 * 1000;\nexport const RESIZE_DEBOUNCE_MS = 200;\nexport const VIEWPORT_TOLERANCE = 50;\nexport const STORAGE_PREFIX = \"ui-states:\";\n\nexport const RADIUS_MAP = {\n \"0px\": \"rounded-none\",\n \"2px\": \"rounded-sm\",\n \"4px\": \"rounded\",\n \"6px\": \"rounded-md\",\n \"8px\": \"rounded-lg\",\n \"12px\": \"rounded-xl\",\n \"16px\": \"rounded-2xl\",\n \"24px\": \"rounded-3xl\",\n \"9999px\": \"rounded-full\",\n} as const;\n\nexport const IGNORED_TAGS = new Set([\n \"SCRIPT\",\n \"STYLE\",\n \"LINK\",\n \"META\",\n \"NOSCRIPT\",\n \"BR\",\n \"HR\",\n \"WBR\",\n]);\n\nexport const LEAF_TAGS = new Set([\n \"IMG\",\n \"VIDEO\",\n \"CANVAS\",\n \"SVG\",\n \"INPUT\",\n \"TEXTAREA\",\n \"SELECT\",\n \"BUTTON\",\n \"A\",\n \"SPAN\",\n \"P\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n \"LABEL\",\n]);\n","import { IGNORED_TAGS, MIN_WIDTH, MIN_HEIGHT } from \"../constants\";\nimport type { ElementRect } from \"../types\";\n\nexport function shouldIgnoreElement(element: Element): boolean {\n if (IGNORED_TAGS.has(element.tagName)) {\n return true;\n }\n\n if (element instanceof HTMLElement && element.hidden) {\n return true;\n }\n\n const style = window.getComputedStyle(element);\n if (style.display === \"none\" || style.visibility === \"hidden\" || style.opacity === \"0\") {\n return true;\n }\n\n return false;\n}\n\nexport function isElementTooSmall(rect: ElementRect): boolean {\n return rect.width < MIN_WIDTH || rect.height < MIN_HEIGHT;\n}\n\nexport function getElementRect(element: Element): ElementRect {\n const domRect = element.getBoundingClientRect();\n return {\n width: domRect.width,\n height: domRect.height,\n top: domRect.top,\n left: domRect.left,\n };\n}\n","import { RADIUS_MAP } from \"../constants\";\nimport type { LayoutInfo, SkeletonNode } from \"../types\";\n\nfunction parseGap(gapValue: string): number {\n const parsed = parseFloat(gapValue);\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\nfunction normalizeRadius(computed: string): string {\n if (!computed || computed === \"0px\") return \"rounded-none\";\n\n const parts = computed.split(\" \");\n const first = parts[0] ?? \"0px\";\n\n const mapped = RADIUS_MAP[first as keyof typeof RADIUS_MAP];\n if (mapped) return mapped;\n\n const px = parseFloat(first);\n if (Number.isNaN(px)) return \"rounded\";\n\n if (px >= 9999) return \"rounded-full\";\n if (px >= 24) return \"rounded-3xl\";\n if (px >= 16) return \"rounded-2xl\";\n if (px >= 12) return \"rounded-xl\";\n if (px >= 8) return \"rounded-lg\";\n if (px >= 6) return \"rounded-md\";\n if (px >= 4) return \"rounded\";\n if (px >= 2) return \"rounded-sm\";\n return \"rounded-none\";\n}\n\nfunction detectGridCols(style: CSSStyleDeclaration): number | undefined {\n if (style.display !== \"grid\") return undefined;\n\n const template = style.gridTemplateColumns;\n if (!template || template === \"none\") return undefined;\n\n const cols = template.split(/\\s+/).filter((part) => part !== \"none\" && part.length > 0);\n return cols.length > 0 ? cols.length : undefined;\n}\n\nfunction normalizeDisplay(display: string): SkeletonNode[\"display\"] {\n if (display.includes(\"flex\")) return \"flex\";\n if (display.includes(\"grid\")) return \"grid\";\n if (display.includes(\"inline-block\")) return \"inline-block\";\n if (display.includes(\"inline\")) return \"inline\";\n return \"block\";\n}\n\nexport function detectLayout(element: Element): LayoutInfo {\n const style = window.getComputedStyle(element);\n const display = normalizeDisplay(style.display);\n\n return {\n display,\n flexDirection:\n display === \"flex\"\n ? (style.flexDirection as \"row\" | \"column\") === \"column\"\n ? \"column\"\n : \"row\"\n : undefined,\n gridCols: detectGridCols(style),\n gap: parseGap(style.gap),\n borderRadius: normalizeRadius(style.borderRadius),\n };\n}\n","import { MAX_DEPTH, LEAF_TAGS } from \"../constants\";\nimport type { DomWalkerOptions, SkeletonNode } from \"../types\";\nimport { shouldIgnoreElement, isElementTooSmall, getElementRect } from \"../utils/element-filters\";\nimport { detectLayout } from \"./layout-detector\";\n\nlet nodeCounter = 0;\n\nfunction generateId(): string {\n nodeCounter += 1;\n return `sk-${nodeCounter}`;\n}\n\nfunction isLeafElement(element: Element): boolean {\n if (LEAF_TAGS.has(element.tagName)) return true;\n\n const hasTextOnly =\n element.childNodes.length > 0 &&\n Array.from(element.childNodes).every((node) => node.nodeType === Node.TEXT_NODE);\n\n if (hasTextOnly) {\n const text = element.textContent?.trim() ?? \"\";\n return text.length > 0;\n }\n\n return element.children.length === 0;\n}\n\nfunction walkElement(\n element: Element,\n depth: number,\n options: DomWalkerOptions,\n): SkeletonNode | null {\n if (depth > options.maxDepth) return null;\n if (shouldIgnoreElement(element)) return null;\n\n const rect = getElementRect(element);\n if (isElementTooSmall(rect)) return null;\n\n const layout = detectLayout(element);\n const isLeaf = isLeafElement(element);\n\n if (isLeaf) {\n return {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n gap: 0,\n isLeaf: true,\n children: [],\n tagName: element.tagName,\n };\n }\n\n const children: SkeletonNode[] = [];\n for (const child of Array.from(element.children)) {\n const childNode = walkElement(child, depth + 1, options);\n if (childNode) {\n children.push(childNode);\n }\n }\n\n if (children.length === 0) {\n return {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n gap: 0,\n isLeaf: true,\n children: [],\n tagName: element.tagName,\n };\n }\n\n return {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n flexDirection: layout.flexDirection,\n gridCols: layout.gridCols,\n gap: layout.gap,\n isLeaf: false,\n children,\n tagName: element.tagName,\n };\n}\n\nexport function walkDom(root: Element): readonly SkeletonNode[] {\n nodeCounter = 0;\n\n const options: DomWalkerOptions = {\n maxDepth: MAX_DEPTH,\n minWidth: 8,\n minHeight: 8,\n };\n\n const results: SkeletonNode[] = [];\n\n for (const child of Array.from(root.children)) {\n const node = walkElement(child, 0, options);\n if (node) {\n results.push(node);\n }\n }\n\n if (results.length === 0) {\n const rect = getElementRect(root);\n const layout = detectLayout(root);\n return [\n {\n id: generateId(),\n width: rect.width,\n height: rect.height,\n borderRadius: layout.borderRadius,\n display: layout.display,\n gap: 0,\n isLeaf: true,\n children: [],\n tagName: root.tagName,\n },\n ];\n }\n\n return results;\n}\n","import { CACHE_TTL, STORAGE_PREFIX, VIEWPORT_TOLERANCE } from \"../constants\";\nimport type { CacheEntry, SkeletonNode } from \"../types\";\n\nfunction getStorageKey(key: string): string {\n return `${STORAGE_PREFIX}${key}`;\n}\n\nexport function getCachedTree(key: string): readonly SkeletonNode[] | null {\n try {\n const raw = sessionStorage.getItem(getStorageKey(key));\n if (!raw) return null;\n\n const entry: CacheEntry = JSON.parse(raw);\n const now = Date.now();\n\n if (now - entry.timestamp > CACHE_TTL) {\n sessionStorage.removeItem(getStorageKey(key));\n return null;\n }\n\n const widthDiff = Math.abs(window.innerWidth - entry.viewportWidth);\n const heightDiff = Math.abs(window.innerHeight - entry.viewportHeight);\n if (widthDiff > VIEWPORT_TOLERANCE || heightDiff > VIEWPORT_TOLERANCE) {\n sessionStorage.removeItem(getStorageKey(key));\n return null;\n }\n\n return entry.tree;\n } catch {\n return null;\n }\n}\n\nexport function setCachedTree(key: string, tree: readonly SkeletonNode[]): void {\n try {\n const entry: CacheEntry = {\n tree,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n timestamp: Date.now(),\n };\n sessionStorage.setItem(getStorageKey(key), JSON.stringify(entry));\n } catch {\n /* empty */\n }\n}\n","import { useEffect, useRef, useCallback, useState } from \"react\";\nimport { RESIZE_DEBOUNCE_MS } from \"../constants\";\n\ninterface Size {\n readonly width: number;\n readonly height: number;\n}\n\nexport function useResizeObserver(\n ref: React.RefObject<Element>,\n): Size | null {\n const [size, setSize] = useState<Size | null>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const handleResize = useCallback((entries: ResizeObserverEntry[]) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n const entry = entries[0];\n if (entry) {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n }, RESIZE_DEBOUNCE_MS);\n }, []);\n\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n\n const observer = new ResizeObserver(handleResize);\n observer.observe(element);\n\n return () => {\n observer.disconnect();\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [ref, handleResize]);\n\n return size;\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { SkeletonNode } from \"../types\";\nimport { walkDom } from \"../core/dom-walker\";\nimport { getCachedTree, setCachedTree } from \"../utils/storage\";\nimport { useResizeObserver } from \"./use-resize-observer\";\n\ninterface UseSkeletonTreeOptions {\n readonly isLoading: boolean;\n readonly enableCache: boolean;\n readonly cacheKey?: string;\n}\n\ninterface UseSkeletonTreeResult {\n readonly tree: readonly SkeletonNode[] | null;\n readonly measureRef: React.RefObject<HTMLDivElement>;\n readonly hasMeasured: boolean;\n}\n\nexport function useSkeletonTree(options: UseSkeletonTreeOptions): UseSkeletonTreeResult {\n const { isLoading, enableCache, cacheKey } = options;\n const measureRef = useRef<HTMLDivElement>(null);\n const [tree, setTree] = useState<readonly SkeletonNode[] | null>(() => {\n if (enableCache && cacheKey) {\n return getCachedTree(cacheKey);\n }\n return null;\n });\n const [hasMeasured, setHasMeasured] = useState(tree !== null);\n\n const size = useResizeObserver(measureRef);\n\n const measure = useCallback(() => {\n const element = measureRef.current;\n if (!element) return;\n\n const newTree = walkDom(element);\n setTree(newTree);\n setHasMeasured(true);\n\n if (enableCache && cacheKey) {\n setCachedTree(cacheKey, newTree);\n }\n }, [enableCache, cacheKey]);\n\n useEffect(() => {\n if (!isLoading || hasMeasured) return;\n\n const frame = requestAnimationFrame(() => {\n measure();\n });\n\n return () => cancelAnimationFrame(frame);\n }, [isLoading, hasMeasured, measure]);\n\n useEffect(() => {\n if (isLoading && size) {\n measure();\n }\n }, [isLoading, size, measure]);\n\n useEffect(() => {\n if (!isLoading) {\n setHasMeasured(false);\n }\n }, [isLoading]);\n\n return { tree, measureRef, hasMeasured };\n}\n","type ClassValue = string | boolean | null | undefined;\n\nexport function cn(...classes: ClassValue[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n","import type { SkeletonNode } from \"../types\";\nimport { cn } from \"../utils/cn\";\n\nfunction getLayoutClasses(node: SkeletonNode): string {\n if (node.isLeaf) return \"\";\n\n const classes: string[] = [];\n\n if (node.display === \"flex\") {\n classes.push(\"flex\");\n if (node.flexDirection === \"column\") {\n classes.push(\"flex-col\");\n }\n } else if (node.display === \"grid\" && node.gridCols) {\n classes.push(\"grid\");\n classes.push(`grid-cols-${node.gridCols}`);\n } else if (node.display === \"inline\" || node.display === \"inline-block\") {\n classes.push(\"inline-flex\");\n } else {\n classes.push(\"flex flex-col\");\n }\n\n return cn(...classes);\n}\n\nfunction getSkeletonClasses(node: SkeletonNode): string {\n if (!node.isLeaf) return \"\";\n return cn(\n \"animate-pulse\",\n \"bg-neutral-200/60 dark:bg-neutral-700/60\",\n node.borderRadius,\n );\n}\n\nexport interface GeneratedSkeleton {\n readonly node: SkeletonNode;\n readonly className: string;\n readonly style: Record<string, string | number>;\n readonly children: readonly GeneratedSkeleton[];\n}\n\nfunction generateNode(node: SkeletonNode): GeneratedSkeleton {\n const style: Record<string, string | number> = {\n width: node.width,\n height: node.isLeaf ? node.height : \"auto\",\n };\n\n if (node.gap > 0 && !node.isLeaf) {\n style.gap = node.gap;\n }\n\n const layoutClass = getLayoutClasses(node);\n const skeletonClass = getSkeletonClasses(node);\n const className = cn(layoutClass, skeletonClass);\n\n const children = node.isLeaf\n ? []\n : node.children.map((child) => generateNode(child));\n\n return { node, className, style, children };\n}\n\nexport function generateSkeletonTree(\n nodes: readonly SkeletonNode[],\n): readonly GeneratedSkeleton[] {\n return nodes.map((node) => generateNode(node));\n}\n","import type { SkeletonNode } from \"../types\";\nimport { generateSkeletonTree, type GeneratedSkeleton } from \"../core/skeleton-generator\";\nimport { cn } from \"../utils/cn\";\n\ninterface SkeletonRendererProps {\n readonly tree: readonly SkeletonNode[];\n readonly className?: string;\n}\n\nfunction SkeletonNodeView({ skeleton }: { readonly skeleton: GeneratedSkeleton }) {\n return (\n <div\n className={skeleton.className}\n style={skeleton.style}\n aria-hidden=\"true\"\n >\n {skeleton.children.map((child) => (\n <SkeletonNodeView key={child.node.id} skeleton={child} />\n ))}\n </div>\n );\n}\n\nexport function SkeletonRenderer({ tree, className }: SkeletonRendererProps) {\n const generated = generateSkeletonTree(tree);\n\n return (\n <div\n className={cn(\"relative\", className)}\n role=\"status\"\n aria-busy=\"true\"\n aria-label=\"Loading content\"\n >\n {generated.map((skeleton) => (\n <SkeletonNodeView key={skeleton.node.id} skeleton={skeleton} />\n ))}\n </div>\n );\n}\n","import { cn } from \"../utils/cn\";\n\ninterface ErrorRendererProps {\n readonly error: unknown;\n readonly retry?: () => void;\n readonly className?: string;\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return \"An unexpected error occurred\";\n}\n\nexport function ErrorRenderer({ error, retry, className }: ErrorRendererProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 p-6 text-center\",\n className,\n )}\n role=\"alert\"\n >\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30\">\n <svg\n className=\"h-6 w-6 text-red-600 dark:text-red-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z\"\n />\n </svg>\n </div>\n <p className=\"text-sm text-neutral-600 dark:text-neutral-400\">\n {getErrorMessage(error)}\n </p>\n {retry && (\n <button\n type=\"button\"\n onClick={retry}\n className=\"rounded-md bg-neutral-100 px-3 py-1.5 text-sm font-medium text-neutral-700 transition-colors hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n >\n Try again\n </button>\n )}\n </div>\n );\n}\n","import { cn } from \"../utils/cn\";\n\ninterface EmptyRendererProps {\n readonly className?: string;\n}\n\nexport function EmptyRenderer({ className }: EmptyRendererProps) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center gap-3 p-6 text-center\",\n className,\n )}\n >\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-neutral-100 dark:bg-neutral-800\">\n <svg\n className=\"h-6 w-6 text-neutral-400 dark:text-neutral-500\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5m6 4.125l2.25 2.25m0 0l2.25 2.25M12 13.875l2.25-2.25M12 13.875l-2.25 2.25M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z\"\n />\n </svg>\n </div>\n <p className=\"text-sm text-neutral-500 dark:text-neutral-400\">\n No data found\n </p>\n </div>\n );\n}\n","import { cn } from \"./cn\";\n\ninterface FallbackSkeletonProps {\n readonly className?: string;\n}\n\nexport function FallbackSkeleton({ className }: FallbackSkeletonProps) {\n return (\n <div className={cn(\"flex flex-col gap-4 w-full animate-pulse\", className)}>\n <div className=\"h-6 w-3/4 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"h-4 w-full rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"h-4 w-5/6 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"flex gap-3\">\n <div className=\"h-10 w-10 rounded-full bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"flex flex-col gap-2 flex-1\">\n <div className=\"h-4 w-1/2 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n <div className=\"h-4 w-1/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n </div>\n </div>\n <div className=\"h-4 w-2/3 rounded-md bg-neutral-200/60 dark:bg-neutral-700/60\" />\n </div>\n );\n}\n","import type { UIStatesProps } from \"../types\";\nimport { useUIState } from \"../hooks/use-ui-state\";\nimport { useSkeletonTree } from \"../hooks/use-skeleton-tree\";\nimport { SkeletonRenderer } from \"../renderers/skeleton-renderer\";\nimport { ErrorRenderer } from \"../renderers/error-renderer\";\nimport { EmptyRenderer } from \"../renderers/empty-renderer\";\nimport { FallbackSkeleton } from \"../utils/fallback-skeleton\";\nimport { cn } from \"../utils/cn\";\n\nexport function UIStates(props: UIStatesProps) {\n const {\n children,\n emptyState,\n errorState,\n enableCache = false,\n cacheKey,\n className,\n skeletonClassName,\n } = props;\n\n const { state, error, retry } = useUIState(props);\n const { tree, measureRef, hasMeasured } = useSkeletonTree({\n isLoading: state === \"loading\",\n enableCache,\n cacheKey,\n });\n\n if (state === \"error\") {\n if (errorState) {\n if (typeof errorState === \"function\") {\n return <>{errorState(error, retry)}</>;\n }\n return <>{errorState}</>;\n }\n return <ErrorRenderer error={error} retry={retry} className={className} />;\n }\n\n if (state === \"empty\") {\n if (emptyState) {\n return <>{emptyState}</>;\n }\n return <EmptyRenderer className={className} />;\n }\n\n if (state === \"loading\") {\n return (\n <div className={cn(\"relative\", className)}>\n {/* Hidden children for DOM measurement */}\n <div\n ref={measureRef}\n aria-hidden=\"true\"\n style={{\n visibility: \"hidden\",\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n height: 0,\n }}\n >\n {children}\n </div>\n\n {/* Skeleton overlay */}\n {hasMeasured && tree ? (\n <SkeletonRenderer tree={tree} className={skeletonClassName} />\n ) : (\n <FallbackSkeleton className={skeletonClassName} />\n )}\n </div>\n );\n }\n\n return <>{children}</>;\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@promise-inc/ui-states",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Auto-generated skeleton loading states from real DOM — zero config React component",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"type-check": "tsc --noEmit",
|
|
27
|
+
"dev": "tsup --watch"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"react": ">=18.0.0",
|
|
31
|
+
"react-dom": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/react": "^18.2.0",
|
|
35
|
+
"@types/react-dom": "^18.2.0",
|
|
36
|
+
"react": "^18.2.0",
|
|
37
|
+
"react-dom": "^18.2.0",
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.4.0"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"react",
|
|
43
|
+
"skeleton",
|
|
44
|
+
"loading",
|
|
45
|
+
"ui-states",
|
|
46
|
+
"auto-skeleton",
|
|
47
|
+
"loading-state"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/promise-inc/ui-states"
|
|
53
|
+
},
|
|
54
|
+
"sideEffects": false
|
|
55
|
+
}
|