@soulbatical/tetra-ui 0.1.13 → 0.1.15
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/dist/components/InfiniteGrid.d.ts +62 -0
- package/dist/components/InfiniteGrid.d.ts.map +1 -0
- package/dist/components/InfiniteGrid.js +65 -0
- package/dist/components/InfiniteGrid.js.map +1 -0
- package/dist/components/ListDetailLayout.d.ts +85 -0
- package/dist/components/ListDetailLayout.d.ts.map +1 -0
- package/dist/components/ListDetailLayout.js +113 -0
- package/dist/components/ListDetailLayout.js.map +1 -0
- package/dist/hooks/useInfiniteList.d.ts +69 -0
- package/dist/hooks/useInfiniteList.d.ts.map +1 -0
- package/dist/hooks/useInfiniteList.js +131 -0
- package/dist/hooks/useInfiniteList.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React, { type ReactNode } from "react";
|
|
2
|
+
export interface InfiniteGridProps<TItem> {
|
|
3
|
+
/** Items to render */
|
|
4
|
+
items: TItem[];
|
|
5
|
+
/** Render function for each item */
|
|
6
|
+
renderItem: (item: TItem, index: number) => ReactNode;
|
|
7
|
+
/** Number of grid columns (responsive: 1 → sm → lg) */
|
|
8
|
+
columns?: 1 | 2 | 3 | 4;
|
|
9
|
+
/** Gap between items (Tailwind gap class number) */
|
|
10
|
+
gap?: 4 | 6 | 8;
|
|
11
|
+
/** Show initial loading state */
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
/** Show loading-more indicator at bottom */
|
|
14
|
+
loadingMore?: boolean;
|
|
15
|
+
/** Whether more items can be loaded */
|
|
16
|
+
hasMore?: boolean;
|
|
17
|
+
/** Sentinel ref from useInfiniteScroll */
|
|
18
|
+
sentinelRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
|
|
19
|
+
/** Number of skeleton cards to show during initial load */
|
|
20
|
+
skeletonCount?: number;
|
|
21
|
+
/** Custom skeleton element (default: animated gray box) */
|
|
22
|
+
renderSkeleton?: () => ReactNode;
|
|
23
|
+
/** Skeleton aspect ratio class (default: "aspect-square") */
|
|
24
|
+
skeletonAspect?: string;
|
|
25
|
+
/** Message when no items */
|
|
26
|
+
emptyMessage?: string;
|
|
27
|
+
/** Custom empty state */
|
|
28
|
+
emptyState?: ReactNode;
|
|
29
|
+
/** Total item count (for "Showing X of Y" text) */
|
|
30
|
+
totalCount?: number;
|
|
31
|
+
/** Entity name for display (e.g., "styles", "ads") */
|
|
32
|
+
entityName?: string;
|
|
33
|
+
/** Additional CSS class for the grid container */
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* InfiniteGrid — Responsive grid with built-in infinite scroll, skeletons, and empty state.
|
|
38
|
+
*
|
|
39
|
+
* Replaces the pattern of: manual grid + IntersectionObserver + skeleton array + empty div.
|
|
40
|
+
* Pair with `useInfiniteScroll` or `useInfiniteList` hook.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* import { InfiniteGrid, useInfiniteScroll } from '@soulbatical/tetra-ui';
|
|
45
|
+
*
|
|
46
|
+
* const { sentinelRef } = useInfiniteScroll({ onLoadMore: loadMore, hasMore });
|
|
47
|
+
*
|
|
48
|
+
* <InfiniteGrid
|
|
49
|
+
* items={styles}
|
|
50
|
+
* renderItem={(style) => <StyleCard key={style.id} style={style} />}
|
|
51
|
+
* columns={3}
|
|
52
|
+
* loading={loading}
|
|
53
|
+
* loadingMore={loadingMore}
|
|
54
|
+
* hasMore={hasMore}
|
|
55
|
+
* sentinelRef={sentinelRef}
|
|
56
|
+
* totalCount={total}
|
|
57
|
+
* entityName="styles"
|
|
58
|
+
* />
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function InfiniteGrid<TItem>({ items, renderItem, columns, gap, loading, loadingMore, hasMore, sentinelRef, skeletonCount, renderSkeleton, skeletonAspect, emptyMessage, emptyState, totalCount, entityName, className, }: InfiniteGridProps<TItem>): import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
//# sourceMappingURL=InfiniteGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfiniteGrid.d.ts","sourceRoot":"","sources":["../../src/components/InfiniteGrid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI9C,MAAM,WAAW,iBAAiB,CAAC,KAAK;IACtC,sBAAsB;IACtB,KAAK,EAAE,KAAK,EAAE,CAAC;IAEf,oCAAoC;IACpC,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAEtD,uDAAuD;IACvD,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAExB,oDAAoD;IACpD,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEhB,iCAAiC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;IAExF,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,SAAS,CAAC;IAEjC,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,4BAA4B;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yBAAyB;IACzB,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,EAClC,KAAK,EACL,UAAU,EACV,OAAW,EACX,GAAO,EACP,OAAe,EACf,WAAmB,EACnB,OAAe,EACf,WAAW,EACX,aAAiB,EACjB,cAAc,EACd,cAAgC,EAChC,YAA+B,EAC/B,UAAU,EACV,UAAU,EACV,UAAoB,EACpB,SAAS,GACV,EAAE,iBAAiB,CAAC,KAAK,CAAC,2CAkD1B"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import React from "react";
|
|
4
|
+
// ─── Column class mapping ───────────────────────────────────
|
|
5
|
+
const GRID_COLS = {
|
|
6
|
+
1: "grid-cols-1",
|
|
7
|
+
2: "grid-cols-1 sm:grid-cols-2",
|
|
8
|
+
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
9
|
+
4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
10
|
+
};
|
|
11
|
+
const GAP_CLASSES = {
|
|
12
|
+
4: "gap-4",
|
|
13
|
+
6: "gap-6",
|
|
14
|
+
8: "gap-8",
|
|
15
|
+
};
|
|
16
|
+
// ─── Default Skeleton ───────────────────────────────────────
|
|
17
|
+
function DefaultSkeleton({ aspect }) {
|
|
18
|
+
return (_jsx("div", { className: `${aspect} animate-pulse rounded-xl bg-gray-200 dark:bg-gray-800` }));
|
|
19
|
+
}
|
|
20
|
+
// ─── Loading More Indicator ─────────────────────────────────
|
|
21
|
+
function LoadingMoreIndicator({ entityName }) {
|
|
22
|
+
return (_jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-400", children: [_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-blue-500" }), "Loading more ", entityName, "..."] }));
|
|
23
|
+
}
|
|
24
|
+
// ─── Component ──────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* InfiniteGrid — Responsive grid with built-in infinite scroll, skeletons, and empty state.
|
|
27
|
+
*
|
|
28
|
+
* Replaces the pattern of: manual grid + IntersectionObserver + skeleton array + empty div.
|
|
29
|
+
* Pair with `useInfiniteScroll` or `useInfiniteList` hook.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* import { InfiniteGrid, useInfiniteScroll } from '@soulbatical/tetra-ui';
|
|
34
|
+
*
|
|
35
|
+
* const { sentinelRef } = useInfiniteScroll({ onLoadMore: loadMore, hasMore });
|
|
36
|
+
*
|
|
37
|
+
* <InfiniteGrid
|
|
38
|
+
* items={styles}
|
|
39
|
+
* renderItem={(style) => <StyleCard key={style.id} style={style} />}
|
|
40
|
+
* columns={3}
|
|
41
|
+
* loading={loading}
|
|
42
|
+
* loadingMore={loadingMore}
|
|
43
|
+
* hasMore={hasMore}
|
|
44
|
+
* sentinelRef={sentinelRef}
|
|
45
|
+
* totalCount={total}
|
|
46
|
+
* entityName="styles"
|
|
47
|
+
* />
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function InfiniteGrid({ items, renderItem, columns = 3, gap = 6, loading = false, loadingMore = false, hasMore = false, sentinelRef, skeletonCount = 6, renderSkeleton, skeletonAspect = "aspect-square", emptyMessage = "No items found", emptyState, totalCount, entityName = "items", className, }) {
|
|
51
|
+
const gridClass = `grid ${GRID_COLS[columns]} ${GAP_CLASSES[gap]} ${className ?? ""}`.trim();
|
|
52
|
+
// ─── Initial Loading ──────────────────────────────
|
|
53
|
+
if (loading) {
|
|
54
|
+
return (_jsx("div", { className: gridClass, children: Array.from({ length: skeletonCount }).map((_, i) => renderSkeleton ? (_jsx(React.Fragment, { children: renderSkeleton() }, i)) : (_jsx(DefaultSkeleton, { aspect: skeletonAspect }, i))) }));
|
|
55
|
+
}
|
|
56
|
+
// ─── Empty State ──────────────────────────────────
|
|
57
|
+
if (items.length === 0) {
|
|
58
|
+
if (emptyState)
|
|
59
|
+
return _jsx(_Fragment, { children: emptyState });
|
|
60
|
+
return (_jsx("div", { className: "rounded-lg border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-6 py-16 text-center", children: _jsx("p", { className: "text-sm text-gray-500", children: emptyMessage }) }));
|
|
61
|
+
}
|
|
62
|
+
// ─── Grid + Sentinel ──────────────────────────────
|
|
63
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: gridClass, children: items.map((item, index) => renderItem(item, index)) }), hasMore && sentinelRef && (_jsx("div", { ref: sentinelRef, className: "mt-8 flex justify-center py-8", children: loadingMore && _jsx(LoadingMoreIndicator, { entityName: entityName }) })), !hasMore && items.length > 0 && totalCount !== undefined && (_jsxs("p", { className: "mt-8 text-center text-xs text-gray-400", children: ["All ", totalCount, " ", entityName, " loaded"] }))] }));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=InfiniteGrid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfiniteGrid.js","sourceRoot":"","sources":["../../src/components/InfiniteGrid.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React, { type ReactNode } from "react";
|
|
2
|
+
export interface ListDetailLayoutProps<TItem> {
|
|
3
|
+
/** Items to display in the list */
|
|
4
|
+
items: TItem[];
|
|
5
|
+
/** Extract unique ID from item */
|
|
6
|
+
getItemId: (item: TItem) => string;
|
|
7
|
+
/** Render a single list row */
|
|
8
|
+
renderListItem: (item: TItem, isSelected: boolean) => ReactNode;
|
|
9
|
+
/** Render the detail panel for the selected item */
|
|
10
|
+
renderDetail: (item: TItem) => ReactNode;
|
|
11
|
+
/** Currently selected item ID (controlled) */
|
|
12
|
+
selectedId?: string | null;
|
|
13
|
+
/** Called when an item is selected */
|
|
14
|
+
onSelect: (id: string | null) => void;
|
|
15
|
+
/** Action buttons at the bottom of the detail panel */
|
|
16
|
+
actions?: (item: TItem) => ReactNode;
|
|
17
|
+
/** Enable keyboard navigation with arrow keys (default: true) */
|
|
18
|
+
keyboardNav?: boolean;
|
|
19
|
+
/** Width of the detail panel (Tailwind class, default: "flex-1") */
|
|
20
|
+
detailWidth?: string;
|
|
21
|
+
/** Width of the list when detail is open (Tailwind class, default: "w-[320px] min-w-[320px]") */
|
|
22
|
+
listCompactWidth?: string;
|
|
23
|
+
/** Title shown above the list */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** Subtitle / count indicator */
|
|
26
|
+
subtitle?: string;
|
|
27
|
+
/** Header actions (create button, etc.) */
|
|
28
|
+
headerActions?: ReactNode;
|
|
29
|
+
/** Show loading state */
|
|
30
|
+
loading?: boolean;
|
|
31
|
+
/** Empty state when no items */
|
|
32
|
+
emptyMessage?: string;
|
|
33
|
+
/** Infinite scroll sentinel ref */
|
|
34
|
+
sentinelRef?: React.RefObject<HTMLDivElement> | ((node: HTMLDivElement | null) => void);
|
|
35
|
+
/** Whether more items can be loaded */
|
|
36
|
+
hasMore?: boolean;
|
|
37
|
+
/** Loading more indicator */
|
|
38
|
+
loadingMore?: boolean;
|
|
39
|
+
/** Additional CSS class for the outer container */
|
|
40
|
+
className?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* ListDetailLayout — Master-detail split view (Pipedrive-style).
|
|
44
|
+
*
|
|
45
|
+
* Shows a scrollable list on the left. Clicking an item opens a detail
|
|
46
|
+
* panel on the right with a slide-in animation. Arrow keys navigate
|
|
47
|
+
* between items while the detail panel stays open.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* import { ListDetailLayout } from '@soulbatical/tetra-ui';
|
|
52
|
+
*
|
|
53
|
+
* const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
54
|
+
*
|
|
55
|
+
* <ListDetailLayout
|
|
56
|
+
* items={leads}
|
|
57
|
+
* getItemId={(lead) => lead.id}
|
|
58
|
+
* selectedId={selectedId}
|
|
59
|
+
* onSelect={setSelectedId}
|
|
60
|
+
* renderListItem={(lead, isSelected) => (
|
|
61
|
+
* <div className={isSelected ? 'bg-blue-50' : ''}>
|
|
62
|
+
* <p className="font-medium">{lead.name}</p>
|
|
63
|
+
* <p className="text-sm text-gray-500">{lead.company}</p>
|
|
64
|
+
* </div>
|
|
65
|
+
* )}
|
|
66
|
+
* renderDetail={(lead) => (
|
|
67
|
+
* <div>
|
|
68
|
+
* <h2>{lead.name}</h2>
|
|
69
|
+
* <p>{lead.email}</p>
|
|
70
|
+
* <p>{lead.phone}</p>
|
|
71
|
+
* </div>
|
|
72
|
+
* )}
|
|
73
|
+
* actions={(lead) => (
|
|
74
|
+
* <>
|
|
75
|
+
* <button onClick={() => archive(lead.id)}>Archive</button>
|
|
76
|
+
* <button onClick={() => convert(lead.id)}>Convert to Deal</button>
|
|
77
|
+
* </>
|
|
78
|
+
* )}
|
|
79
|
+
* title="Leads Inbox"
|
|
80
|
+
* subtitle="198 leads"
|
|
81
|
+
* />
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function ListDetailLayout<TItem>({ items, getItemId, renderListItem, renderDetail, selectedId, onSelect, actions, keyboardNav, detailWidth, listCompactWidth, title, subtitle, headerActions, loading, emptyMessage, sentinelRef, hasMore, loadingMore, className, }: ListDetailLayoutProps<TItem>): import("react/jsx-runtime").JSX.Element;
|
|
85
|
+
//# sourceMappingURL=ListDetailLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListDetailLayout.d.ts","sourceRoot":"","sources":["../../src/components/ListDetailLayout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAkC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI9E,MAAM,WAAW,qBAAqB,CAAC,KAAK;IAC1C,mCAAmC;IACnC,KAAK,EAAE,KAAK,EAAE,CAAC;IAEf,kCAAkC;IAClC,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,CAAC;IAEnC,+BAA+B;IAC/B,cAAc,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,KAAK,SAAS,CAAC;IAEhE,oDAAoD;IACpD,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC;IAEzC,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,sCAAsC;IACtC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAEtC,uDAAuD;IACvD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC;IAErC,iEAAiE;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,iGAAiG;IACjG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,SAAS,CAAC;IAE1B,yBAAyB;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,mCAAmC;IACnC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;IAExF,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,EACtC,KAAK,EACL,SAAS,EACT,cAAc,EACd,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,OAAO,EACP,WAAkB,EAClB,WAAsB,EACtB,gBAA4C,EAC5C,KAAK,EACL,QAAQ,EACR,aAAa,EACb,OAAe,EACf,YAA+B,EAC/B,WAAW,EACX,OAAe,EACf,WAAmB,EACnB,SAAS,GACV,EAAE,qBAAqB,CAAC,KAAK,CAAC,2CA6L9B"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useCallback, useRef } from "react";
|
|
4
|
+
// ─── Close Icon ─────────────────────────────────────────────
|
|
5
|
+
function CloseIcon() {
|
|
6
|
+
return (_jsx("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }));
|
|
7
|
+
}
|
|
8
|
+
function ChevronUpIcon() {
|
|
9
|
+
return (_jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 15.75l7.5-7.5 7.5 7.5" }) }));
|
|
10
|
+
}
|
|
11
|
+
function ChevronDownIcon() {
|
|
12
|
+
return (_jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: 2, stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" }) }));
|
|
13
|
+
}
|
|
14
|
+
// ─── Component ──────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* ListDetailLayout — Master-detail split view (Pipedrive-style).
|
|
17
|
+
*
|
|
18
|
+
* Shows a scrollable list on the left. Clicking an item opens a detail
|
|
19
|
+
* panel on the right with a slide-in animation. Arrow keys navigate
|
|
20
|
+
* between items while the detail panel stays open.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { ListDetailLayout } from '@soulbatical/tetra-ui';
|
|
25
|
+
*
|
|
26
|
+
* const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
27
|
+
*
|
|
28
|
+
* <ListDetailLayout
|
|
29
|
+
* items={leads}
|
|
30
|
+
* getItemId={(lead) => lead.id}
|
|
31
|
+
* selectedId={selectedId}
|
|
32
|
+
* onSelect={setSelectedId}
|
|
33
|
+
* renderListItem={(lead, isSelected) => (
|
|
34
|
+
* <div className={isSelected ? 'bg-blue-50' : ''}>
|
|
35
|
+
* <p className="font-medium">{lead.name}</p>
|
|
36
|
+
* <p className="text-sm text-gray-500">{lead.company}</p>
|
|
37
|
+
* </div>
|
|
38
|
+
* )}
|
|
39
|
+
* renderDetail={(lead) => (
|
|
40
|
+
* <div>
|
|
41
|
+
* <h2>{lead.name}</h2>
|
|
42
|
+
* <p>{lead.email}</p>
|
|
43
|
+
* <p>{lead.phone}</p>
|
|
44
|
+
* </div>
|
|
45
|
+
* )}
|
|
46
|
+
* actions={(lead) => (
|
|
47
|
+
* <>
|
|
48
|
+
* <button onClick={() => archive(lead.id)}>Archive</button>
|
|
49
|
+
* <button onClick={() => convert(lead.id)}>Convert to Deal</button>
|
|
50
|
+
* </>
|
|
51
|
+
* )}
|
|
52
|
+
* title="Leads Inbox"
|
|
53
|
+
* subtitle="198 leads"
|
|
54
|
+
* />
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function ListDetailLayout({ items, getItemId, renderListItem, renderDetail, selectedId, onSelect, actions, keyboardNav = true, detailWidth = "flex-1", listCompactWidth = "w-[320px] min-w-[320px]", title, subtitle, headerActions, loading = false, emptyMessage = "No items found", sentinelRef, hasMore = false, loadingMore = false, className, }) {
|
|
58
|
+
const listRef = useRef(null);
|
|
59
|
+
const selectedItem = items.find((item) => getItemId(item) === selectedId);
|
|
60
|
+
const isDetailOpen = selectedId !== null && selectedItem !== undefined;
|
|
61
|
+
// ─── Keyboard Navigation ──────────────────────────
|
|
62
|
+
const navigateToItem = useCallback((direction) => {
|
|
63
|
+
if (!selectedId || items.length === 0)
|
|
64
|
+
return;
|
|
65
|
+
const currentIndex = items.findIndex((item) => getItemId(item) === selectedId);
|
|
66
|
+
if (currentIndex === -1)
|
|
67
|
+
return;
|
|
68
|
+
const nextIndex = direction === "up"
|
|
69
|
+
? Math.max(0, currentIndex - 1)
|
|
70
|
+
: Math.min(items.length - 1, currentIndex + 1);
|
|
71
|
+
if (nextIndex !== currentIndex) {
|
|
72
|
+
onSelect(getItemId(items[nextIndex]));
|
|
73
|
+
// Scroll the selected item into view in the list
|
|
74
|
+
const listEl = listRef.current;
|
|
75
|
+
if (listEl) {
|
|
76
|
+
const itemEl = listEl.querySelector(`[data-item-id="${getItemId(items[nextIndex])}"]`);
|
|
77
|
+
itemEl?.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}, [items, selectedId, getItemId, onSelect]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!keyboardNav || !isDetailOpen)
|
|
83
|
+
return;
|
|
84
|
+
const handleKeyDown = (e) => {
|
|
85
|
+
if (e.key === "ArrowUp") {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
navigateToItem("up");
|
|
88
|
+
}
|
|
89
|
+
else if (e.key === "ArrowDown") {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
navigateToItem("down");
|
|
92
|
+
}
|
|
93
|
+
else if (e.key === "Escape") {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
onSelect(null);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
99
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
100
|
+
}, [keyboardNav, isDetailOpen, navigateToItem, onSelect]);
|
|
101
|
+
// ─── Loading State ────────────────────────────────
|
|
102
|
+
if (loading) {
|
|
103
|
+
return (_jsx("div", { className: `flex h-full ${className ?? ""}`, children: _jsx("div", { className: "flex-1 p-6", children: _jsx("div", { className: "space-y-3", children: Array.from({ length: 8 }).map((_, i) => (_jsx("div", { className: "h-16 animate-pulse rounded-lg bg-gray-200 dark:bg-gray-800" }, i))) }) }) }));
|
|
104
|
+
}
|
|
105
|
+
return (_jsxs("div", { className: `flex h-full overflow-hidden ${className ?? ""}`, children: [_jsxs("div", { ref: listRef, className: `flex flex-col border-r border-gray-200 dark:border-gray-700 overflow-y-auto transition-all duration-300 ${isDetailOpen ? listCompactWidth : "flex-1"}`, children: [(title || headerActions) && (_jsxs("div", { className: "sticky top-0 z-10 flex items-center justify-between border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 px-4 py-3", children: [_jsxs("div", { children: [title && (_jsx("h2", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: title })), subtitle && (_jsx("p", { className: "text-xs text-gray-500", children: subtitle }))] }), headerActions] })), items.length === 0 ? (_jsx("div", { className: "flex-1 flex items-center justify-center p-8", children: _jsx("p", { className: "text-sm text-gray-500", children: emptyMessage }) })) : (_jsxs("div", { className: "flex-1", children: [items.map((item) => {
|
|
106
|
+
const id = getItemId(item);
|
|
107
|
+
const isSelected = id === selectedId;
|
|
108
|
+
return (_jsx("button", { type: "button", "data-item-id": id, onClick: () => onSelect(isSelected ? null : id), className: `w-full text-left px-4 py-3 border-b border-gray-100 dark:border-gray-800 transition-colors ${isSelected
|
|
109
|
+
? "bg-blue-50 dark:bg-blue-900/30 border-l-[3px] border-l-blue-500 pl-[13px]"
|
|
110
|
+
: "hover:bg-gray-50 dark:hover:bg-gray-800/50"}`, children: renderListItem(item, isSelected) }, id));
|
|
111
|
+
}), hasMore && sentinelRef && (_jsx("div", { ref: sentinelRef, className: "py-4 flex justify-center", children: loadingMore && (_jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-blue-500" })) }))] }))] }), _jsx("div", { className: `flex flex-col overflow-hidden border-l border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 transition-all duration-300 ${isDetailOpen ? `${detailWidth} opacity-100` : "w-0 border-l-0 opacity-0"}`, children: selectedItem && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-200 dark:border-gray-700 px-4 py-3", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => navigateToItem("up"), className: "rounded-md p-1.5 text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-700 disabled:opacity-30 transition-colors", disabled: items.findIndex((item) => getItemId(item) === selectedId) === 0, "aria-label": "Previous item", children: _jsx(ChevronUpIcon, {}) }), _jsx("button", { type: "button", onClick: () => navigateToItem("down"), className: "rounded-md p-1.5 text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-700 disabled:opacity-30 transition-colors", disabled: items.findIndex((item) => getItemId(item) === selectedId) === items.length - 1, "aria-label": "Next item", children: _jsx(ChevronDownIcon, {}) })] }), _jsx("button", { type: "button", onClick: () => onSelect(null), className: "rounded-md p-1.5 text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-700 transition-colors", "aria-label": "Close detail", children: _jsx(CloseIcon, {}) })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: renderDetail(selectedItem) }), actions && (_jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 px-4 py-3 flex items-center gap-3", children: actions(selectedItem) }))] })) })] }));
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=ListDetailLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListDetailLayout.js","sourceRoot":"","sources":["../../src/components/ListDetailLayout.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface UseInfiniteListOptions<TFilters extends Record<string, string>> {
|
|
2
|
+
/** API endpoint (e.g., '/api/admin/style-library') */
|
|
3
|
+
endpoint: string;
|
|
4
|
+
/** Items per page (default: 30) */
|
|
5
|
+
limit?: number;
|
|
6
|
+
/** Filter values — refetches from offset 0 when changed */
|
|
7
|
+
filters?: TFilters;
|
|
8
|
+
/** Enable/disable (default: true) */
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Key in the response data object that holds the items array.
|
|
12
|
+
* Default: "items". Examples: "styles", "ads", "items"
|
|
13
|
+
*/
|
|
14
|
+
dataKey?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Key in the response data object that holds the total count.
|
|
17
|
+
* Default: "total"
|
|
18
|
+
*/
|
|
19
|
+
totalKey?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface UseInfiniteListResult<TItem> {
|
|
22
|
+
/** Accumulated items across all loaded pages */
|
|
23
|
+
items: TItem[];
|
|
24
|
+
/** Total count of items matching filters (from server) */
|
|
25
|
+
total: number;
|
|
26
|
+
/** Initial loading (first page) */
|
|
27
|
+
loading: boolean;
|
|
28
|
+
/** Loading additional pages */
|
|
29
|
+
loadingMore: boolean;
|
|
30
|
+
/** Whether more items can be loaded */
|
|
31
|
+
hasMore: boolean;
|
|
32
|
+
/** Sentinel ref to attach to the scroll trigger element */
|
|
33
|
+
sentinelRef: (node: HTMLDivElement | null) => void;
|
|
34
|
+
/** Manually trigger a refresh (resets to page 0) */
|
|
35
|
+
refresh: () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* useInfiniteList — Simple infinite scroll hook for REST API endpoints.
|
|
39
|
+
*
|
|
40
|
+
* A lighter alternative to `useGenericList` for pages that don't have a
|
|
41
|
+
* full FeatureConfig. Just point it at an API endpoint and it handles
|
|
42
|
+
* pagination, filter resets, and IntersectionObserver automatically.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* import { useInfiniteList, InfiniteGrid } from '@soulbatical/tetra-ui';
|
|
47
|
+
*
|
|
48
|
+
* const { items, loading, loadingMore, hasMore, sentinelRef, total } = useInfiniteList<Style>({
|
|
49
|
+
* endpoint: '/api/admin/style-library',
|
|
50
|
+
* limit: 30,
|
|
51
|
+
* filters: { category, search, complexity },
|
|
52
|
+
* dataKey: 'styles',
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* return (
|
|
56
|
+
* <InfiniteGrid
|
|
57
|
+
* items={items}
|
|
58
|
+
* renderItem={(style) => <StyleCard style={style} />}
|
|
59
|
+
* loading={loading}
|
|
60
|
+
* loadingMore={loadingMore}
|
|
61
|
+
* hasMore={hasMore}
|
|
62
|
+
* sentinelRef={sentinelRef}
|
|
63
|
+
* totalCount={total}
|
|
64
|
+
* />
|
|
65
|
+
* );
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function useInfiniteList<TItem, TFilters extends Record<string, string> = Record<string, string>>({ endpoint, limit, filters, enabled, dataKey, totalKey, }: UseInfiniteListOptions<TFilters>): UseInfiniteListResult<TItem>;
|
|
69
|
+
//# sourceMappingURL=useInfiniteList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInfiniteList.d.ts","sourceRoot":"","sources":["../../src/hooks/useInfiniteList.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB,CAAC,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAC7E,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IAEjB,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,QAAQ,CAAC;IAEnB,qCAAqC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB,CAAC,KAAK;IAC1C,gDAAgD;IAChD,KAAK,EAAE,KAAK,EAAE,CAAC;IAEf,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IAEd,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IAEjB,+BAA+B;IAC/B,WAAW,EAAE,OAAO,CAAC;IAErB,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IAEjB,2DAA2D;IAC3D,WAAW,EAAE,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IAEnD,oDAAoD;IACpD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EACL,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChE,EACA,QAAQ,EACR,KAAU,EACV,OAAwB,EACxB,OAAc,EACd,OAAiB,EACjB,QAAkB,GACnB,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CA0GjE"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
3
|
+
import { apiClient } from "../services/apiClient.js";
|
|
4
|
+
import { useInfiniteScroll } from "./useInfiniteScroll.js";
|
|
5
|
+
// ─── Hook ───────────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* useInfiniteList — Simple infinite scroll hook for REST API endpoints.
|
|
8
|
+
*
|
|
9
|
+
* A lighter alternative to `useGenericList` for pages that don't have a
|
|
10
|
+
* full FeatureConfig. Just point it at an API endpoint and it handles
|
|
11
|
+
* pagination, filter resets, and IntersectionObserver automatically.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import { useInfiniteList, InfiniteGrid } from '@soulbatical/tetra-ui';
|
|
16
|
+
*
|
|
17
|
+
* const { items, loading, loadingMore, hasMore, sentinelRef, total } = useInfiniteList<Style>({
|
|
18
|
+
* endpoint: '/api/admin/style-library',
|
|
19
|
+
* limit: 30,
|
|
20
|
+
* filters: { category, search, complexity },
|
|
21
|
+
* dataKey: 'styles',
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* return (
|
|
25
|
+
* <InfiniteGrid
|
|
26
|
+
* items={items}
|
|
27
|
+
* renderItem={(style) => <StyleCard style={style} />}
|
|
28
|
+
* loading={loading}
|
|
29
|
+
* loadingMore={loadingMore}
|
|
30
|
+
* hasMore={hasMore}
|
|
31
|
+
* sentinelRef={sentinelRef}
|
|
32
|
+
* totalCount={total}
|
|
33
|
+
* />
|
|
34
|
+
* );
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export function useInfiniteList({ endpoint, limit = 30, filters = {}, enabled = true, dataKey = "items", totalKey = "total", }) {
|
|
38
|
+
const [items, setItems] = useState([]);
|
|
39
|
+
const [total, setTotal] = useState(0);
|
|
40
|
+
const [loading, setLoading] = useState(true);
|
|
41
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
42
|
+
const [hasMore, setHasMore] = useState(true);
|
|
43
|
+
const offsetRef = useRef(0);
|
|
44
|
+
const fetchingRef = useRef(false);
|
|
45
|
+
// Serialize filters for dependency tracking
|
|
46
|
+
const filterKey = JSON.stringify(filters);
|
|
47
|
+
// ─── Fetch Function ───────────────────────────────
|
|
48
|
+
const fetchPage = useCallback(async (offset, append) => {
|
|
49
|
+
if (fetchingRef.current)
|
|
50
|
+
return;
|
|
51
|
+
fetchingRef.current = true;
|
|
52
|
+
if (offset === 0)
|
|
53
|
+
setLoading(true);
|
|
54
|
+
else
|
|
55
|
+
setLoadingMore(true);
|
|
56
|
+
try {
|
|
57
|
+
const params = new URLSearchParams({
|
|
58
|
+
limit: String(limit),
|
|
59
|
+
offset: String(offset),
|
|
60
|
+
});
|
|
61
|
+
// Add non-empty filters to query
|
|
62
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
63
|
+
if (value !== undefined && value !== null && value !== "") {
|
|
64
|
+
params.set(key, value);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const url = `${endpoint}?${params.toString()}`;
|
|
68
|
+
const res = await apiClient.get(url);
|
|
69
|
+
if (res.success && res.data) {
|
|
70
|
+
const newItems = (res.data[dataKey] ?? res.data.items ?? res.data.data ?? []);
|
|
71
|
+
const serverTotal = res.data[totalKey] ??
|
|
72
|
+
res.data.total ??
|
|
73
|
+
res.data.meta?.total ??
|
|
74
|
+
0;
|
|
75
|
+
setItems((prev) => (append ? [...prev, ...newItems] : newItems));
|
|
76
|
+
setTotal(serverTotal);
|
|
77
|
+
setHasMore(offset + newItems.length < serverTotal);
|
|
78
|
+
offsetRef.current = offset + newItems.length;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// API unavailable — keep current state
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
setLoading(false);
|
|
86
|
+
setLoadingMore(false);
|
|
87
|
+
fetchingRef.current = false;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
91
|
+
[endpoint, limit, filterKey, dataKey, totalKey]);
|
|
92
|
+
// ─── Reset on filter change ───────────────────────
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (!enabled)
|
|
95
|
+
return;
|
|
96
|
+
offsetRef.current = 0;
|
|
97
|
+
setItems([]);
|
|
98
|
+
setHasMore(true);
|
|
99
|
+
fetchPage(0, false);
|
|
100
|
+
}, [enabled, fetchPage]);
|
|
101
|
+
// ─── Load More ────────────────────────────────────
|
|
102
|
+
const loadMore = useCallback(() => {
|
|
103
|
+
if (!hasMore || loading || loadingMore)
|
|
104
|
+
return;
|
|
105
|
+
fetchPage(offsetRef.current, true);
|
|
106
|
+
}, [hasMore, loading, loadingMore, fetchPage]);
|
|
107
|
+
// ─── Infinite Scroll ──────────────────────────────
|
|
108
|
+
const { sentinelRef } = useInfiniteScroll({
|
|
109
|
+
onLoadMore: loadMore,
|
|
110
|
+
hasMore,
|
|
111
|
+
threshold: 300,
|
|
112
|
+
enabled: enabled && !loading,
|
|
113
|
+
});
|
|
114
|
+
// ─── Manual Refresh ───────────────────────────────
|
|
115
|
+
const refresh = useCallback(() => {
|
|
116
|
+
offsetRef.current = 0;
|
|
117
|
+
setItems([]);
|
|
118
|
+
setHasMore(true);
|
|
119
|
+
fetchPage(0, false);
|
|
120
|
+
}, [fetchPage]);
|
|
121
|
+
return {
|
|
122
|
+
items,
|
|
123
|
+
total,
|
|
124
|
+
loading,
|
|
125
|
+
loadingMore,
|
|
126
|
+
hasMore,
|
|
127
|
+
sentinelRef,
|
|
128
|
+
refresh,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=useInfiniteList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useInfiniteList.js","sourceRoot":"","sources":["../../src/hooks/useInfiniteList.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,10 +26,13 @@ export { StatusBadge } from "./components/StatusBadge.js";
|
|
|
26
26
|
export { AutoCard, type CardConfig, type AutoCardProps, type LinkComponent } from "./components/AutoCard.js";
|
|
27
27
|
export { CookieConsent, type CookieConsentProps } from "./components/CookieConsent.js";
|
|
28
28
|
export { OAuthButtons, type OAuthButtonsProps } from "./components/OAuthButtons.js";
|
|
29
|
+
export { InfiniteGrid, type InfiniteGridProps, } from "./components/InfiniteGrid.js";
|
|
30
|
+
export { ListDetailLayout, type ListDetailLayoutProps, } from "./components/ListDetailLayout.js";
|
|
29
31
|
export { useDebounce } from "./hooks/useDebounce.js";
|
|
30
32
|
export { useDialog } from "./hooks/useDialog.js";
|
|
31
33
|
export { useIsMobile } from "./hooks/use-mobile.js";
|
|
32
34
|
export { useInfiniteScroll } from "./hooks/useInfiniteScroll.js";
|
|
35
|
+
export { useInfiniteList, type UseInfiniteListOptions, type UseInfiniteListResult, } from "./hooks/useInfiniteList.js";
|
|
33
36
|
export { useCacheInvalidation } from "./hooks/useCacheInvalidation.js";
|
|
34
37
|
export { useFormSubmit } from "./hooks/useFormSubmit.js";
|
|
35
38
|
export { useQueryState } from "./hooks/useQueryState.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -36,11 +36,15 @@ export { StatusBadge } from "./components/StatusBadge.js";
|
|
|
36
36
|
export { AutoCard } from "./components/AutoCard.js";
|
|
37
37
|
export { CookieConsent } from "./components/CookieConsent.js";
|
|
38
38
|
export { OAuthButtons } from "./components/OAuthButtons.js";
|
|
39
|
+
// Layout components
|
|
40
|
+
export { InfiniteGrid, } from "./components/InfiniteGrid.js";
|
|
41
|
+
export { ListDetailLayout, } from "./components/ListDetailLayout.js";
|
|
39
42
|
// Hooks — utility
|
|
40
43
|
export { useDebounce } from "./hooks/useDebounce.js";
|
|
41
44
|
export { useDialog } from "./hooks/useDialog.js";
|
|
42
45
|
export { useIsMobile } from "./hooks/use-mobile.js";
|
|
43
46
|
export { useInfiniteScroll } from "./hooks/useInfiniteScroll.js";
|
|
47
|
+
export { useInfiniteList, } from "./hooks/useInfiniteList.js";
|
|
44
48
|
export { useCacheInvalidation } from "./hooks/useCacheInvalidation.js";
|
|
45
49
|
export { useFormSubmit } from "./hooks/useFormSubmit.js";
|
|
46
50
|
// Hooks — query state & filters
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "restricted"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.1.
|
|
7
|
+
"version": "0.1.15",
|
|
8
8
|
"description": "Shared React frontend framework for Tetra platform projects (Soulbatical BV) — config-driven components, hooks, providers, and styling",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"main": "dist/index.js",
|