react-resource-ui 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # React Resource UI
2
2
 
3
- A data orchestration layer for React focused on pagination and list-based UI patterns.
3
+ A high-level data orchestration layer for React focused on pagination, lists, and UI-driven data patterns.
4
4
 
5
5
  npm: https://www.npmjs.com/package/react-resource-ui
6
6
 
@@ -10,27 +10,75 @@ npm: https://www.npmjs.com/package/react-resource-ui
10
10
 
11
11
  React Resource UI provides a unified abstraction for handling data fetching, pagination, and virtualization in React applications.
12
12
 
13
- It simplifies common UI patterns such as tables and lists by removing the need to rewrite logic when switching between pagination strategies.
13
+ Instead of manually implementing pagination logic and rewriting UI behavior for different use cases, you define your data once and control behavior through configuration.
14
+
15
+ ---
16
+
17
+ ## Why use this?
18
+
19
+ In real applications, data fetching alone is not enough. You also need to manage:
20
+
21
+ - pagination logic
22
+ - switching between page, load more, and infinite scroll
23
+ - UI state consistency
24
+ - preventing stale updates and race conditions
25
+
26
+ Most tools provide low-level primitives, but you still write this logic yourself.
27
+
28
+ React Resource UI focuses on these higher-level patterns and removes the need to rewrite logic when requirements change.
14
29
 
15
30
  ---
16
31
 
17
32
  ## Installation
18
33
 
34
+ ```bash
19
35
  npm install react-resource-ui
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Core Concepts
41
+
42
+ ### 1. Source
43
+
44
+ Defines where your data comes from. It can be:
45
+
46
+ - an async function
47
+ - a URL string
48
+ - a static array
49
+
50
+ ---
51
+
52
+ ### 2. Pagination
53
+
54
+ Controls how data is fetched and appended:
55
+
56
+ - page → traditional pagination
57
+ - loadmore → append on button click
58
+ - infinite → auto-fetch on scroll
59
+
60
+ ---
61
+
62
+ ### 3. Virtualization
63
+
64
+ Optimizes rendering for large datasets by only rendering visible rows.
20
65
 
21
66
  ---
22
67
 
23
68
  ## Basic Usage
24
69
 
70
+ ```tsx
25
71
  import { useResource } from "react-resource-ui";
26
72
 
27
73
  function App() {
28
74
  const { data, loading, error, page, setPage } = useResource({
29
75
  source: async ({ page = 1, pageSize = 10 }) => {
30
76
  const skip = (page - 1) * pageSize;
77
+
31
78
  const res = await fetch(
32
79
  `https://dummyjson.com/todos?limit=${pageSize}&skip=${skip}`
33
80
  );
81
+
34
82
  const json = await res.json();
35
83
  return json.todos;
36
84
  },
@@ -39,39 +87,192 @@ function App() {
39
87
  type: "page",
40
88
  pageSize: 20,
41
89
  },
90
+ });
91
+
92
+ return null;
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Using with Total Count (Recommended)
99
+
100
+ For accurate pagination behavior, return `{ data, total }`:
101
+
102
+ ```tsx
103
+ const { data } = useResource({
104
+ source: async ({ page = 1, pageSize = 10 }) => {
105
+ const skip = (page - 1) * pageSize;
106
+
107
+ const res = await fetch(
108
+ `https://dummyjson.com/todos?limit=${pageSize}&skip=${skip}`
109
+ );
110
+
111
+ const json = await res.json();
112
+
113
+ return {
114
+ data: json.todos,
115
+ total: json.total,
116
+ };
117
+ },
118
+
119
+ pagination: {
120
+ type: "page",
121
+ pageSize: 20,
122
+ },
123
+ });
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Pagination Modes
129
+
130
+ ### Page-based
131
+
132
+ ```ts
133
+ pagination: {
134
+ type: "page",
135
+ pageSize: 20,
136
+ }
137
+ ```
138
+
139
+ You control navigation using `page` and `setPage`.
140
+
141
+ ---
142
+
143
+ ### Load More
144
+
145
+ ```ts
146
+ pagination: {
147
+ type: "loadmore",
148
+ pageSize: 20,
149
+ }
150
+ ```
151
+
152
+ Append data on button click.
153
+
154
+ ---
155
+
156
+ ### Infinite Scroll
157
+
158
+ ```ts
159
+ pagination: {
160
+ type: "infinite",
161
+ pageSize: 20,
162
+ }
163
+ ```
164
+
165
+ Automatically fetch next page when scrolling near the bottom.
166
+
167
+ ---
168
+
169
+ ## Using with DataTable
170
+
171
+ ```tsx
172
+ import { useResource, DataTable } from "react-resource-ui";
173
+
174
+ function App() {
175
+ const {
176
+ data,
177
+ loading,
178
+ error,
179
+ page,
180
+ setPage,
181
+ setScrollTop,
182
+ offsetY,
183
+ totalHeight,
184
+ totalItems,
185
+ scrollRef,
186
+ hasNext,
187
+ } = useResource({
188
+ source: async ({ page = 1, pageSize = 20 }) => {
189
+ const skip = (page - 1) * pageSize;
190
+
191
+ const res = await fetch(
192
+ `https://dummyjson.com/todos?limit=${pageSize}&skip=${skip}`
193
+ );
194
+
195
+ const json = await res.json();
196
+
197
+ return {
198
+ data: json.todos,
199
+ total: json.total,
200
+ };
201
+ },
202
+
203
+ pagination: {
204
+ type: "page",
205
+ pageSize: 20,
206
+ },
42
207
 
43
208
  virtualization: {
44
209
  enabled: true,
45
- itemHeight: 40,
46
- containerHeight: 400,
210
+ itemHeight: 50,
211
+ containerHeight: 300,
47
212
  },
48
213
  });
49
214
 
50
- return null;
215
+ return (
216
+ <DataTable
217
+ data={data}
218
+ loading={loading}
219
+ error={error}
220
+ page={page}
221
+ setPage={setPage}
222
+ setScrollTop={setScrollTop}
223
+ type="page"
224
+ virtualization={true}
225
+ offsetY={offsetY}
226
+ totalHeight={totalHeight}
227
+ totalItems={totalItems}
228
+ scrollRef={scrollRef}
229
+ hasNext={hasNext}
230
+ />
231
+ );
51
232
  }
233
+ ```
52
234
 
53
235
  ---
54
236
 
55
- ## Pagination Modes
237
+ ## Virtualization
238
+
239
+ ```ts
240
+ virtualization: {
241
+ enabled: true,
242
+ itemHeight: 50,
243
+ containerHeight: 300,
244
+ }
245
+ ```
56
246
 
57
- The same logic can be reused across different pagination strategies by updating configuration only.
247
+ - `itemHeight` height of each row (must match UI)
248
+ - `containerHeight` → visible scroll container height
249
+
250
+ ---
58
251
 
59
- Page-based:
60
- pagination: { type: "page" }
252
+ ## Returned Values
61
253
 
62
- Load more:
63
- pagination: { type: "loadmore" }
254
+ `useResource` returns:
64
255
 
65
- Infinite scroll:
66
- pagination: { type: "infinite" }
256
+ - `data` → current visible data
257
+ - `loading` request state
258
+ - `error` → error state
259
+ - `page` → current page
260
+ - `setPage` → update page
261
+ - `setScrollTop` → update scroll position
262
+ - `offsetY` → virtualization offset
263
+ - `totalHeight` → total virtual height
264
+ - `totalItems` → total items loaded
265
+ - `scrollRef` → scroll container ref
266
+ - `hasNext` → whether next page exists
67
267
 
68
268
  ---
69
269
 
70
270
  ## Features
71
271
 
72
- - Unified API for multiple pagination strategies
73
- - Built-in virtualization support
74
- - Works with async functions, URLs, or static data sources
272
+ - Unified API for pagination strategies
273
+ - Page-based, load more, and infinite scroll support
274
+ - Built-in virtualization
275
+ - Works with async functions, URLs, or static data
75
276
  - Request deduplication using request tracking
76
277
  - Lightweight page-based caching
77
278
  - Designed for table and list UIs
@@ -82,22 +283,22 @@ pagination: { type: "infinite" }
82
283
 
83
284
  - Reduce UI-specific data handling complexity
84
285
  - Avoid rewriting logic when changing pagination behavior
85
- - Provide a higher-level abstraction over common data-fetching patterns
286
+ - Provide a higher-level abstraction over common frontend patterns
86
287
  - Keep configuration simple and predictable
87
288
 
88
289
  ---
89
290
 
90
291
  ## Status
91
292
 
92
- Version: 0.1.0
293
+ Version: 0.1.x
93
294
 
94
- This is an early release focused on core functionality.
95
- Additional testing and edge case handling are in progress.
295
+ This is an early release focused on core pagination and virtualization functionality. Improvements and edge case handling are in progress.
96
296
 
97
297
  ---
98
298
 
99
299
  ## Roadmap
100
300
 
301
+ - Grid-based virtualized rendering
101
302
  - Sorting and filtering support
102
303
  - Form integration
103
304
  - Improved caching strategies
package/dist/index.cjs CHANGED
@@ -212,16 +212,16 @@ function DataTable(props) {
212
212
  const offsetY = props.offsetY ?? 0;
213
213
  const totalHeight = props.totalHeight ?? 0;
214
214
  const itemHeight = 50;
215
- const colCount = data[0] ? Object.keys(data[0]).length : 1;
215
+ const columns = data[0] ? Object.keys(data[0]) : [];
216
216
  if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "Loading..." });
217
217
  if (error) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: error.message });
218
218
  if ((props.totalItems ?? data.length) === 0)
219
219
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "No Data to create Table" });
220
220
  const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { children: [
221
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: Object.keys(data[0]).map((val) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: val }, val)) }) }),
221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: columns.map((val) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: val }, val)) }) }),
222
222
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tbody", { children: [
223
- virtualization && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { style: { height: offsetY }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { colSpan: colCount }) }),
224
- data.map((val, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: Object.keys(val).map((key) => {
223
+ virtualization && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { style: { height: offsetY }, children: columns.map((key) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {}, key)) }),
224
+ data.map((val, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: columns.map((key) => {
225
225
  const value = val[key];
226
226
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "cell", children: value != null ? value.toString() : "-" }) }, key);
227
227
  }) }, index)),
@@ -229,9 +229,12 @@ function DataTable(props) {
229
229
  "tr",
230
230
  {
231
231
  style: {
232
- height: totalHeight - offsetY - data.length * itemHeight
232
+ height: Math.max(
233
+ 0,
234
+ totalHeight - offsetY - data.length * itemHeight
235
+ )
233
236
  },
234
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { colSpan: colCount })
237
+ children: columns.map((key) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {}, key))
235
238
  }
236
239
  )
237
240
  ] })
package/dist/index.js CHANGED
@@ -185,16 +185,16 @@ function DataTable(props) {
185
185
  const offsetY = props.offsetY ?? 0;
186
186
  const totalHeight = props.totalHeight ?? 0;
187
187
  const itemHeight = 50;
188
- const colCount = data[0] ? Object.keys(data[0]).length : 1;
188
+ const columns = data[0] ? Object.keys(data[0]) : [];
189
189
  if (loading) return /* @__PURE__ */ jsx("div", { children: "Loading..." });
190
190
  if (error) return /* @__PURE__ */ jsx("div", { children: error.message });
191
191
  if ((props.totalItems ?? data.length) === 0)
192
192
  return /* @__PURE__ */ jsx("p", { children: "No Data to create Table" });
193
193
  const content = /* @__PURE__ */ jsxs("table", { children: [
194
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: Object.keys(data[0]).map((val) => /* @__PURE__ */ jsx("th", { children: val }, val)) }) }),
194
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((val) => /* @__PURE__ */ jsx("th", { children: val }, val)) }) }),
195
195
  /* @__PURE__ */ jsxs("tbody", { children: [
196
- virtualization && /* @__PURE__ */ jsx("tr", { style: { height: offsetY }, children: /* @__PURE__ */ jsx("td", { colSpan: colCount }) }),
197
- data.map((val, index) => /* @__PURE__ */ jsx("tr", { children: Object.keys(val).map((key) => {
196
+ virtualization && /* @__PURE__ */ jsx("tr", { style: { height: offsetY }, children: columns.map((key) => /* @__PURE__ */ jsx("td", {}, key)) }),
197
+ data.map((val, index) => /* @__PURE__ */ jsx("tr", { children: columns.map((key) => {
198
198
  const value = val[key];
199
199
  return /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("div", { className: "cell", children: value != null ? value.toString() : "-" }) }, key);
200
200
  }) }, index)),
@@ -202,9 +202,12 @@ function DataTable(props) {
202
202
  "tr",
203
203
  {
204
204
  style: {
205
- height: totalHeight - offsetY - data.length * itemHeight
205
+ height: Math.max(
206
+ 0,
207
+ totalHeight - offsetY - data.length * itemHeight
208
+ )
206
209
  },
207
- children: /* @__PURE__ */ jsx("td", { colSpan: colCount })
210
+ children: columns.map((key) => /* @__PURE__ */ jsx("td", {}, key))
208
211
  }
209
212
  )
210
213
  ] })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-resource-ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "A high-level data orchestration hook for React with pagination, caching, and virtualization",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",