From f876ad9e581d114d47904f27d9a87c0e2a9f554c Mon Sep 17 00:00:00 2001 From: shubham-7span Date: Mon, 2 Feb 2026 19:09:20 +0530 Subject: [PATCH 1/9] Update package version to 1.0.2 and adjust build configuration for @7span/react-list --- packages/react-list/package.json | 13 ++++++++----- packages/react-list/src/index.js | 2 +- packages/react-list/vite.config.js | 12 ++++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/react-list/package.json b/packages/react-list/package.json index ebe29c5..6c06ca8 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -1,6 +1,6 @@ { "name": "@7span/react-list", - "version": "1.0.1", + "version": "1.0.2", "description": "A simple and reusable list component for React", "type": "module", "scripts": { @@ -10,13 +10,16 @@ "preview": "vite preview", "prepublishOnly": "npm run build" }, - "main": "src/index.js", + "main": "dist/react-list.js", + "module": "dist/react-list.js", "exports": { - ".": "./src/index.js" + ".": { + "import": "./dist/react-list.js", + "require": "./dist/react-list.cjs" + } }, "files": [ - "dist", - "src" + "dist" ], "peerDependencies": { "react": "^18.2.0 || ^19.0.0", diff --git a/packages/react-list/src/index.js b/packages/react-list/src/index.js index d132e3f..0748a39 100644 --- a/packages/react-list/src/index.js +++ b/packages/react-list/src/index.js @@ -4,7 +4,7 @@ export { ReactListError } from "./components/error"; export { ReactListGoTo } from "./components/go-to"; export { ReactListInitialLoader } from "./components/initial-loader"; export { ReactListItems } from "./components/items"; -export { default } from "./components/list"; +export { default as ReactList } from "./components/list"; export { ReactListLoadMore } from "./components/load-more"; export { ReactListLoader } from "./components/loader"; export { ReactListPagination } from "./components/pagination"; diff --git a/packages/react-list/vite.config.js b/packages/react-list/vite.config.js index 0d1dd24..a1037f0 100644 --- a/packages/react-list/vite.config.js +++ b/packages/react-list/vite.config.js @@ -1,25 +1,25 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; -import { createRequire } from "module"; -const require = createRequire(import.meta.url); + // https://vite.dev/config/ export default defineConfig({ plugins: [react()], build: { rollupOptions: { - external: ["react", "react/jsx-runtime"], + external: ["react", "react-dom", "react/jsx-runtime"], output: { globals: { - react: "react", + react: "React", + "react-dom": "ReactDOM", "react/jsx-runtime": "jsxRuntime", }, - exports: "named", }, }, lib: { - entry: [`src/index.js`], + entry: "src/index.js", name: "ReactList", fileName: "react-list", + formats: ["es", "cjs"], }, }, }); From 6d83bd6abfdb87fe615ec9bf7f6138765ec7bf7c Mon Sep 17 00:00:00 2001 From: shubham-7span Date: Mon, 2 Feb 2026 19:27:13 +0530 Subject: [PATCH 2/9] Refactor package.json for @7span/react-list: remove module and exports fields, retain publishConfig, and clean up dependencies. --- packages/react-list/package.json | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 6c06ca8..7423430 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -11,23 +11,16 @@ "prepublishOnly": "npm run build" }, "main": "dist/react-list.js", - "module": "dist/react-list.js", - "exports": { - ".": { - "import": "./dist/react-list.js", - "require": "./dist/react-list.cjs" - } - }, "files": [ "dist" ], + "publishConfig": { + "access": "public" + }, "peerDependencies": { "react": "^18.2.0 || ^19.0.0", "react-dom": "^18.2.0 || ^19.0.0" }, - "publishConfig": { - "access": "public" - }, "devDependencies": { "@vitejs/plugin-react": "^4.3.4", "vite": "^6.3.1" From 1392ead2b21de716ad4307a14c48fc7d4631e315 Mon Sep 17 00:00:00 2001 From: shubham-7span Date: Mon, 2 Feb 2026 19:29:18 +0530 Subject: [PATCH 3/9] Refactor export statement in index.js for @7span/react-list: simplify default export from components/list --- packages/react-list/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-list/src/index.js b/packages/react-list/src/index.js index 0748a39..d132e3f 100644 --- a/packages/react-list/src/index.js +++ b/packages/react-list/src/index.js @@ -4,7 +4,7 @@ export { ReactListError } from "./components/error"; export { ReactListGoTo } from "./components/go-to"; export { ReactListInitialLoader } from "./components/initial-loader"; export { ReactListItems } from "./components/items"; -export { default as ReactList } from "./components/list"; +export { default } from "./components/list"; export { ReactListLoadMore } from "./components/load-more"; export { ReactListLoader } from "./components/loader"; export { ReactListPagination } from "./components/pagination"; From bafe2908267536c12650cd87ec2f8b3974b54fa4 Mon Sep 17 00:00:00 2001 From: darshak-7span Date: Fri, 20 Mar 2026 18:51:44 +0530 Subject: [PATCH 4/9] Enhance playground and TypeScript setup: integrate Tailwind CSS, update dependencies, and add new components for improved list functionality. --- apps/playground-typescript/index.html | 14 + apps/playground-typescript/package.json | 29 + apps/playground-typescript/postcss.config.mjs | 6 + apps/playground-typescript/src/App.tsx | 6 + .../src/api/request-handler.ts | 87 +++ .../src/components/list-wrapper.tsx | 298 ++++++++ .../src/components/react-list.ts | 75 ++ apps/playground-typescript/src/index.css | 2 + apps/playground-typescript/src/main.tsx | 11 + apps/playground-typescript/tailwind.config.js | 8 + apps/playground-typescript/tsconfig.json | 16 + apps/playground-typescript/vite.config.ts | 7 + apps/playground/package.json | 10 +- apps/playground/postcss.config.js | 6 + .../src/components/list-wrapper.jsx | 654 ++++++++---------- apps/playground/src/index.css | 10 +- apps/playground/tailwind.config.js | 9 + packages/react-list/package.json | 21 +- .../react-list/src/components/attributes.jsx | 53 -- .../react-list/src/components/attributes.tsx | 87 +++ .../src/components/{empty.jsx => empty.tsx} | 6 +- .../src/components/{error.jsx => error.tsx} | 9 +- .../src/components/{go-to.jsx => go-to.tsx} | 20 +- .../src/components/initial-loader.jsx | 25 - .../src/components/initial-loader.tsx | 40 ++ .../src/components/{items.jsx => items.tsx} | 24 +- .../src/components/{list.jsx => list.tsx} | 94 ++- .../{load-more.jsx => load-more.tsx} | 14 +- packages/react-list/src/components/loader.jsx | 29 - packages/react-list/src/components/loader.tsx | 39 ++ .../{pagination.jsx => pagination.tsx} | 46 +- .../components/{per-page.jsx => per-page.tsx} | 48 +- .../components/{refresh.jsx => refresh.tsx} | 18 +- packages/react-list/src/components/search.jsx | 59 -- packages/react-list/src/components/search.tsx | 75 ++ .../components/{summary.jsx => summary.tsx} | 23 +- .../src/components/{utils.js => utils.ts} | 23 +- .../react-list/src/context/list-provider.jsx | 55 -- .../react-list/src/context/list-provider.tsx | 91 +++ .../react-list/src/{index.js => index.ts} | 22 + packages/react-list/src/types/index.ts | 22 + .../react-list/src/types/list-provider.ts | 156 +++++ packages/react-list/src/types/react-list.ts | 39 ++ .../react-list/src/{utils.js => utils.ts} | 0 packages/react-list/tsconfig.build.json | 18 + packages/react-list/tsconfig.json | 6 + pnpm-lock.yaml | 616 +++++++++++++++-- 47 files changed, 2303 insertions(+), 723 deletions(-) create mode 100644 apps/playground-typescript/index.html create mode 100644 apps/playground-typescript/package.json create mode 100644 apps/playground-typescript/postcss.config.mjs create mode 100644 apps/playground-typescript/src/App.tsx create mode 100644 apps/playground-typescript/src/api/request-handler.ts create mode 100644 apps/playground-typescript/src/components/list-wrapper.tsx create mode 100644 apps/playground-typescript/src/components/react-list.ts create mode 100644 apps/playground-typescript/src/index.css create mode 100644 apps/playground-typescript/src/main.tsx create mode 100644 apps/playground-typescript/tailwind.config.js create mode 100644 apps/playground-typescript/tsconfig.json create mode 100644 apps/playground-typescript/vite.config.ts create mode 100644 apps/playground/postcss.config.js create mode 100644 apps/playground/tailwind.config.js delete mode 100644 packages/react-list/src/components/attributes.jsx create mode 100644 packages/react-list/src/components/attributes.tsx rename packages/react-list/src/components/{empty.jsx => empty.tsx} (77%) rename packages/react-list/src/components/{error.jsx => error.tsx} (72%) rename packages/react-list/src/components/{go-to.jsx => go-to.tsx} (73%) delete mode 100644 packages/react-list/src/components/initial-loader.jsx create mode 100644 packages/react-list/src/components/initial-loader.tsx rename packages/react-list/src/components/{items.jsx => items.tsx} (64%) rename packages/react-list/src/components/{list.jsx => list.tsx} (81%) rename packages/react-list/src/components/{load-more.jsx => load-more.tsx} (71%) delete mode 100644 packages/react-list/src/components/loader.jsx create mode 100644 packages/react-list/src/components/loader.tsx rename packages/react-list/src/components/{pagination.jsx => pagination.tsx} (76%) rename packages/react-list/src/components/{per-page.jsx => per-page.tsx} (55%) rename packages/react-list/src/components/{refresh.jsx => refresh.tsx} (63%) delete mode 100644 packages/react-list/src/components/search.jsx create mode 100644 packages/react-list/src/components/search.tsx rename packages/react-list/src/components/{summary.jsx => summary.tsx} (72%) rename packages/react-list/src/components/{utils.js => utils.ts} (51%) delete mode 100644 packages/react-list/src/context/list-provider.jsx create mode 100644 packages/react-list/src/context/list-provider.tsx rename packages/react-list/src/{index.js => index.ts} (64%) create mode 100644 packages/react-list/src/types/index.ts create mode 100644 packages/react-list/src/types/list-provider.ts create mode 100644 packages/react-list/src/types/react-list.ts rename packages/react-list/src/{utils.js => utils.ts} (100%) create mode 100644 packages/react-list/tsconfig.build.json create mode 100644 packages/react-list/tsconfig.json diff --git a/apps/playground-typescript/index.html b/apps/playground-typescript/index.html new file mode 100644 index 0000000..fa41216 --- /dev/null +++ b/apps/playground-typescript/index.html @@ -0,0 +1,14 @@ + + + + + + + Vite + React (TypeScript) + + +
+ + + + diff --git a/apps/playground-typescript/package.json b/apps/playground-typescript/package.json new file mode 100644 index 0000000..3416511 --- /dev/null +++ b/apps/playground-typescript/package.json @@ -0,0 +1,29 @@ +{ + "name": "playground-typescript", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "typecheck": "tsc -p tsconfig.json --noEmit", + "preview": "vite preview" + }, + "dependencies": { + "@7span/react-list": "workspace:*", + "@iconify/react": "^5.2.1", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.2.2", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.27", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3", + "vite": "^6.3.1" + } +} diff --git a/apps/playground-typescript/postcss.config.mjs b/apps/playground-typescript/postcss.config.mjs new file mode 100644 index 0000000..51a6e4e --- /dev/null +++ b/apps/playground-typescript/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +}; diff --git a/apps/playground-typescript/src/App.tsx b/apps/playground-typescript/src/App.tsx new file mode 100644 index 0000000..92febc7 --- /dev/null +++ b/apps/playground-typescript/src/App.tsx @@ -0,0 +1,6 @@ +import ListWrapper from './components/list-wrapper'; + +export default function App() { + return ; +} + diff --git a/apps/playground-typescript/src/api/request-handler.ts b/apps/playground-typescript/src/api/request-handler.ts new file mode 100644 index 0000000..e6b611a --- /dev/null +++ b/apps/playground-typescript/src/api/request-handler.ts @@ -0,0 +1,87 @@ +import type { ReactListRequestArgs, ReactListResponse } from '@7span/react-list'; + +export type PlaygroundItem = { + id: number; + name: string; + status?: string; + date_updated?: string; + [key: string]: unknown; +}; + +type Filters = Record; + +const requestHandler = async ( + args: ReactListRequestArgs, +): Promise> => { + const { + endpoint, + page, + perPage, + search, + sortBy, + sortOrder, + filters, + meta, + } = args; + + const params = new URLSearchParams(); + + if (page && perPage) { + params.append('page', String(page)); + params.append('limit', String(perPage)); + } + + if (search) params.append('search', search); + + if (sortBy) { + params.append( + 'sort', + sortOrder === 'desc' ? `-${sortBy}` : sortBy, + ); + } + + if (filters && Object.keys(filters).length > 0) { + // Keep it simple for the playground. + for (const [key, value] of Object.entries(filters)) { + if (value === undefined || value === '') continue; + params.append(`filter[${key}][_eq]`, String(value)); + } + } + + // Example: meta support (not required by ReactList, just forwarded in args) + if (meta && typeof meta === 'object') { + // noop; you can add meta params here. + } + + const queryString = params.toString(); + const url = `https://everest.7span.in/items/${endpoint}${ + queryString ? `?${queryString}` : '' + }`; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`API request failed: ${response.status}`); + } + const data: any = await response.json(); + + return { + items: (data.data ?? []) as PlaygroundItem[], + count: + data.meta?.total_count ?? + data.meta?.filter_count ?? + 0, + meta: data.meta ?? {}, + }; + } catch (error) { + return { + items: [], + count: 0, + meta: {}, + error: error instanceof Error ? error : undefined, + } as unknown as ReactListResponse; + } +}; + +export default requestHandler; + diff --git a/apps/playground-typescript/src/components/list-wrapper.tsx b/apps/playground-typescript/src/components/list-wrapper.tsx new file mode 100644 index 0000000..02e2641 --- /dev/null +++ b/apps/playground-typescript/src/components/list-wrapper.tsx @@ -0,0 +1,298 @@ +import { useMemo, useState } from "react"; + +import ReactList, { + ReactListEmpty, + ReactListError, + ReactListGoTo, + ReactListInitialLoader, + ReactListItems, + ReactListLoader, + ReactListPagination, + ReactListPerPage, + ReactListProvider, + ReactListSearch, + ReactListSummary, +} from "@7span/react-list"; + +import { Icon } from "@iconify/react"; + +import reactListOptions from "./react-list"; +import type { PlaygroundItem } from "../api/request-handler"; + +type Filters = Record; + +export default function ListWrapper() { + const [filters, setFilters] = useState({}); + const paginationMode = "pagination" as const; + + // Stable render-prop children for the search component. + const searchChildren = useMemo( + () => + ({ + search, + setSearch, + }: { + search: string; + setSearch: (value: string) => void; + }) => ( +
+ setSearch(e.target.value)} + placeholder="Search skills..." + className="w-full rounded-md border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500" + /> +
+ ), + [], + ); + + return ( +
+
+ + +
+

+ React List TypeScript Playground +

+ +
+ {searchChildren} + + +
+
+ +
+ +
+
+
+ {[0, 1, 2, 3].map((i) => ( +
+ ))} +
+
+ + +
+
+ +
+
+ No data found +
+
+
+ + + {({ error }: { error: Error }) => ( +
+
+ +
+
{error.name}
+
{error.message}
+
+
+
+ )} +
+ + + {({ items }) => ( +
+ {items.map((item, idx) => { + const row = item as PlaygroundItem; + + return ( +
+
+
+ ID {row?.id} +
+ +
+ {row?.name} +
+ +
+ Updated:{" "} + {row?.date_updated + ? new Date( + row.date_updated, + ).toLocaleString() + : "-"} +
+
+ +
+ {row?.status ?? "-"} +
+
+ ); + })} +
+ )} +
+
+ +
+ + {({ isLoading }: { isLoading: boolean }) => + isLoading ? ( +
+ Loading... +
+ ) : null + } +
+
+
+ +
+
+ + {({ visibleCount, count }) => ( +
+ {visibleCount} results + {typeof count === "number" ? ` (total ${count})` : ""} +
+ )} +
+ +
+ + {({ perPage, setPerPage, options }) => ( + + )} + + + + {({ setPage, page, pagesCount }) => ( +
+ setPage(Number(e.target.value))} + className="w-20 rounded-md border border-gray-200 bg-white px-3 py-2 text-sm shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500" + /> + + of {pagesCount} + +
+ )} +
+ + + {({ + page, + pagesToDisplay, + hasPrev, + hasNext, + prev, + next, + first, + last, + setPage, + }) => ( +
+ + + + +
+ {pagesToDisplay.map((p) => ( + + ))} +
+ + + + +
+ )} +
+
+
+
+
+ + +
+
+ ); +} diff --git a/apps/playground-typescript/src/components/react-list.ts b/apps/playground-typescript/src/components/react-list.ts new file mode 100644 index 0000000..ed965c9 --- /dev/null +++ b/apps/playground-typescript/src/components/react-list.ts @@ -0,0 +1,75 @@ +import type { + ReactListProviderConfig, + ReactListRequestArgs, + ReactListResponse, + ReactListStateManager, +} from "@7span/react-list"; + +import requestHandler from "../api/request-handler"; +import type { PlaygroundItem } from "../api/request-handler"; + +type Filters = Record; + +const stateManagerKey = (endpoint: string, version: number) => + `react-list--${endpoint}--${version}`; + +const stateManager: ReactListStateManager = { + init(context: any) { + const { endpoint, version } = context; + const allKeys = `react-list--${endpoint}--`; + const latestKey = stateManagerKey(endpoint, version); + + const staleKeys = Object.keys(localStorage).filter( + (key) => key.startsWith(allKeys) && key !== latestKey, + ); + staleKeys.forEach((key) => localStorage.removeItem(key)); + }, + set(context: any) { + const { + endpoint, + version, + search, + page, + perPage, + sortBy, + sortOrder, + filters, + attrSettings, + } = context; + + const key = stateManagerKey(endpoint, version); + localStorage.setItem( + key, + JSON.stringify({ + search, + page, + perPage, + sortBy, + sortOrder, + filters, + attrSettings, + }), + ); + }, + get(context: any) { + const { endpoint, version } = context; + const key = stateManagerKey(endpoint, version); + + try { + const raw = localStorage.getItem(key); + if (!raw) return null; + return JSON.parse(raw) as any; + } catch { + return null; + } + }, +}; + +const config: ReactListProviderConfig = { + requestHandler: requestHandler as unknown as ( + args: ReactListRequestArgs, + ) => Promise>, + stateManager, +}; + +export default config; diff --git a/apps/playground-typescript/src/index.css b/apps/playground-typescript/src/index.css new file mode 100644 index 0000000..d1d9133 --- /dev/null +++ b/apps/playground-typescript/src/index.css @@ -0,0 +1,2 @@ +@import "tailwindcss"; +@source "../**/*.{js,jsx,ts,tsx}"; \ No newline at end of file diff --git a/apps/playground-typescript/src/main.tsx b/apps/playground-typescript/src/main.tsx new file mode 100644 index 0000000..0c5505f --- /dev/null +++ b/apps/playground-typescript/src/main.tsx @@ -0,0 +1,11 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; + +import App from "./App"; +import "./index.css"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/apps/playground-typescript/tailwind.config.js b/apps/playground-typescript/tailwind.config.js new file mode 100644 index 0000000..a117e69 --- /dev/null +++ b/apps/playground-typescript/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./index.html", "./src/**/*.{ts,tsx,jsx,js}"], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/playground-typescript/tsconfig.json b/apps/playground-typescript/tsconfig.json new file mode 100644 index 0000000..e034b35 --- /dev/null +++ b/apps/playground-typescript/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["vite/client"], + "resolveJsonModule": true + }, + "include": ["src"] +} + diff --git a/apps/playground-typescript/vite.config.ts b/apps/playground-typescript/vite.config.ts new file mode 100644 index 0000000..f0c8be1 --- /dev/null +++ b/apps/playground-typescript/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], +}); + diff --git a/apps/playground/package.json b/apps/playground/package.json index c903db3..90148b5 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -10,21 +10,25 @@ "preview": "vite preview" }, "dependencies": { + "@7span/react-list": "workspace:*", + "@iconify/react": "^5.2.1", "axios": "1.11.0", "react": "^19.0.0", - "react-dom": "^19.0.0", - "@iconify/react": "^5.2.1", - "@7span/react-list": "workspace:*" + "react-dom": "^19.0.0" }, "devDependencies": { "@eslint/js": "^9.22.0", + "@tailwindcss/postcss": "^4.2.2", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.27", "eslint": "^9.22.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", "vite": "^6.3.1" } } diff --git a/apps/playground/postcss.config.js b/apps/playground/postcss.config.js new file mode 100644 index 0000000..51a6e4e --- /dev/null +++ b/apps/playground/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +}; diff --git a/apps/playground/src/components/list-wrapper.jsx b/apps/playground/src/components/list-wrapper.jsx index a74d603..c8600b0 100644 --- a/apps/playground/src/components/list-wrapper.jsx +++ b/apps/playground/src/components/list-wrapper.jsx @@ -1,3 +1,5 @@ +import { useMemo, useState } from 'react'; + import ReactList, { ReactListEmpty, ReactListError, @@ -10,416 +12,334 @@ import ReactList, { ReactListProvider, ReactListSearch, ReactListSummary, -} from "@7span/react-list"; +} from '@7span/react-list'; + +import { Icon } from '@iconify/react'; -import { Icon } from "@iconify/react"; -import { useState } from "react"; +import reactListOptions from './react-list'; -import reactListOptions from "./react-list"; +const STATUS_OPTIONS = [ + { label: 'All Status', value: '' }, + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + { label: 'Archived', value: 'archived' }, +]; -import "../app.css"; +const COLOR_OPTIONS = [ + { label: 'All Colors', value: '' }, + { label: 'Red', value: '#FF9900' }, + { label: 'Blue', value: '#FFEB0F' }, + { label: 'Green', value: '#F7DF1E' }, + { label: 'Yellow', value: '#5E24FF' }, +]; -const ListWrapper = () => { +export default function ListWrapper() { const [filters, setFilters] = useState({}); + const paginationMode = 'pagination'; + + const searchChildren = useMemo( + () => + ({ search, setSearch }) => ( +
+ setSearch(e.target.value)} + placeholder="Search skills..." + className="w-full rounded-md border border-gray-700 bg-gray-900 px-3 py-2 text-sm text-gray-100 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20" + /> +
+ ), + [], + ); + return ( -
-

React List Playground

- - -
-
- {/* */} - - {({ search, setSearch }) => ( -
- { - setSearch(e.target.value); - }} - placeholder="Search skills..." - className="search-input" - /> -
- )} -
-
-
-
-
- +
+
+
+

+ React List Playground (Tailwind) +

+ +
+ + +
+ {searchChildren} + -
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- {[...Array(5)].map((_, index) => ( -
-
-
-
-
-
+ {COLOR_OPTIONS.map((opt) => ( + ))} -
-
-
-
- -
-
-
-
- -
-
- -

No Data Found

- -

- We couldn't find any matching records. Try adjusting your - search or filters. -

+ - -
-
- - {({ error }) => ( -
-
- -
-

Something went wrong

-

- {error.message || - "An unexpected error occurred while fetching data."} -

-
-

- {error.name}: {error.message} -

-
-
- )} -
- - {({ items, sort, setSort }) => { - return ( -
- -
-
- + +
+
+
+ {[0, 1, 2, 3].map((i) => ( +
+ ))} +
+
+ + +
+ +
+
+ No data found
- - - - - - - - - - - - {items.map((item) => ( - - - - - - - ))} - -
ID - Name{" "} - - Status - Update At{" "} - -
{item.id}{item.name}{item.status} - {new Date(item.date_updated).toLocaleString()} -
-
- ); - }} - - {/* Footer */} -
-
-
- - {({ visibleCount }) => ( - - {visibleCount} Results - - )} - -
+ + {({ items }) => ( +
+ {items.map((item, idx) => { + const row = item ?? {}; + return ( +
+
+
+ ID {row.id} +
-
- Page Size: - - {({ perPage, setPerPage, options }) => ( -
- -
- +
+ {row.name} +
+ +
+ Updated:{' '} + {row.date_updated + ? new Date( + row.date_updated, + ).toLocaleString() + : '-'} +
+
+ +
+ {row.status ?? '-'} +
+
+ ); + })}
-
- )} - -
+ )} + -
- - {({ setPage, page, pagesCount }) => ( -
- Go to: - { - const page = Number(e.target.value); - setPage(page); - }} - className="page-input" - /> - of {pagesCount} -
- )} -
-
-
+ + {({ isLoading }) => + isLoading ? ( +
+ Loading... +
+ ) : null + } +
+
- - {({ - page, - pagesToDisplay, - hasNext, - hasPrev, - prev, - next, - first, - last, - setPage, - }) => ( -
- +
+
+ + {({ visibleCount, count }) => ( +
+ {visibleCount} results + {typeof count === 'number' + ? ` (total ${count})` + : ''} +
+ )} +
- +
+ + {({ perPage, setPerPage, options }) => ( + + )} + -
- {pagesToDisplay.map((item, index) => { - const isActive = item === page; + + {({ setPage, page, pagesCount }) => ( +
+ + setPage(Number(e.target.value)) + } + className="w-20 rounded-md border border-gray-700 bg-gray-900 px-3 py-2 text-sm text-gray-100 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20" + /> + + of {pagesCount} + +
+ )} +
- return ( - - ); - })} -
+ + {({ + page, + pagesToDisplay, + hasPrev, + hasNext, + first, + prev, + next, + last, + setPage, + }) => ( +
+ + - +
+ {pagesToDisplay.map((p) => ( + + ))} +
- + + +
+ )} +
+
+
- )} - -
+
+ +
- - +
+
); -}; +} -export default ListWrapper; diff --git a/apps/playground/src/index.css b/apps/playground/src/index.css index 08a3ac9..a50c033 100644 --- a/apps/playground/src/index.css +++ b/apps/playground/src/index.css @@ -1,3 +1,6 @@ +@import "tailwindcss"; +@source "../**/*.{js,jsx,ts,tsx}"; + :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -18,6 +21,7 @@ a { color: #646cff; text-decoration: inherit; } + a:hover { color: #535bf2; } @@ -46,9 +50,11 @@ button { cursor: pointer; transition: border-color 0.25s; } + button:hover { border-color: #646cff; } + button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; @@ -59,10 +65,12 @@ button:focus-visible { color: #213547; background-color: #ffffff; } + a:hover { color: #747bff; } + button { background-color: #f9f9f9; } -} +} \ No newline at end of file diff --git a/apps/playground/tailwind.config.js b/apps/playground/tailwind.config.js new file mode 100644 index 0000000..524f96e --- /dev/null +++ b/apps/playground/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +}; + diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 7423430..6163710 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -5,12 +5,22 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build": "vite build && pnpm run build:types", + "build:types": "tsc -p tsconfig.build.json", "lint": "eslint .", "preview": "vite preview", - "prepublishOnly": "npm run build" + "prepublishOnly": "pnpm run build" + }, + "main": "dist/react-list.cjs", + "module": "dist/react-list.js", + "types": "dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/react-list.js", + "require": "./dist/react-list.cjs" + } }, - "main": "dist/react-list.js", "files": [ "dist" ], @@ -22,7 +32,10 @@ "react-dom": "^18.2.0 || ^19.0.0" }, "devDependencies": { + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^4.3.4", + "typescript": "^5.9.3", "vite": "^6.3.1" } -} +} \ No newline at end of file diff --git a/packages/react-list/src/components/attributes.jsx b/packages/react-list/src/components/attributes.jsx deleted file mode 100644 index b3fc189..0000000 --- a/packages/react-list/src/components/attributes.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import { memo, useCallback, useMemo } from "react"; -import { useListContext } from "../context/list-provider"; - -export const ReactListAttributes = memo(({ children, renderAttribute }) => { - const { listState } = useListContext(); - const { attrs, attrSettings, updateAttr } = listState; - - const handleAttrChange = useCallback( - (attrName) => (e) => { - updateAttr(attrName, "visible", e.target.checked); - }, - [updateAttr] - ); - - const scope = useMemo( - () => ({ - attrs, - attrSettings, - updateAttr, - }), - [attrs, attrSettings, updateAttr] - ); - - if (children) { - return children(scope); - } - - return ( -
- {attrs.map((attr, index) => { - if (renderAttribute) { - return renderAttribute({ - key: `attr-${index}`, - attr, - updateAttr, - attrSettings, - }); - } - - return ( - - ); - })} -
- ); -}); diff --git a/packages/react-list/src/components/attributes.tsx b/packages/react-list/src/components/attributes.tsx new file mode 100644 index 0000000..fa4e2d7 --- /dev/null +++ b/packages/react-list/src/components/attributes.tsx @@ -0,0 +1,87 @@ +import { memo, useCallback, useMemo } from "react"; +import { useListContext } from "../context/list-provider"; +import type { ReactListAttrSettings, ReactListAttribute } from "../types"; +import type { ChangeEvent, ReactNode } from "react"; + +type ReactListAttributesUpdateAttr = ( + attrName: string, + settingKey: string, + value: unknown, +) => void; + +type ReactListAttributesScope = { + attrs: ReactListAttribute[]; + attrSettings: ReactListAttrSettings; + updateAttr: ReactListAttributesUpdateAttr; +}; + +type ReactListAttributesRenderAttributeArgs = { + key: string; + attr: ReactListAttribute; + updateAttr: ReactListAttributesUpdateAttr; + attrSettings: ReactListAttrSettings; +}; + +type ReactListAttributesProps = { + children?: ReactNode | ((scope: ReactListAttributesScope) => ReactNode); + renderAttribute?: (args: ReactListAttributesRenderAttributeArgs) => ReactNode; +}; + +export const ReactListAttributes = memo( + ({ children, renderAttribute }: ReactListAttributesProps) => { + const { listState } = useListContext(); + const { attrs, attrSettings, updateAttr } = listState; + + const handleAttrChange = useCallback( + (attrName: string) => (e: ChangeEvent) => { + updateAttr(attrName, "visible", e.target.checked); + }, + [updateAttr], + ); + + const scope = useMemo( + () => ({ + attrs, + attrSettings, + updateAttr, + }), + [attrs, attrSettings, updateAttr], + ); + + if (typeof children === "function") { + return children(scope); + } + + if (children) return children; + + return ( +
+ {attrs.map((attr, index) => { + if (renderAttribute) { + return ( + + {renderAttribute({ + key: `attr-${index}`, + attr, + updateAttr, + attrSettings, + })} + + ); + } + + return ( + + ); + })} +
+ ); + }, +); diff --git a/packages/react-list/src/components/empty.jsx b/packages/react-list/src/components/empty.tsx similarity index 77% rename from packages/react-list/src/components/empty.jsx rename to packages/react-list/src/components/empty.tsx index 40dbeed..c97be07 100644 --- a/packages/react-list/src/components/empty.jsx +++ b/packages/react-list/src/components/empty.tsx @@ -1,7 +1,11 @@ import { memo } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListEmpty = memo(({ children }) => { +type ReactListEmptyProps = { + children?: React.ReactNode; +}; + +export const ReactListEmpty = memo(({ children }: ReactListEmptyProps) => { const { listState } = useListContext(); const { data: items, loader, error } = listState; const { isLoading, initialLoading } = loader; diff --git a/packages/react-list/src/components/error.jsx b/packages/react-list/src/components/error.tsx similarity index 72% rename from packages/react-list/src/components/error.jsx rename to packages/react-list/src/components/error.tsx index 957ad19..476b5d0 100644 --- a/packages/react-list/src/components/error.jsx +++ b/packages/react-list/src/components/error.tsx @@ -1,7 +1,14 @@ import { memo } from "react"; +import type { ReactNode } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListError = memo(({ children }) => { +type ReactListErrorProps = { + children?: + | ReactNode + | ((scope: { error: Error }) => ReactNode); +}; + +export const ReactListError = memo(({ children }: ReactListErrorProps) => { const { listState } = useListContext(); const { error, loader } = listState; const { isLoading } = loader; diff --git a/packages/react-list/src/components/go-to.jsx b/packages/react-list/src/components/go-to.tsx similarity index 73% rename from packages/react-list/src/components/go-to.jsx rename to packages/react-list/src/components/go-to.tsx index 361162b..a076d86 100644 --- a/packages/react-list/src/components/go-to.jsx +++ b/packages/react-list/src/components/go-to.tsx @@ -1,7 +1,21 @@ import { memo, useCallback, useMemo } from "react"; +import type { ReactNode } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListGoTo = memo(({ children }) => { +type ReactListGoToScope = { + setPage: (page: number, addContext?: Record) => void; + page: number; + pages: number[]; + pagesCount: number; +}; + +type ReactListGoToProps = { + children?: + | ReactNode + | ((scope: ReactListGoToScope) => ReactNode); +}; + +export const ReactListGoTo = memo(({ children }: ReactListGoToProps) => { const { listState } = useListContext(); const { data, count, pagination, setPage, loader, error } = listState; const { page, perPage } = pagination; @@ -42,8 +56,10 @@ export const ReactListGoTo = memo(({ children }) => { return (
- {children ? ( + {typeof children === "function" ? ( children(scope) + ) : children ? ( + children ) : ( handleChange(e.target.value)} - placeholder="Search..." - /> - )} -
- ); -}); diff --git a/packages/react-list/src/components/search.tsx b/packages/react-list/src/components/search.tsx new file mode 100644 index 0000000..0eb7d1c --- /dev/null +++ b/packages/react-list/src/components/search.tsx @@ -0,0 +1,75 @@ +import { memo, useEffect, useRef, useState } from "react"; +import type { ReactNode } from "react"; + +import { useListContext } from "../context/list-provider"; + +type ReactListSearchScope = { + search: string; + setSearch: (value: string) => void; +}; + +type ReactListSearchProps = { + debounceTime?: number; + children?: ReactNode | ((scope: ReactListSearchScope) => ReactNode); +}; + +export const ReactListSearch = memo( + ({ children, debounceTime = 500 }: ReactListSearchProps) => { + const { listState } = useListContext(); + const { search, setSearch } = listState; + + const [localSearch, setLocalSearch] = useState(search ?? ""); + const debounceTimerRef = useRef | null>(null); + + // Sync local state with context when the list search value changes. + useEffect(() => { + if (search !== localSearch) { + setLocalSearch(search ?? ""); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [search]); + + const handleChange = (value: string) => { + setLocalSearch(value); + + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current); + } + + debounceTimerRef.current = setTimeout(() => { + setSearch(value); + }, debounceTime); + }; + + useEffect(() => { + return () => { + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current); + } + }; + }, []); + + const scope: ReactListSearchScope = { + search: localSearch, + setSearch: handleChange, + }; + + return ( +
+ {typeof children === "function" ? ( + children(scope) + ) : children ? ( + children + ) : ( + handleChange(e.target.value)} + placeholder="Search..." + /> + )} +
+ ); + } +); + diff --git a/packages/react-list/src/components/summary.jsx b/packages/react-list/src/components/summary.tsx similarity index 72% rename from packages/react-list/src/components/summary.jsx rename to packages/react-list/src/components/summary.tsx index 284da5c..a360b0a 100644 --- a/packages/react-list/src/components/summary.jsx +++ b/packages/react-list/src/components/summary.tsx @@ -1,7 +1,21 @@ import { memo, useMemo } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListSummary = memo(({ children }) => { +import type { ReactNode } from "react"; + +type ReactListSummaryScope = { + from: number; + to: number; + visibleCount: number; + count: number; +}; + +type ReactListSummaryProps = { + children?: ReactNode | ((scope: ReactListSummaryScope) => ReactNode); +}; + +export const ReactListSummary = memo( + ({ children }: ReactListSummaryProps) => { const { listState } = useListContext(); const { data, count, pagination, loader, error } = listState; const { page, perPage } = pagination; @@ -35,8 +49,10 @@ export const ReactListSummary = memo(({ children }) => { return (
- {children ? ( + {typeof children === "function" ? ( children(scope) + ) : children ? ( + children ) : ( Showing {summaryData.visibleCount} items ( @@ -48,4 +64,5 @@ export const ReactListSummary = memo(({ children }) => { )}
); -}); + } +); diff --git a/packages/react-list/src/components/utils.js b/packages/react-list/src/components/utils.ts similarity index 51% rename from packages/react-list/src/components/utils.js rename to packages/react-list/src/components/utils.ts index f4a7279..e9f4e33 100644 --- a/packages/react-list/src/components/utils.js +++ b/packages/react-list/src/components/utils.ts @@ -1,10 +1,11 @@ -export const deepEqual = (obj1, obj2) => { +export const deepEqual = (obj1: unknown, obj2: unknown): boolean => { if (obj1 === obj2) return true; if (obj1 == null || obj2 == null) return obj1 === obj2; - if (typeof obj1 !== "object" || typeof obj2 !== "object") + if (typeof obj1 !== "object" || typeof obj2 !== "object") { return obj1 === obj2; + } if (Array.isArray(obj1) && Array.isArray(obj2)) { if (obj1.length !== obj2.length) return false; @@ -16,22 +17,28 @@ export const deepEqual = (obj1, obj2) => { if (Array.isArray(obj1) || Array.isArray(obj2)) return false; - const keys1 = Object.keys(obj1).filter((key) => obj1[key] !== undefined); - const keys2 = Object.keys(obj2).filter((key) => obj2[key] !== undefined); + const record1 = obj1 as Record; + const record2 = obj2 as Record; + + const keys1 = Object.keys(record1).filter((key) => record1[key] !== undefined); + const keys2 = Object.keys(record2).filter((key) => record2[key] !== undefined); if (keys1.length !== keys2.length) return false; - for (let key of keys1) { + for (const key of keys1) { if (!keys2.includes(key)) return false; - if (!deepEqual(obj1[key], obj2[key])) return false; + if (!deepEqual(record1[key], record2[key])) return false; } return true; }; -export const hasActiveFilters = (currentFilters, initialFilters) => { +export const hasActiveFilters = ( + currentFilters: Record | null | undefined, + initialFilters: Record | null | undefined +): boolean => { if (!initialFilters || Object.keys(initialFilters).length === 0) { - return currentFilters && Object.keys(currentFilters).length > 0; + return !!currentFilters && Object.keys(currentFilters).length > 0; } if (!currentFilters || Object.keys(currentFilters).length === 0) { diff --git a/packages/react-list/src/context/list-provider.jsx b/packages/react-list/src/context/list-provider.jsx deleted file mode 100644 index bd4e21a..0000000 --- a/packages/react-list/src/context/list-provider.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import { createContext, useContext, useMemo, useState } from "react"; - -const ListContext = createContext(null); - -export const ReactListProvider = ({ children, config }) => { - const { requestHandler, stateManager = {} } = config; - const [listState, setListState] = useState({ - data: [], - response: null, - error: null, - count: 0, - selection: [], - pagination: { - page: 1, - perPage: 25, - }, - loader: { - isLoading: false, - initialLoading: true, - }, - sort: { - sortBy: null, - sortOrder: "desc", - }, - search: "", - filters: {}, - attrs: [], - isEmpty: true, - isInitializing: true, - }); - - if (!requestHandler) { - throw new Error("ListProvider: requestHandler is required."); - } - - const value = useMemo( - () => ({ - requestHandler, - stateManager, - listState, - setListState, - }), - [requestHandler, stateManager, listState] - ); - - return {children}; -}; - -export const useListContext = () => { - const context = useContext(ListContext); - if (!context) { - throw new Error("useListContext must be used within a ListProvider"); - } - return context; -}; diff --git a/packages/react-list/src/context/list-provider.tsx b/packages/react-list/src/context/list-provider.tsx new file mode 100644 index 0000000..0182397 --- /dev/null +++ b/packages/react-list/src/context/list-provider.tsx @@ -0,0 +1,91 @@ +import { createContext, useContext, useMemo, useState } from "react"; +import type { ReactNode } from "react"; + +import type { + ReactListContextValue, + ReactListFilters, + ReactListItem, + ReactListItemId, + ReactListListState, + ReactListProviderConfig, + ReactListResponse, + ReactListRequestHandler, + ReactListStateManager, +} from "../types"; + +const ListContext = createContext(null); + +type ReactListProviderProps = { + children: ReactNode; + config: ReactListProviderConfig; +}; + +const noop = () => {}; + +export const ReactListProvider = ({ children, config }: ReactListProviderProps) => { + const { requestHandler, stateManager = {} } = config; + + if (!requestHandler) { + throw new Error("ListProvider: requestHandler is required."); + } + + const [listState, setListState] = useState>({ + data: [], + response: null as ReactListResponse | null, + error: null, + count: 0, + selection: [] as ReactListItemId[], + pagination: { + page: 1, + perPage: 25, + hasMore: false, + }, + loader: { + isLoading: false, + initialLoading: true, + }, + sort: { + sortBy: "", + sortOrder: "desc", + }, + hasActiveFilters: false, + search: "", + filters: {}, + attrs: [], + attrSettings: {}, + isEmpty: true, + + // These actions are replaced by `ReactList` once it mounts. + setPage: noop, + setPerPage: noop, + setSearch: noop, + setSort: noop, + loadMore: noop, + clearFilters: noop, + refresh: noop, + setFilters: noop, + updateAttr: noop, + updateItemById: noop, + setSelection: noop, + }); + + const value: ReactListContextValue = useMemo( + () => ({ + requestHandler: requestHandler as ReactListRequestHandler, + stateManager: stateManager as ReactListStateManager, + listState, + setListState, + }), + [requestHandler, stateManager, listState] + ); + + return {children}; +}; + +export const useListContext = (): ReactListContextValue => { + const context = useContext(ListContext); + if (!context) { + throw new Error("useListContext must be used within a ListProvider"); + } + return context; +}; diff --git a/packages/react-list/src/index.js b/packages/react-list/src/index.ts similarity index 64% rename from packages/react-list/src/index.js rename to packages/react-list/src/index.ts index d132e3f..65eca60 100644 --- a/packages/react-list/src/index.js +++ b/packages/react-list/src/index.ts @@ -13,3 +13,25 @@ export { ReactListRefresh } from "./components/refresh"; export { ReactListSearch } from "./components/search"; export { ReactListSummary } from "./components/summary"; export { ReactListProvider } from "./context/list-provider"; + +export type { + ReactListAttrSettings, + ReactListContext, + ReactListContextValue, + ReactListFilters, + ReactListAttribute, + ReactListProps, + ReactListPaginationMode, + ReactListItem, + ReactListItemId, + ReactListListState, + ReactListLoaderState, + ReactListPaginationState, + ReactListProviderConfig, + ReactListRequestArgs, + ReactListRequestHandler, + ReactListResponse, + ReactListSort, + ReactListSortOrder, + ReactListStateManager, +} from "./types"; diff --git a/packages/react-list/src/types/index.ts b/packages/react-list/src/types/index.ts new file mode 100644 index 0000000..d27aaf5 --- /dev/null +++ b/packages/react-list/src/types/index.ts @@ -0,0 +1,22 @@ +export type { + ReactListAttrSettings, + ReactListContext, + ReactListContextValue, + ReactListItem, + ReactListItemId, + ReactListListState, + ReactListLoaderState, + ReactListPaginationState, + ReactListProviderConfig, + ReactListRequestArgs, + ReactListRequestHandler, + ReactListResponse, + ReactListSort, + ReactListSortOrder, + ReactListStateManager, + ReactListFilters, + ReactListAttribute, +} from './list-provider.ts'; + +export type { ReactListProps, ReactListPaginationMode } from './react-list'; + diff --git a/packages/react-list/src/types/list-provider.ts b/packages/react-list/src/types/list-provider.ts new file mode 100644 index 0000000..795ddbd --- /dev/null +++ b/packages/react-list/src/types/list-provider.ts @@ -0,0 +1,156 @@ +import type * as React from 'react'; + +export type ReactListItemId = string | number; + +export type ReactListItem = Record & { + id?: ReactListItemId; +}; + +export type ReactListFilters = Record; + +export type ReactListSortOrder = '' | 'asc' | 'desc' | (string & {}); + +export type ReactListAttrSettings = Record< + string, + { + visible: boolean; + } +>; + +export type ReactListRequestArgs< + TFilters extends ReactListFilters = ReactListFilters, +> = { + endpoint: string; + version: number; + meta: Record; + page: number; + perPage: number; + search: string; + sortBy: string; + sortOrder: ReactListSortOrder; + filters: TFilters; +} & Record; + +export type ReactListResponse = { + items: TItem[]; + count: number; + meta?: unknown; + [key: string]: unknown; +}; + +export type ReactListRequestHandler< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = (args: ReactListRequestArgs) => Promise>; + +export type ReactListPersistedState< + TFilters extends ReactListFilters = ReactListFilters, +> = { + page?: number; + perPage?: number; + sortBy?: string; + sortOrder?: ReactListSortOrder; + search?: string; + attrSettings?: ReactListAttrSettings; + filters?: TFilters; +}; + +export type ReactListContext = { + endpoint: string; + version: number; + meta: Record; + search: string; + page: number; + perPage: number; + sortBy: string; + sortOrder: ReactListSortOrder; + filters: TFilters; + attrSettings: ReactListAttrSettings; + isRefresh: boolean; +}; + +export type ReactListStateManager< + TFilters extends ReactListFilters = ReactListFilters, +> = { + init?: (context: ReactListContext) => void; + get?: (context: ReactListContext) => ReactListPersistedState | null; + set?: (context: ReactListContext) => void; +}; + +export type ReactListProviderConfig< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + requestHandler: ReactListRequestHandler; + stateManager?: ReactListStateManager; +}; + +export type ReactListPaginationState = { + page: number; + perPage: number; + hasMore: boolean; +}; + +export type ReactListLoaderState = { + isLoading: boolean; + initialLoading: boolean; +}; + +export type ReactListSort = { + sortBy: string; + sortOrder: ReactListSortOrder; +}; + +export type ReactListAttribute = { + name: string; + label?: string; +}; + +export type ReactListActions< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + setPage: (value: number, addContext?: Record) => void; + setPerPage: (value: number) => void; + setSearch: (value: string) => void; + setSort: (args: { by: string; order: ReactListSortOrder }) => void; + loadMore: () => void; + clearFilters: () => void; + refresh: (addContext?: Record) => void; + setFilters: (filters: TFilters) => void; + updateAttr: (attrName: string, settingKey: string, value: unknown) => void; + updateItemById: (item: Partial, id: ReactListItemId) => void; + setSelection: (selection: ReactListItemId[]) => void; +}; + +export type ReactListListState< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + data: TItem[]; + response: ReactListResponse | null; + error: Error | null; + count: number; + selection: ReactListItemId[]; + pagination: ReactListPaginationState; + loader: ReactListLoaderState; + sort: ReactListSort; + hasActiveFilters: boolean; + search: string; + filters: TFilters; + attrs: ReactListAttribute[]; + attrSettings: ReactListAttrSettings; + isEmpty: boolean; + // Actions are appended by the main `ReactList` component. +} & ReactListActions; + +export type ReactListContextValue< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + requestHandler: ReactListRequestHandler; + stateManager: ReactListStateManager; + listState: ReactListListState; + setListState: React.Dispatch>>; +}; + diff --git a/packages/react-list/src/types/react-list.ts b/packages/react-list/src/types/react-list.ts new file mode 100644 index 0000000..4ec6d6c --- /dev/null +++ b/packages/react-list/src/types/react-list.ts @@ -0,0 +1,39 @@ +import type { ReactNode } from 'react'; + +import type { + ReactListAttribute, + ReactListFilters, + ReactListItem, + ReactListListState, + ReactListResponse, + ReactListSortOrder, +} from './list-provider'; + +export type ReactListPaginationMode = 'pagination' | 'loadMore'; + +export type ReactListProps< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + initialItems?: TItem[]; + children?: + | ReactNode + | ((scope: ReactListListState) => ReactNode); + + endpoint: string; + page?: number; + perPage?: number; + sortBy?: string; + sortOrder?: ReactListSortOrder; + count?: number; + search?: string; + filters?: TFilters; + attrs?: Array; + version?: number; + paginationMode?: ReactListPaginationMode; + meta?: Record; + onResponse?: (res: ReactListResponse) => void; + afterPageChange?: (res: ReactListResponse) => void; + afterLoadMore?: (res: ReactListResponse) => void; +}; + diff --git a/packages/react-list/src/utils.js b/packages/react-list/src/utils.ts similarity index 100% rename from packages/react-list/src/utils.js rename to packages/react-list/src/utils.ts diff --git a/packages/react-list/tsconfig.build.json b/packages/react-list/tsconfig.build.json new file mode 100644 index 0000000..b96c8ea --- /dev/null +++ b/packages/react-list/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "allowJs": true, + "checkJs": false, + "declaration": true, + "emitDeclarationOnly": true, + "declarationMap": true, + "outDir": "dist/types", + "strict": false, + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/react-list/tsconfig.json b/packages/react-list/tsconfig.json new file mode 100644 index 0000000..5c29504 --- /dev/null +++ b/packages/react-list/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "noEmit": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ee8495..a620d7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ importers: devDependencies: vitepress: specifier: ^2.0.0-alpha.15 - version: 2.0.0-alpha.15(axios@1.11.0)(postcss@8.5.6) + version: 2.0.0-alpha.15(axios@1.11.0)(jiti@2.6.1)(lightningcss@1.32.0)(postcss@8.5.8)(typescript@5.9.3) apps/playground: dependencies: @@ -35,6 +35,9 @@ importers: '@eslint/js': specifier: ^9.22.0 version: 9.25.1 + '@tailwindcss/postcss': + specifier: ^4.2.2 + version: 4.2.2 '@types/react': specifier: ^19.0.10 version: 19.1.2 @@ -43,22 +46,74 @@ importers: version: 19.1.2(@types/react@19.1.2) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3) + version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) + autoprefixer: + specifier: ^10.4.27 + version: 10.4.27(postcss@8.5.8) eslint: specifier: ^9.22.0 - version: 9.25.1 + version: 9.25.1(jiti@2.6.1) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.25.1) + version: 5.2.0(eslint@9.25.1(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: ^0.4.19 - version: 0.4.20(eslint@9.25.1) + version: 0.4.20(eslint@9.25.1(jiti@2.6.1)) globals: specifier: ^16.0.0 version: 16.0.0 + postcss: + specifier: ^8.5.8 + version: 8.5.8 + tailwindcss: + specifier: ^4.2.2 + version: 4.2.2 vite: specifier: ^6.3.1 - version: 6.3.3 + version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) + + apps/playground-typescript: + dependencies: + '@7span/react-list': + specifier: workspace:* + version: link:../../packages/react-list + '@iconify/react': + specifier: ^5.2.1 + version: 5.2.1(react@19.1.0) + react: + specifier: ^19.0.0 + version: 19.1.0 + react-dom: + specifier: ^19.0.0 + version: 19.1.0(react@19.1.0) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.2.2 + version: 4.2.2 + '@types/react': + specifier: ^19.0.10 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.0.4 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) + autoprefixer: + specifier: ^10.4.27 + version: 10.4.27(postcss@8.5.8) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + tailwindcss: + specifier: ^4.2.2 + version: 4.2.2 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^6.3.1 + version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) packages/react-list: dependencies: @@ -69,15 +124,28 @@ importers: specifier: ^18.2.0 || ^19.0.0 version: 19.1.0(react@19.1.0) devDependencies: + '@types/react': + specifier: ^19.1.13 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.1.9 + version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3) + version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) + typescript: + specifier: ^5.9.3 + version: 5.9.3 vite: specifier: ^6.3.1 - version: 6.3.3 + version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -407,6 +475,9 @@ packages: resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -415,9 +486,6 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -661,6 +729,94 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} + + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.2.2': + resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -702,9 +858,17 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react@19.1.2': resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -843,12 +1007,24 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + axios@1.11.0: resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + baseline-browser-mapping@2.10.9: + resolution: {integrity: sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==} + engines: {node: '>=6.0.0'} + hasBin: true + birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} @@ -860,6 +1036,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -868,8 +1049,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001715: - resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} + caniuse-lite@1.0.30001780: + resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -915,6 +1096,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -935,6 +1119,10 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -945,6 +1133,13 @@ packages: electron-to-chromium@1.5.141: resolution: {integrity: sha512-qS+qH9oqVYc1ooubTiB9l904WVyM6qNYxtOEEGReoZXw3xlqeYdFr5GclNzbkAufWgwWLEPoDi3d9MoRwwIjGw==} + electron-to-chromium@1.5.321: + resolution: {integrity: sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==} + + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -1091,6 +1286,9 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1131,6 +1329,9 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1189,6 +1390,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1222,6 +1427,76 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1291,6 +1566,9 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + oniguruma-parser@0.12.1: resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} @@ -1335,12 +1613,11 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} - engines: {node: ^10 || ^12 || >=14} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -1443,6 +1720,13 @@ packages: tabbable@6.3.0: resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -1458,6 +1742,11 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -1479,6 +1768,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1612,6 +1907,8 @@ packages: snapshots: + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -1821,9 +2118,9 @@ snapshots: '@esbuild/win32-x64@0.25.3': optional: true - '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1)': + '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1(jiti@2.6.1))': dependencies: - eslint: 9.25.1 + eslint: 9.25.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -1892,21 +2189,24 @@ snapshots: '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@rolldown/pluginutils@1.0.0-beta.53': {} @@ -2074,6 +2374,75 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@tailwindcss/node@4.2.2': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.20.1 + jiti: 2.6.1 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.2 + + '@tailwindcss/oxide-android-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide@4.2.2': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 + + '@tailwindcss/postcss@4.2.2': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + postcss: 8.5.8 + tailwindcss: 4.2.2 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.0 @@ -2122,32 +2491,40 @@ snapshots: dependencies: '@types/react': 19.1.2 + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + '@types/react@19.1.2': dependencies: csstype: 3.1.3 + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + '@types/unist@3.0.3': {} '@types/web-bluetooth@0.0.21': {} '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.4.1(vite@6.3.3)': + '@vitejs/plugin-react@4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: '@babel/core': 7.26.10 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.3 + vite: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.3(vite@7.2.7)(vue@3.5.25)': + '@vitejs/plugin-vue@6.0.3(vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0))(vue@3.5.25(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.2.7 - vue: 3.5.25 + vite: 7.2.7(jiti@2.6.1)(lightningcss@1.32.0) + vue: 3.5.25(typescript@5.9.3) '@vue/compiler-core@3.5.25': dependencies: @@ -2171,7 +2548,7 @@ snapshots: '@vue/shared': 3.5.25 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.6 + postcss: 8.5.8 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.25': @@ -2213,35 +2590,35 @@ snapshots: '@vue/shared': 3.5.25 csstype: 3.1.3 - '@vue/server-renderer@3.5.25(vue@3.5.25)': + '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': dependencies: '@vue/compiler-ssr': 3.5.25 '@vue/shared': 3.5.25 - vue: 3.5.25 + vue: 3.5.25(typescript@5.9.3) '@vue/shared@3.5.25': {} - '@vueuse/core@14.1.0(vue@3.5.25)': + '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.1.0 - '@vueuse/shared': 14.1.0(vue@3.5.25) - vue: 3.5.25 + '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) - '@vueuse/integrations@14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25)': + '@vueuse/integrations@14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25(typescript@5.9.3))': dependencies: - '@vueuse/core': 14.1.0(vue@3.5.25) - '@vueuse/shared': 14.1.0(vue@3.5.25) - vue: 3.5.25 + '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) + '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: axios: 1.11.0 focus-trap: 7.6.6 '@vueuse/metadata@14.1.0': {} - '@vueuse/shared@14.1.0(vue@3.5.25)': + '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': dependencies: - vue: 3.5.25 + vue: 3.5.25(typescript@5.9.3) acorn-jsx@5.3.2(acorn@8.14.1): dependencies: @@ -2264,6 +2641,15 @@ snapshots: asynckit@0.4.0: {} + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001780 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + axios@1.11.0: dependencies: follow-redirects: 1.15.11 @@ -2274,6 +2660,8 @@ snapshots: balanced-match@1.0.2: {} + baseline-browser-mapping@2.10.9: {} + birpc@2.9.0: {} brace-expansion@1.1.11: @@ -2283,11 +2671,19 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001715 + caniuse-lite: 1.0.30001780 electron-to-chromium: 1.5.141 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.9 + caniuse-lite: 1.0.30001780 + electron-to-chromium: 1.5.321 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2295,7 +2691,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001715: {} + caniuse-lite@1.0.30001780: {} ccount@2.0.1: {} @@ -2336,6 +2732,8 @@ snapshots: csstype@3.1.3: {} + csstype@3.2.3: {} + debug@4.4.0: dependencies: ms: 2.1.3 @@ -2346,6 +2744,8 @@ snapshots: dequal@2.0.3: {} + detect-libc@2.1.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -2358,6 +2758,13 @@ snapshots: electron-to-chromium@1.5.141: {} + electron-to-chromium@1.5.321: {} + + enhanced-resolve@5.20.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + entities@4.5.0: {} es-define-property@1.0.1: {} @@ -2407,13 +2814,13 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@5.2.0(eslint@9.25.1): + eslint-plugin-react-hooks@5.2.0(eslint@9.25.1(jiti@2.6.1)): dependencies: - eslint: 9.25.1 + eslint: 9.25.1(jiti@2.6.1) - eslint-plugin-react-refresh@0.4.20(eslint@9.25.1): + eslint-plugin-react-refresh@0.4.20(eslint@9.25.1(jiti@2.6.1)): dependencies: - eslint: 9.25.1 + eslint: 9.25.1(jiti@2.6.1) eslint-scope@8.3.0: dependencies: @@ -2424,9 +2831,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.25.1: + eslint@9.25.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1) + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.1 @@ -2461,6 +2868,8 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -2528,6 +2937,8 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + fraction.js@5.3.4: {} + fsevents@2.3.3: optional: true @@ -2565,6 +2976,8 @@ snapshots: gopd@1.2.0: {} + graceful-fs@4.2.11: {} + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -2620,6 +3033,8 @@ snapshots: isexe@2.0.0: {} + jiti@2.6.1: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -2645,6 +3060,55 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -2714,6 +3178,8 @@ snapshots: node-releases@2.0.19: {} + node-releases@2.0.36: {} + oniguruma-parser@0.12.1: {} oniguruma-to-es@4.3.4: @@ -2755,13 +3221,9 @@ snapshots: picomatch@4.0.3: {} - postcss@8.5.3: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 + postcss-value-parser@4.2.0: {} - postcss@8.5.6: + postcss@8.5.8: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -2896,6 +3358,10 @@ snapshots: tabbable@6.3.0: {} + tailwindcss@4.2.2: {} + + tapable@2.3.0: {} + tinyglobby@0.2.13: dependencies: fdir: 6.4.4(picomatch@4.0.2) @@ -2912,6 +3378,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + typescript@5.9.3: {} + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -2941,6 +3409,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -2955,29 +3429,33 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@6.3.3: + vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.25.3 fdir: 6.4.4(picomatch@4.0.2) picomatch: 4.0.2 - postcss: 8.5.3 + postcss: 8.5.8 rollup: 4.40.0 tinyglobby: 0.2.13 optionalDependencies: fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 - vite@7.2.7: + vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.25.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 - vitepress@2.0.0-alpha.15(axios@1.11.0)(postcss@8.5.6): + vitepress@2.0.0-alpha.15(axios@1.11.0)(jiti@2.6.1)(lightningcss@1.32.0)(postcss@8.5.8)(typescript@5.9.3): dependencies: '@docsearch/css': 4.3.2 '@docsearch/js': 4.3.2 @@ -2986,19 +3464,19 @@ snapshots: '@shikijs/transformers': 3.20.0 '@shikijs/types': 3.20.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 6.0.3(vite@7.2.7)(vue@3.5.25) + '@vitejs/plugin-vue': 6.0.3(vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0))(vue@3.5.25(typescript@5.9.3)) '@vue/devtools-api': 8.0.5 '@vue/shared': 3.5.25 - '@vueuse/core': 14.1.0(vue@3.5.25) - '@vueuse/integrations': 14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25) + '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) + '@vueuse/integrations': 14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25(typescript@5.9.3)) focus-trap: 7.6.6 mark.js: 8.11.1 minisearch: 7.2.0 shiki: 3.20.0 - vite: 7.2.7 - vue: 3.5.25 + vite: 7.2.7(jiti@2.6.1)(lightningcss@1.32.0) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: - postcss: 8.5.6 + postcss: 8.5.8 transitivePeerDependencies: - '@types/node' - async-validator @@ -3024,13 +3502,15 @@ snapshots: - universal-cookie - yaml - vue@3.5.25: + vue@3.5.25(typescript@5.9.3): dependencies: '@vue/compiler-dom': 3.5.25 '@vue/compiler-sfc': 3.5.25 '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25) + '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) '@vue/shared': 3.5.25 + optionalDependencies: + typescript: 5.9.3 which@2.0.2: dependencies: From 7162a1d9583944a9833b2884074be48ae883e0af Mon Sep 17 00:00:00 2001 From: darshak-7span Date: Fri, 20 Mar 2026 18:51:55 +0530 Subject: [PATCH 5/9] Update package version to 1.1.0 for @7span/react-list --- packages/react-list/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 6163710..9ed6aa8 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -1,6 +1,6 @@ { "name": "@7span/react-list", - "version": "1.0.2", + "version": "1.1.0", "description": "A simple and reusable list component for React", "type": "module", "scripts": { From 118f9f73dca1fecee370a1708c4737e640a2cd80 Mon Sep 17 00:00:00 2001 From: darshak-7span Date: Fri, 20 Mar 2026 18:56:05 +0530 Subject: [PATCH 6/9] Revert "Update package version to 1.1.0 for @7span/react-list" This reverts commit 7162a1d9583944a9833b2884074be48ae883e0af. --- packages/react-list/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 9ed6aa8..6163710 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -1,6 +1,6 @@ { "name": "@7span/react-list", - "version": "1.1.0", + "version": "1.0.2", "description": "A simple and reusable list component for React", "type": "module", "scripts": { From c7842fee441853a5ba079f2d5a72a626cae3a184 Mon Sep 17 00:00:00 2001 From: darshak-7span Date: Fri, 20 Mar 2026 18:58:42 +0530 Subject: [PATCH 7/9] Revert "Enhance playground and TypeScript setup: integrate Tailwind CSS, update dependencies, and add new components for improved list functionality." This reverts commit bafe2908267536c12650cd87ec2f8b3974b54fa4. --- apps/playground-typescript/index.html | 14 - apps/playground-typescript/package.json | 29 - apps/playground-typescript/postcss.config.mjs | 6 - apps/playground-typescript/src/App.tsx | 6 - .../src/api/request-handler.ts | 87 --- .../src/components/list-wrapper.tsx | 298 -------- .../src/components/react-list.ts | 75 -- apps/playground-typescript/src/index.css | 2 - apps/playground-typescript/src/main.tsx | 11 - apps/playground-typescript/tailwind.config.js | 8 - apps/playground-typescript/tsconfig.json | 16 - apps/playground-typescript/vite.config.ts | 7 - apps/playground/package.json | 10 +- apps/playground/postcss.config.js | 6 - .../src/components/list-wrapper.jsx | 654 ++++++++++-------- apps/playground/src/index.css | 10 +- apps/playground/tailwind.config.js | 9 - packages/react-list/package.json | 21 +- .../react-list/src/components/attributes.jsx | 53 ++ .../react-list/src/components/attributes.tsx | 87 --- .../src/components/{empty.tsx => empty.jsx} | 6 +- .../src/components/{error.tsx => error.jsx} | 9 +- .../src/components/{go-to.tsx => go-to.jsx} | 20 +- .../src/components/initial-loader.jsx | 25 + .../src/components/initial-loader.tsx | 40 -- .../src/components/{items.tsx => items.jsx} | 24 +- .../src/components/{list.tsx => list.jsx} | 94 +-- .../{load-more.tsx => load-more.jsx} | 14 +- packages/react-list/src/components/loader.jsx | 29 + packages/react-list/src/components/loader.tsx | 39 -- .../{pagination.tsx => pagination.jsx} | 46 +- .../components/{per-page.tsx => per-page.jsx} | 48 +- .../components/{refresh.tsx => refresh.jsx} | 18 +- packages/react-list/src/components/search.jsx | 59 ++ packages/react-list/src/components/search.tsx | 75 -- .../components/{summary.tsx => summary.jsx} | 23 +- .../src/components/{utils.ts => utils.js} | 23 +- .../react-list/src/context/list-provider.jsx | 55 ++ .../react-list/src/context/list-provider.tsx | 91 --- .../react-list/src/{index.ts => index.js} | 22 - packages/react-list/src/types/index.ts | 22 - .../react-list/src/types/list-provider.ts | 156 ----- packages/react-list/src/types/react-list.ts | 39 -- .../react-list/src/{utils.ts => utils.js} | 0 packages/react-list/tsconfig.build.json | 18 - packages/react-list/tsconfig.json | 6 - pnpm-lock.yaml | 616 ++--------------- 47 files changed, 723 insertions(+), 2303 deletions(-) delete mode 100644 apps/playground-typescript/index.html delete mode 100644 apps/playground-typescript/package.json delete mode 100644 apps/playground-typescript/postcss.config.mjs delete mode 100644 apps/playground-typescript/src/App.tsx delete mode 100644 apps/playground-typescript/src/api/request-handler.ts delete mode 100644 apps/playground-typescript/src/components/list-wrapper.tsx delete mode 100644 apps/playground-typescript/src/components/react-list.ts delete mode 100644 apps/playground-typescript/src/index.css delete mode 100644 apps/playground-typescript/src/main.tsx delete mode 100644 apps/playground-typescript/tailwind.config.js delete mode 100644 apps/playground-typescript/tsconfig.json delete mode 100644 apps/playground-typescript/vite.config.ts delete mode 100644 apps/playground/postcss.config.js delete mode 100644 apps/playground/tailwind.config.js create mode 100644 packages/react-list/src/components/attributes.jsx delete mode 100644 packages/react-list/src/components/attributes.tsx rename packages/react-list/src/components/{empty.tsx => empty.jsx} (77%) rename packages/react-list/src/components/{error.tsx => error.jsx} (72%) rename packages/react-list/src/components/{go-to.tsx => go-to.jsx} (73%) create mode 100644 packages/react-list/src/components/initial-loader.jsx delete mode 100644 packages/react-list/src/components/initial-loader.tsx rename packages/react-list/src/components/{items.tsx => items.jsx} (64%) rename packages/react-list/src/components/{list.tsx => list.jsx} (81%) rename packages/react-list/src/components/{load-more.tsx => load-more.jsx} (71%) create mode 100644 packages/react-list/src/components/loader.jsx delete mode 100644 packages/react-list/src/components/loader.tsx rename packages/react-list/src/components/{pagination.tsx => pagination.jsx} (76%) rename packages/react-list/src/components/{per-page.tsx => per-page.jsx} (55%) rename packages/react-list/src/components/{refresh.tsx => refresh.jsx} (63%) create mode 100644 packages/react-list/src/components/search.jsx delete mode 100644 packages/react-list/src/components/search.tsx rename packages/react-list/src/components/{summary.tsx => summary.jsx} (72%) rename packages/react-list/src/components/{utils.ts => utils.js} (51%) create mode 100644 packages/react-list/src/context/list-provider.jsx delete mode 100644 packages/react-list/src/context/list-provider.tsx rename packages/react-list/src/{index.ts => index.js} (64%) delete mode 100644 packages/react-list/src/types/index.ts delete mode 100644 packages/react-list/src/types/list-provider.ts delete mode 100644 packages/react-list/src/types/react-list.ts rename packages/react-list/src/{utils.ts => utils.js} (100%) delete mode 100644 packages/react-list/tsconfig.build.json delete mode 100644 packages/react-list/tsconfig.json diff --git a/apps/playground-typescript/index.html b/apps/playground-typescript/index.html deleted file mode 100644 index fa41216..0000000 --- a/apps/playground-typescript/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Vite + React (TypeScript) - - -
- - - - diff --git a/apps/playground-typescript/package.json b/apps/playground-typescript/package.json deleted file mode 100644 index 3416511..0000000 --- a/apps/playground-typescript/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "playground-typescript", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "typecheck": "tsc -p tsconfig.json --noEmit", - "preview": "vite preview" - }, - "dependencies": { - "@7span/react-list": "workspace:*", - "@iconify/react": "^5.2.1", - "react": "^19.0.0", - "react-dom": "^19.0.0" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.2.2", - "@types/react": "^19.0.10", - "@types/react-dom": "^19.0.4", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.27", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.2", - "typescript": "^5.9.3", - "vite": "^6.3.1" - } -} diff --git a/apps/playground-typescript/postcss.config.mjs b/apps/playground-typescript/postcss.config.mjs deleted file mode 100644 index 51a6e4e..0000000 --- a/apps/playground-typescript/postcss.config.mjs +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - '@tailwindcss/postcss': {}, - autoprefixer: {}, - }, -}; diff --git a/apps/playground-typescript/src/App.tsx b/apps/playground-typescript/src/App.tsx deleted file mode 100644 index 92febc7..0000000 --- a/apps/playground-typescript/src/App.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import ListWrapper from './components/list-wrapper'; - -export default function App() { - return ; -} - diff --git a/apps/playground-typescript/src/api/request-handler.ts b/apps/playground-typescript/src/api/request-handler.ts deleted file mode 100644 index e6b611a..0000000 --- a/apps/playground-typescript/src/api/request-handler.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { ReactListRequestArgs, ReactListResponse } from '@7span/react-list'; - -export type PlaygroundItem = { - id: number; - name: string; - status?: string; - date_updated?: string; - [key: string]: unknown; -}; - -type Filters = Record; - -const requestHandler = async ( - args: ReactListRequestArgs, -): Promise> => { - const { - endpoint, - page, - perPage, - search, - sortBy, - sortOrder, - filters, - meta, - } = args; - - const params = new URLSearchParams(); - - if (page && perPage) { - params.append('page', String(page)); - params.append('limit', String(perPage)); - } - - if (search) params.append('search', search); - - if (sortBy) { - params.append( - 'sort', - sortOrder === 'desc' ? `-${sortBy}` : sortBy, - ); - } - - if (filters && Object.keys(filters).length > 0) { - // Keep it simple for the playground. - for (const [key, value] of Object.entries(filters)) { - if (value === undefined || value === '') continue; - params.append(`filter[${key}][_eq]`, String(value)); - } - } - - // Example: meta support (not required by ReactList, just forwarded in args) - if (meta && typeof meta === 'object') { - // noop; you can add meta params here. - } - - const queryString = params.toString(); - const url = `https://everest.7span.in/items/${endpoint}${ - queryString ? `?${queryString}` : '' - }`; - - try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`API request failed: ${response.status}`); - } - const data: any = await response.json(); - - return { - items: (data.data ?? []) as PlaygroundItem[], - count: - data.meta?.total_count ?? - data.meta?.filter_count ?? - 0, - meta: data.meta ?? {}, - }; - } catch (error) { - return { - items: [], - count: 0, - meta: {}, - error: error instanceof Error ? error : undefined, - } as unknown as ReactListResponse; - } -}; - -export default requestHandler; - diff --git a/apps/playground-typescript/src/components/list-wrapper.tsx b/apps/playground-typescript/src/components/list-wrapper.tsx deleted file mode 100644 index 02e2641..0000000 --- a/apps/playground-typescript/src/components/list-wrapper.tsx +++ /dev/null @@ -1,298 +0,0 @@ -import { useMemo, useState } from "react"; - -import ReactList, { - ReactListEmpty, - ReactListError, - ReactListGoTo, - ReactListInitialLoader, - ReactListItems, - ReactListLoader, - ReactListPagination, - ReactListPerPage, - ReactListProvider, - ReactListSearch, - ReactListSummary, -} from "@7span/react-list"; - -import { Icon } from "@iconify/react"; - -import reactListOptions from "./react-list"; -import type { PlaygroundItem } from "../api/request-handler"; - -type Filters = Record; - -export default function ListWrapper() { - const [filters, setFilters] = useState({}); - const paginationMode = "pagination" as const; - - // Stable render-prop children for the search component. - const searchChildren = useMemo( - () => - ({ - search, - setSearch, - }: { - search: string; - setSearch: (value: string) => void; - }) => ( -
- setSearch(e.target.value)} - placeholder="Search skills..." - className="w-full rounded-md border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500" - /> -
- ), - [], - ); - - return ( -
-
- - -
-

- React List TypeScript Playground -

- -
- {searchChildren} - - -
-
- -
- -
-
-
- {[0, 1, 2, 3].map((i) => ( -
- ))} -
-
- - -
-
- -
-
- No data found -
-
-
- - - {({ error }: { error: Error }) => ( -
-
- -
-
{error.name}
-
{error.message}
-
-
-
- )} -
- - - {({ items }) => ( -
- {items.map((item, idx) => { - const row = item as PlaygroundItem; - - return ( -
-
-
- ID {row?.id} -
- -
- {row?.name} -
- -
- Updated:{" "} - {row?.date_updated - ? new Date( - row.date_updated, - ).toLocaleString() - : "-"} -
-
- -
- {row?.status ?? "-"} -
-
- ); - })} -
- )} -
-
- -
- - {({ isLoading }: { isLoading: boolean }) => - isLoading ? ( -
- Loading... -
- ) : null - } -
-
-
- -
-
- - {({ visibleCount, count }) => ( -
- {visibleCount} results - {typeof count === "number" ? ` (total ${count})` : ""} -
- )} -
- -
- - {({ perPage, setPerPage, options }) => ( - - )} - - - - {({ setPage, page, pagesCount }) => ( -
- setPage(Number(e.target.value))} - className="w-20 rounded-md border border-gray-200 bg-white px-3 py-2 text-sm shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500" - /> - - of {pagesCount} - -
- )} -
- - - {({ - page, - pagesToDisplay, - hasPrev, - hasNext, - prev, - next, - first, - last, - setPage, - }) => ( -
- - - - -
- {pagesToDisplay.map((p) => ( - - ))} -
- - - - -
- )} -
-
-
-
-
- - -
-
- ); -} diff --git a/apps/playground-typescript/src/components/react-list.ts b/apps/playground-typescript/src/components/react-list.ts deleted file mode 100644 index ed965c9..0000000 --- a/apps/playground-typescript/src/components/react-list.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { - ReactListProviderConfig, - ReactListRequestArgs, - ReactListResponse, - ReactListStateManager, -} from "@7span/react-list"; - -import requestHandler from "../api/request-handler"; -import type { PlaygroundItem } from "../api/request-handler"; - -type Filters = Record; - -const stateManagerKey = (endpoint: string, version: number) => - `react-list--${endpoint}--${version}`; - -const stateManager: ReactListStateManager = { - init(context: any) { - const { endpoint, version } = context; - const allKeys = `react-list--${endpoint}--`; - const latestKey = stateManagerKey(endpoint, version); - - const staleKeys = Object.keys(localStorage).filter( - (key) => key.startsWith(allKeys) && key !== latestKey, - ); - staleKeys.forEach((key) => localStorage.removeItem(key)); - }, - set(context: any) { - const { - endpoint, - version, - search, - page, - perPage, - sortBy, - sortOrder, - filters, - attrSettings, - } = context; - - const key = stateManagerKey(endpoint, version); - localStorage.setItem( - key, - JSON.stringify({ - search, - page, - perPage, - sortBy, - sortOrder, - filters, - attrSettings, - }), - ); - }, - get(context: any) { - const { endpoint, version } = context; - const key = stateManagerKey(endpoint, version); - - try { - const raw = localStorage.getItem(key); - if (!raw) return null; - return JSON.parse(raw) as any; - } catch { - return null; - } - }, -}; - -const config: ReactListProviderConfig = { - requestHandler: requestHandler as unknown as ( - args: ReactListRequestArgs, - ) => Promise>, - stateManager, -}; - -export default config; diff --git a/apps/playground-typescript/src/index.css b/apps/playground-typescript/src/index.css deleted file mode 100644 index d1d9133..0000000 --- a/apps/playground-typescript/src/index.css +++ /dev/null @@ -1,2 +0,0 @@ -@import "tailwindcss"; -@source "../**/*.{js,jsx,ts,tsx}"; \ No newline at end of file diff --git a/apps/playground-typescript/src/main.tsx b/apps/playground-typescript/src/main.tsx deleted file mode 100644 index 0c5505f..0000000 --- a/apps/playground-typescript/src/main.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; - -import App from "./App"; -import "./index.css"; - -createRoot(document.getElementById("root")!).render( - - - , -); diff --git a/apps/playground-typescript/tailwind.config.js b/apps/playground-typescript/tailwind.config.js deleted file mode 100644 index a117e69..0000000 --- a/apps/playground-typescript/tailwind.config.js +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ["./index.html", "./src/**/*.{ts,tsx,jsx,js}"], - theme: { - extend: {}, - }, - plugins: [], -}; diff --git a/apps/playground-typescript/tsconfig.json b/apps/playground-typescript/tsconfig.json deleted file mode 100644 index e034b35..0000000 --- a/apps/playground-typescript/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "moduleResolution": "Bundler", - "jsx": "react-jsx", - "strict": true, - "skipLibCheck": true, - "noEmit": true, - "types": ["vite/client"], - "resolveJsonModule": true - }, - "include": ["src"] -} - diff --git a/apps/playground-typescript/vite.config.ts b/apps/playground-typescript/vite.config.ts deleted file mode 100644 index f0c8be1..0000000 --- a/apps/playground-typescript/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [react()], -}); - diff --git a/apps/playground/package.json b/apps/playground/package.json index 90148b5..c903db3 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -10,25 +10,21 @@ "preview": "vite preview" }, "dependencies": { - "@7span/react-list": "workspace:*", - "@iconify/react": "^5.2.1", "axios": "1.11.0", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "@iconify/react": "^5.2.1", + "@7span/react-list": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.22.0", - "@tailwindcss/postcss": "^4.2.2", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.27", "eslint": "^9.22.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", - "postcss": "^8.5.8", - "tailwindcss": "^4.2.2", "vite": "^6.3.1" } } diff --git a/apps/playground/postcss.config.js b/apps/playground/postcss.config.js deleted file mode 100644 index 51a6e4e..0000000 --- a/apps/playground/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - '@tailwindcss/postcss': {}, - autoprefixer: {}, - }, -}; diff --git a/apps/playground/src/components/list-wrapper.jsx b/apps/playground/src/components/list-wrapper.jsx index c8600b0..a74d603 100644 --- a/apps/playground/src/components/list-wrapper.jsx +++ b/apps/playground/src/components/list-wrapper.jsx @@ -1,5 +1,3 @@ -import { useMemo, useState } from 'react'; - import ReactList, { ReactListEmpty, ReactListError, @@ -12,334 +10,416 @@ import ReactList, { ReactListProvider, ReactListSearch, ReactListSummary, -} from '@7span/react-list'; - -import { Icon } from '@iconify/react'; +} from "@7span/react-list"; -import reactListOptions from './react-list'; +import { Icon } from "@iconify/react"; +import { useState } from "react"; -const STATUS_OPTIONS = [ - { label: 'All Status', value: '' }, - { label: 'Draft', value: 'draft' }, - { label: 'Published', value: 'published' }, - { label: 'Archived', value: 'archived' }, -]; +import reactListOptions from "./react-list"; -const COLOR_OPTIONS = [ - { label: 'All Colors', value: '' }, - { label: 'Red', value: '#FF9900' }, - { label: 'Blue', value: '#FFEB0F' }, - { label: 'Green', value: '#F7DF1E' }, - { label: 'Yellow', value: '#5E24FF' }, -]; +import "../app.css"; -export default function ListWrapper() { +const ListWrapper = () => { const [filters, setFilters] = useState({}); - const paginationMode = 'pagination'; - - const searchChildren = useMemo( - () => - ({ search, setSearch }) => ( -
- setSearch(e.target.value)} - placeholder="Search skills..." - className="w-full rounded-md border border-gray-700 bg-gray-900 px-3 py-2 text-sm text-gray-100 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20" - /> -
- ), - [], - ); - return ( -
-
-
-

- React List Playground (Tailwind) -

- -
- - -
- {searchChildren} - +
+

React List Playground

+ + +
+
+ {/* */} + + {({ search, setSearch }) => ( +
+ { + setSearch(e.target.value); + }} + placeholder="Search skills..." + className="search-input" + /> +
+ )} +
+
+
+
+
+ +
+ +
+
+
+ - - +
+ +
- -
- -
-
-
- {[0, 1, 2, 3].map((i) => ( -
- ))} -
+
+
+
+
+ +
+
+
+
+
+
+
+
- - -
- -
-
- No data found -
+
+
+ {[...Array(5)].map((_, index) => ( +
+
+
+
+
- - - - {({ error }) => ( -
-
- -
-
{error.name}
-
{error.message}
-
-
-
- )} -
- - - {({ items }) => ( -
- {items.map((item, idx) => { - const row = item ?? {}; - return ( -
-
-
- ID {row.id} -
- -
- {row.name} -
+ ))} +
+
+
+ + +
+
+
+
+ +
+
-
- Updated:{' '} - {row.date_updated - ? new Date( - row.date_updated, - ).toLocaleString() - : '-'} -
-
+

No Data Found

-
- {row.status ?? '-'} -
-
- ); - })} -
- )} - +

+ We couldn't find any matching records. Try adjusting your + search or filters. +

+ +
+ + + {({ error }) => ( +
+
+ +
+

Something went wrong

+

+ {error.message || + "An unexpected error occurred while fetching data."} +

+
+

+ {error.name}: {error.message} +

+
+ +
+ )} +
+ + {({ items, sort, setSort }) => { + return ( +
- {({ isLoading }) => - isLoading ? ( -
- Loading... -
- ) : null - } +
+
+ +
+
-
- -
-
- - {({ visibleCount, count }) => ( -
- {visibleCount} results - {typeof count === 'number' - ? ` (total ${count})` - : ''} -
- )} -
+ + + + + + + + + + + {items.map((item) => ( + + + + + + + ))} + +
ID + Name{" "} + + Status + Update At{" "} + - + setSort({ + ...sort, + by: "date_updated", // Update the sortBy state t + order: sorting, + }); + }} + > + + +
{item.id}{item.name}{item.status} + {new Date(item.date_updated).toLocaleString()} +
+
+ ); + }} + + {/* Footer */} +
+
+
+ + {({ visibleCount }) => ( + + {visibleCount} Results + + )} + +
-
- {pagesToDisplay.map((p) => ( - - ))} -
+
+ Page Size: + + {({ perPage, setPerPage, options }) => ( +
+ +
+ +
+
+ )} +
+
- - -
- )} - +
+ + {({ setPage, page, pagesCount }) => ( +
+ Go to: + { + const page = Number(e.target.value); + setPage(page); + }} + className="page-input" + /> + of {pagesCount}
+ )} +
+
+
+ + + {({ + page, + pagesToDisplay, + hasNext, + hasPrev, + prev, + next, + first, + last, + setPage, + }) => ( +
+ + + + +
+ {pagesToDisplay.map((item, index) => { + const isActive = item === page; + + return ( + + ); + })}
+ + + +
-
- - + )} + +
-
-
+ +
); -} +}; +export default ListWrapper; diff --git a/apps/playground/src/index.css b/apps/playground/src/index.css index a50c033..08a3ac9 100644 --- a/apps/playground/src/index.css +++ b/apps/playground/src/index.css @@ -1,6 +1,3 @@ -@import "tailwindcss"; -@source "../**/*.{js,jsx,ts,tsx}"; - :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -21,7 +18,6 @@ a { color: #646cff; text-decoration: inherit; } - a:hover { color: #535bf2; } @@ -50,11 +46,9 @@ button { cursor: pointer; transition: border-color 0.25s; } - button:hover { border-color: #646cff; } - button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; @@ -65,12 +59,10 @@ button:focus-visible { color: #213547; background-color: #ffffff; } - a:hover { color: #747bff; } - button { background-color: #f9f9f9; } -} \ No newline at end of file +} diff --git a/apps/playground/tailwind.config.js b/apps/playground/tailwind.config.js deleted file mode 100644 index 524f96e..0000000 --- a/apps/playground/tailwind.config.js +++ /dev/null @@ -1,9 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'], - theme: { - extend: {}, - }, - plugins: [], -}; - diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 6163710..7423430 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -5,22 +5,12 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build && pnpm run build:types", - "build:types": "tsc -p tsconfig.build.json", + "build": "vite build", "lint": "eslint .", "preview": "vite preview", - "prepublishOnly": "pnpm run build" - }, - "main": "dist/react-list.cjs", - "module": "dist/react-list.js", - "types": "dist/types/index.d.ts", - "exports": { - ".": { - "types": "./dist/types/index.d.ts", - "import": "./dist/react-list.js", - "require": "./dist/react-list.cjs" - } + "prepublishOnly": "npm run build" }, + "main": "dist/react-list.js", "files": [ "dist" ], @@ -32,10 +22,7 @@ "react-dom": "^18.2.0 || ^19.0.0" }, "devDependencies": { - "@types/react": "^19.1.13", - "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^4.3.4", - "typescript": "^5.9.3", "vite": "^6.3.1" } -} \ No newline at end of file +} diff --git a/packages/react-list/src/components/attributes.jsx b/packages/react-list/src/components/attributes.jsx new file mode 100644 index 0000000..b3fc189 --- /dev/null +++ b/packages/react-list/src/components/attributes.jsx @@ -0,0 +1,53 @@ +import { memo, useCallback, useMemo } from "react"; +import { useListContext } from "../context/list-provider"; + +export const ReactListAttributes = memo(({ children, renderAttribute }) => { + const { listState } = useListContext(); + const { attrs, attrSettings, updateAttr } = listState; + + const handleAttrChange = useCallback( + (attrName) => (e) => { + updateAttr(attrName, "visible", e.target.checked); + }, + [updateAttr] + ); + + const scope = useMemo( + () => ({ + attrs, + attrSettings, + updateAttr, + }), + [attrs, attrSettings, updateAttr] + ); + + if (children) { + return children(scope); + } + + return ( +
+ {attrs.map((attr, index) => { + if (renderAttribute) { + return renderAttribute({ + key: `attr-${index}`, + attr, + updateAttr, + attrSettings, + }); + } + + return ( + + ); + })} +
+ ); +}); diff --git a/packages/react-list/src/components/attributes.tsx b/packages/react-list/src/components/attributes.tsx deleted file mode 100644 index fa4e2d7..0000000 --- a/packages/react-list/src/components/attributes.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { memo, useCallback, useMemo } from "react"; -import { useListContext } from "../context/list-provider"; -import type { ReactListAttrSettings, ReactListAttribute } from "../types"; -import type { ChangeEvent, ReactNode } from "react"; - -type ReactListAttributesUpdateAttr = ( - attrName: string, - settingKey: string, - value: unknown, -) => void; - -type ReactListAttributesScope = { - attrs: ReactListAttribute[]; - attrSettings: ReactListAttrSettings; - updateAttr: ReactListAttributesUpdateAttr; -}; - -type ReactListAttributesRenderAttributeArgs = { - key: string; - attr: ReactListAttribute; - updateAttr: ReactListAttributesUpdateAttr; - attrSettings: ReactListAttrSettings; -}; - -type ReactListAttributesProps = { - children?: ReactNode | ((scope: ReactListAttributesScope) => ReactNode); - renderAttribute?: (args: ReactListAttributesRenderAttributeArgs) => ReactNode; -}; - -export const ReactListAttributes = memo( - ({ children, renderAttribute }: ReactListAttributesProps) => { - const { listState } = useListContext(); - const { attrs, attrSettings, updateAttr } = listState; - - const handleAttrChange = useCallback( - (attrName: string) => (e: ChangeEvent) => { - updateAttr(attrName, "visible", e.target.checked); - }, - [updateAttr], - ); - - const scope = useMemo( - () => ({ - attrs, - attrSettings, - updateAttr, - }), - [attrs, attrSettings, updateAttr], - ); - - if (typeof children === "function") { - return children(scope); - } - - if (children) return children; - - return ( -
- {attrs.map((attr, index) => { - if (renderAttribute) { - return ( - - {renderAttribute({ - key: `attr-${index}`, - attr, - updateAttr, - attrSettings, - })} - - ); - } - - return ( - - ); - })} -
- ); - }, -); diff --git a/packages/react-list/src/components/empty.tsx b/packages/react-list/src/components/empty.jsx similarity index 77% rename from packages/react-list/src/components/empty.tsx rename to packages/react-list/src/components/empty.jsx index c97be07..40dbeed 100644 --- a/packages/react-list/src/components/empty.tsx +++ b/packages/react-list/src/components/empty.jsx @@ -1,11 +1,7 @@ import { memo } from "react"; import { useListContext } from "../context/list-provider"; -type ReactListEmptyProps = { - children?: React.ReactNode; -}; - -export const ReactListEmpty = memo(({ children }: ReactListEmptyProps) => { +export const ReactListEmpty = memo(({ children }) => { const { listState } = useListContext(); const { data: items, loader, error } = listState; const { isLoading, initialLoading } = loader; diff --git a/packages/react-list/src/components/error.tsx b/packages/react-list/src/components/error.jsx similarity index 72% rename from packages/react-list/src/components/error.tsx rename to packages/react-list/src/components/error.jsx index 476b5d0..957ad19 100644 --- a/packages/react-list/src/components/error.tsx +++ b/packages/react-list/src/components/error.jsx @@ -1,14 +1,7 @@ import { memo } from "react"; -import type { ReactNode } from "react"; import { useListContext } from "../context/list-provider"; -type ReactListErrorProps = { - children?: - | ReactNode - | ((scope: { error: Error }) => ReactNode); -}; - -export const ReactListError = memo(({ children }: ReactListErrorProps) => { +export const ReactListError = memo(({ children }) => { const { listState } = useListContext(); const { error, loader } = listState; const { isLoading } = loader; diff --git a/packages/react-list/src/components/go-to.tsx b/packages/react-list/src/components/go-to.jsx similarity index 73% rename from packages/react-list/src/components/go-to.tsx rename to packages/react-list/src/components/go-to.jsx index a076d86..361162b 100644 --- a/packages/react-list/src/components/go-to.tsx +++ b/packages/react-list/src/components/go-to.jsx @@ -1,21 +1,7 @@ import { memo, useCallback, useMemo } from "react"; -import type { ReactNode } from "react"; import { useListContext } from "../context/list-provider"; -type ReactListGoToScope = { - setPage: (page: number, addContext?: Record) => void; - page: number; - pages: number[]; - pagesCount: number; -}; - -type ReactListGoToProps = { - children?: - | ReactNode - | ((scope: ReactListGoToScope) => ReactNode); -}; - -export const ReactListGoTo = memo(({ children }: ReactListGoToProps) => { +export const ReactListGoTo = memo(({ children }) => { const { listState } = useListContext(); const { data, count, pagination, setPage, loader, error } = listState; const { page, perPage } = pagination; @@ -56,10 +42,8 @@ export const ReactListGoTo = memo(({ children }: ReactListGoToProps) => { return (
- {typeof children === "function" ? ( + {children ? ( children(scope) - ) : children ? ( - children ) : ( handleChange(e.target.value)} + placeholder="Search..." + /> + )} +
+ ); +}); diff --git a/packages/react-list/src/components/search.tsx b/packages/react-list/src/components/search.tsx deleted file mode 100644 index 0eb7d1c..0000000 --- a/packages/react-list/src/components/search.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { memo, useEffect, useRef, useState } from "react"; -import type { ReactNode } from "react"; - -import { useListContext } from "../context/list-provider"; - -type ReactListSearchScope = { - search: string; - setSearch: (value: string) => void; -}; - -type ReactListSearchProps = { - debounceTime?: number; - children?: ReactNode | ((scope: ReactListSearchScope) => ReactNode); -}; - -export const ReactListSearch = memo( - ({ children, debounceTime = 500 }: ReactListSearchProps) => { - const { listState } = useListContext(); - const { search, setSearch } = listState; - - const [localSearch, setLocalSearch] = useState(search ?? ""); - const debounceTimerRef = useRef | null>(null); - - // Sync local state with context when the list search value changes. - useEffect(() => { - if (search !== localSearch) { - setLocalSearch(search ?? ""); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [search]); - - const handleChange = (value: string) => { - setLocalSearch(value); - - if (debounceTimerRef.current) { - clearTimeout(debounceTimerRef.current); - } - - debounceTimerRef.current = setTimeout(() => { - setSearch(value); - }, debounceTime); - }; - - useEffect(() => { - return () => { - if (debounceTimerRef.current) { - clearTimeout(debounceTimerRef.current); - } - }; - }, []); - - const scope: ReactListSearchScope = { - search: localSearch, - setSearch: handleChange, - }; - - return ( -
- {typeof children === "function" ? ( - children(scope) - ) : children ? ( - children - ) : ( - handleChange(e.target.value)} - placeholder="Search..." - /> - )} -
- ); - } -); - diff --git a/packages/react-list/src/components/summary.tsx b/packages/react-list/src/components/summary.jsx similarity index 72% rename from packages/react-list/src/components/summary.tsx rename to packages/react-list/src/components/summary.jsx index a360b0a..284da5c 100644 --- a/packages/react-list/src/components/summary.tsx +++ b/packages/react-list/src/components/summary.jsx @@ -1,21 +1,7 @@ import { memo, useMemo } from "react"; import { useListContext } from "../context/list-provider"; -import type { ReactNode } from "react"; - -type ReactListSummaryScope = { - from: number; - to: number; - visibleCount: number; - count: number; -}; - -type ReactListSummaryProps = { - children?: ReactNode | ((scope: ReactListSummaryScope) => ReactNode); -}; - -export const ReactListSummary = memo( - ({ children }: ReactListSummaryProps) => { +export const ReactListSummary = memo(({ children }) => { const { listState } = useListContext(); const { data, count, pagination, loader, error } = listState; const { page, perPage } = pagination; @@ -49,10 +35,8 @@ export const ReactListSummary = memo( return (
- {typeof children === "function" ? ( + {children ? ( children(scope) - ) : children ? ( - children ) : ( Showing {summaryData.visibleCount} items ( @@ -64,5 +48,4 @@ export const ReactListSummary = memo( )}
); - } -); +}); diff --git a/packages/react-list/src/components/utils.ts b/packages/react-list/src/components/utils.js similarity index 51% rename from packages/react-list/src/components/utils.ts rename to packages/react-list/src/components/utils.js index e9f4e33..f4a7279 100644 --- a/packages/react-list/src/components/utils.ts +++ b/packages/react-list/src/components/utils.js @@ -1,11 +1,10 @@ -export const deepEqual = (obj1: unknown, obj2: unknown): boolean => { +export const deepEqual = (obj1, obj2) => { if (obj1 === obj2) return true; if (obj1 == null || obj2 == null) return obj1 === obj2; - if (typeof obj1 !== "object" || typeof obj2 !== "object") { + if (typeof obj1 !== "object" || typeof obj2 !== "object") return obj1 === obj2; - } if (Array.isArray(obj1) && Array.isArray(obj2)) { if (obj1.length !== obj2.length) return false; @@ -17,28 +16,22 @@ export const deepEqual = (obj1: unknown, obj2: unknown): boolean => { if (Array.isArray(obj1) || Array.isArray(obj2)) return false; - const record1 = obj1 as Record; - const record2 = obj2 as Record; - - const keys1 = Object.keys(record1).filter((key) => record1[key] !== undefined); - const keys2 = Object.keys(record2).filter((key) => record2[key] !== undefined); + const keys1 = Object.keys(obj1).filter((key) => obj1[key] !== undefined); + const keys2 = Object.keys(obj2).filter((key) => obj2[key] !== undefined); if (keys1.length !== keys2.length) return false; - for (const key of keys1) { + for (let key of keys1) { if (!keys2.includes(key)) return false; - if (!deepEqual(record1[key], record2[key])) return false; + if (!deepEqual(obj1[key], obj2[key])) return false; } return true; }; -export const hasActiveFilters = ( - currentFilters: Record | null | undefined, - initialFilters: Record | null | undefined -): boolean => { +export const hasActiveFilters = (currentFilters, initialFilters) => { if (!initialFilters || Object.keys(initialFilters).length === 0) { - return !!currentFilters && Object.keys(currentFilters).length > 0; + return currentFilters && Object.keys(currentFilters).length > 0; } if (!currentFilters || Object.keys(currentFilters).length === 0) { diff --git a/packages/react-list/src/context/list-provider.jsx b/packages/react-list/src/context/list-provider.jsx new file mode 100644 index 0000000..bd4e21a --- /dev/null +++ b/packages/react-list/src/context/list-provider.jsx @@ -0,0 +1,55 @@ +import { createContext, useContext, useMemo, useState } from "react"; + +const ListContext = createContext(null); + +export const ReactListProvider = ({ children, config }) => { + const { requestHandler, stateManager = {} } = config; + const [listState, setListState] = useState({ + data: [], + response: null, + error: null, + count: 0, + selection: [], + pagination: { + page: 1, + perPage: 25, + }, + loader: { + isLoading: false, + initialLoading: true, + }, + sort: { + sortBy: null, + sortOrder: "desc", + }, + search: "", + filters: {}, + attrs: [], + isEmpty: true, + isInitializing: true, + }); + + if (!requestHandler) { + throw new Error("ListProvider: requestHandler is required."); + } + + const value = useMemo( + () => ({ + requestHandler, + stateManager, + listState, + setListState, + }), + [requestHandler, stateManager, listState] + ); + + return {children}; +}; + +export const useListContext = () => { + const context = useContext(ListContext); + if (!context) { + throw new Error("useListContext must be used within a ListProvider"); + } + return context; +}; diff --git a/packages/react-list/src/context/list-provider.tsx b/packages/react-list/src/context/list-provider.tsx deleted file mode 100644 index 0182397..0000000 --- a/packages/react-list/src/context/list-provider.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { createContext, useContext, useMemo, useState } from "react"; -import type { ReactNode } from "react"; - -import type { - ReactListContextValue, - ReactListFilters, - ReactListItem, - ReactListItemId, - ReactListListState, - ReactListProviderConfig, - ReactListResponse, - ReactListRequestHandler, - ReactListStateManager, -} from "../types"; - -const ListContext = createContext(null); - -type ReactListProviderProps = { - children: ReactNode; - config: ReactListProviderConfig; -}; - -const noop = () => {}; - -export const ReactListProvider = ({ children, config }: ReactListProviderProps) => { - const { requestHandler, stateManager = {} } = config; - - if (!requestHandler) { - throw new Error("ListProvider: requestHandler is required."); - } - - const [listState, setListState] = useState>({ - data: [], - response: null as ReactListResponse | null, - error: null, - count: 0, - selection: [] as ReactListItemId[], - pagination: { - page: 1, - perPage: 25, - hasMore: false, - }, - loader: { - isLoading: false, - initialLoading: true, - }, - sort: { - sortBy: "", - sortOrder: "desc", - }, - hasActiveFilters: false, - search: "", - filters: {}, - attrs: [], - attrSettings: {}, - isEmpty: true, - - // These actions are replaced by `ReactList` once it mounts. - setPage: noop, - setPerPage: noop, - setSearch: noop, - setSort: noop, - loadMore: noop, - clearFilters: noop, - refresh: noop, - setFilters: noop, - updateAttr: noop, - updateItemById: noop, - setSelection: noop, - }); - - const value: ReactListContextValue = useMemo( - () => ({ - requestHandler: requestHandler as ReactListRequestHandler, - stateManager: stateManager as ReactListStateManager, - listState, - setListState, - }), - [requestHandler, stateManager, listState] - ); - - return {children}; -}; - -export const useListContext = (): ReactListContextValue => { - const context = useContext(ListContext); - if (!context) { - throw new Error("useListContext must be used within a ListProvider"); - } - return context; -}; diff --git a/packages/react-list/src/index.ts b/packages/react-list/src/index.js similarity index 64% rename from packages/react-list/src/index.ts rename to packages/react-list/src/index.js index 65eca60..d132e3f 100644 --- a/packages/react-list/src/index.ts +++ b/packages/react-list/src/index.js @@ -13,25 +13,3 @@ export { ReactListRefresh } from "./components/refresh"; export { ReactListSearch } from "./components/search"; export { ReactListSummary } from "./components/summary"; export { ReactListProvider } from "./context/list-provider"; - -export type { - ReactListAttrSettings, - ReactListContext, - ReactListContextValue, - ReactListFilters, - ReactListAttribute, - ReactListProps, - ReactListPaginationMode, - ReactListItem, - ReactListItemId, - ReactListListState, - ReactListLoaderState, - ReactListPaginationState, - ReactListProviderConfig, - ReactListRequestArgs, - ReactListRequestHandler, - ReactListResponse, - ReactListSort, - ReactListSortOrder, - ReactListStateManager, -} from "./types"; diff --git a/packages/react-list/src/types/index.ts b/packages/react-list/src/types/index.ts deleted file mode 100644 index d27aaf5..0000000 --- a/packages/react-list/src/types/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -export type { - ReactListAttrSettings, - ReactListContext, - ReactListContextValue, - ReactListItem, - ReactListItemId, - ReactListListState, - ReactListLoaderState, - ReactListPaginationState, - ReactListProviderConfig, - ReactListRequestArgs, - ReactListRequestHandler, - ReactListResponse, - ReactListSort, - ReactListSortOrder, - ReactListStateManager, - ReactListFilters, - ReactListAttribute, -} from './list-provider.ts'; - -export type { ReactListProps, ReactListPaginationMode } from './react-list'; - diff --git a/packages/react-list/src/types/list-provider.ts b/packages/react-list/src/types/list-provider.ts deleted file mode 100644 index 795ddbd..0000000 --- a/packages/react-list/src/types/list-provider.ts +++ /dev/null @@ -1,156 +0,0 @@ -import type * as React from 'react'; - -export type ReactListItemId = string | number; - -export type ReactListItem = Record & { - id?: ReactListItemId; -}; - -export type ReactListFilters = Record; - -export type ReactListSortOrder = '' | 'asc' | 'desc' | (string & {}); - -export type ReactListAttrSettings = Record< - string, - { - visible: boolean; - } ->; - -export type ReactListRequestArgs< - TFilters extends ReactListFilters = ReactListFilters, -> = { - endpoint: string; - version: number; - meta: Record; - page: number; - perPage: number; - search: string; - sortBy: string; - sortOrder: ReactListSortOrder; - filters: TFilters; -} & Record; - -export type ReactListResponse = { - items: TItem[]; - count: number; - meta?: unknown; - [key: string]: unknown; -}; - -export type ReactListRequestHandler< - TItem = ReactListItem, - TFilters extends ReactListFilters = ReactListFilters, -> = (args: ReactListRequestArgs) => Promise>; - -export type ReactListPersistedState< - TFilters extends ReactListFilters = ReactListFilters, -> = { - page?: number; - perPage?: number; - sortBy?: string; - sortOrder?: ReactListSortOrder; - search?: string; - attrSettings?: ReactListAttrSettings; - filters?: TFilters; -}; - -export type ReactListContext = { - endpoint: string; - version: number; - meta: Record; - search: string; - page: number; - perPage: number; - sortBy: string; - sortOrder: ReactListSortOrder; - filters: TFilters; - attrSettings: ReactListAttrSettings; - isRefresh: boolean; -}; - -export type ReactListStateManager< - TFilters extends ReactListFilters = ReactListFilters, -> = { - init?: (context: ReactListContext) => void; - get?: (context: ReactListContext) => ReactListPersistedState | null; - set?: (context: ReactListContext) => void; -}; - -export type ReactListProviderConfig< - TItem = ReactListItem, - TFilters extends ReactListFilters = ReactListFilters, -> = { - requestHandler: ReactListRequestHandler; - stateManager?: ReactListStateManager; -}; - -export type ReactListPaginationState = { - page: number; - perPage: number; - hasMore: boolean; -}; - -export type ReactListLoaderState = { - isLoading: boolean; - initialLoading: boolean; -}; - -export type ReactListSort = { - sortBy: string; - sortOrder: ReactListSortOrder; -}; - -export type ReactListAttribute = { - name: string; - label?: string; -}; - -export type ReactListActions< - TItem = ReactListItem, - TFilters extends ReactListFilters = ReactListFilters, -> = { - setPage: (value: number, addContext?: Record) => void; - setPerPage: (value: number) => void; - setSearch: (value: string) => void; - setSort: (args: { by: string; order: ReactListSortOrder }) => void; - loadMore: () => void; - clearFilters: () => void; - refresh: (addContext?: Record) => void; - setFilters: (filters: TFilters) => void; - updateAttr: (attrName: string, settingKey: string, value: unknown) => void; - updateItemById: (item: Partial, id: ReactListItemId) => void; - setSelection: (selection: ReactListItemId[]) => void; -}; - -export type ReactListListState< - TItem = ReactListItem, - TFilters extends ReactListFilters = ReactListFilters, -> = { - data: TItem[]; - response: ReactListResponse | null; - error: Error | null; - count: number; - selection: ReactListItemId[]; - pagination: ReactListPaginationState; - loader: ReactListLoaderState; - sort: ReactListSort; - hasActiveFilters: boolean; - search: string; - filters: TFilters; - attrs: ReactListAttribute[]; - attrSettings: ReactListAttrSettings; - isEmpty: boolean; - // Actions are appended by the main `ReactList` component. -} & ReactListActions; - -export type ReactListContextValue< - TItem = ReactListItem, - TFilters extends ReactListFilters = ReactListFilters, -> = { - requestHandler: ReactListRequestHandler; - stateManager: ReactListStateManager; - listState: ReactListListState; - setListState: React.Dispatch>>; -}; - diff --git a/packages/react-list/src/types/react-list.ts b/packages/react-list/src/types/react-list.ts deleted file mode 100644 index 4ec6d6c..0000000 --- a/packages/react-list/src/types/react-list.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { ReactNode } from 'react'; - -import type { - ReactListAttribute, - ReactListFilters, - ReactListItem, - ReactListListState, - ReactListResponse, - ReactListSortOrder, -} from './list-provider'; - -export type ReactListPaginationMode = 'pagination' | 'loadMore'; - -export type ReactListProps< - TItem = ReactListItem, - TFilters extends ReactListFilters = ReactListFilters, -> = { - initialItems?: TItem[]; - children?: - | ReactNode - | ((scope: ReactListListState) => ReactNode); - - endpoint: string; - page?: number; - perPage?: number; - sortBy?: string; - sortOrder?: ReactListSortOrder; - count?: number; - search?: string; - filters?: TFilters; - attrs?: Array; - version?: number; - paginationMode?: ReactListPaginationMode; - meta?: Record; - onResponse?: (res: ReactListResponse) => void; - afterPageChange?: (res: ReactListResponse) => void; - afterLoadMore?: (res: ReactListResponse) => void; -}; - diff --git a/packages/react-list/src/utils.ts b/packages/react-list/src/utils.js similarity index 100% rename from packages/react-list/src/utils.ts rename to packages/react-list/src/utils.js diff --git a/packages/react-list/tsconfig.build.json b/packages/react-list/tsconfig.build.json deleted file mode 100644 index b96c8ea..0000000 --- a/packages/react-list/tsconfig.build.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "Bundler", - "jsx": "react-jsx", - "allowJs": true, - "checkJs": false, - "declaration": true, - "emitDeclarationOnly": true, - "declarationMap": true, - "outDir": "dist/types", - "strict": false, - "skipLibCheck": true - }, - "include": ["src/**/*"], - "exclude": ["dist", "node_modules"] -} diff --git a/packages/react-list/tsconfig.json b/packages/react-list/tsconfig.json deleted file mode 100644 index 5c29504..0000000 --- a/packages/react-list/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "./tsconfig.build.json", - "compilerOptions": { - "noEmit": true - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a620d7b..0ee8495 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ importers: devDependencies: vitepress: specifier: ^2.0.0-alpha.15 - version: 2.0.0-alpha.15(axios@1.11.0)(jiti@2.6.1)(lightningcss@1.32.0)(postcss@8.5.8)(typescript@5.9.3) + version: 2.0.0-alpha.15(axios@1.11.0)(postcss@8.5.6) apps/playground: dependencies: @@ -35,9 +35,6 @@ importers: '@eslint/js': specifier: ^9.22.0 version: 9.25.1 - '@tailwindcss/postcss': - specifier: ^4.2.2 - version: 4.2.2 '@types/react': specifier: ^19.0.10 version: 19.1.2 @@ -46,74 +43,22 @@ importers: version: 19.1.2(@types/react@19.1.2) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) - autoprefixer: - specifier: ^10.4.27 - version: 10.4.27(postcss@8.5.8) + version: 4.4.1(vite@6.3.3) eslint: specifier: ^9.22.0 - version: 9.25.1(jiti@2.6.1) + version: 9.25.1 eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.25.1(jiti@2.6.1)) + version: 5.2.0(eslint@9.25.1) eslint-plugin-react-refresh: specifier: ^0.4.19 - version: 0.4.20(eslint@9.25.1(jiti@2.6.1)) + version: 0.4.20(eslint@9.25.1) globals: specifier: ^16.0.0 version: 16.0.0 - postcss: - specifier: ^8.5.8 - version: 8.5.8 - tailwindcss: - specifier: ^4.2.2 - version: 4.2.2 vite: specifier: ^6.3.1 - version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) - - apps/playground-typescript: - dependencies: - '@7span/react-list': - specifier: workspace:* - version: link:../../packages/react-list - '@iconify/react': - specifier: ^5.2.1 - version: 5.2.1(react@19.1.0) - react: - specifier: ^19.0.0 - version: 19.1.0 - react-dom: - specifier: ^19.0.0 - version: 19.1.0(react@19.1.0) - devDependencies: - '@tailwindcss/postcss': - specifier: ^4.2.2 - version: 4.2.2 - '@types/react': - specifier: ^19.0.10 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.0.4 - version: 19.2.3(@types/react@19.2.14) - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) - autoprefixer: - specifier: ^10.4.27 - version: 10.4.27(postcss@8.5.8) - postcss: - specifier: ^8.5.8 - version: 8.5.8 - tailwindcss: - specifier: ^4.2.2 - version: 4.2.2 - typescript: - specifier: ^5.9.3 - version: 5.9.3 - vite: - specifier: ^6.3.1 - version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) + version: 6.3.3 packages/react-list: dependencies: @@ -124,28 +69,15 @@ importers: specifier: ^18.2.0 || ^19.0.0 version: 19.1.0(react@19.1.0) devDependencies: - '@types/react': - specifier: ^19.1.13 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.1.9 - version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) - typescript: - specifier: ^5.9.3 - version: 5.9.3 + version: 4.4.1(vite@6.3.3) vite: specifier: ^6.3.1 - version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) + version: 6.3.3 packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -475,9 +407,6 @@ packages: resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -486,6 +415,9 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -729,94 +661,6 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - '@tailwindcss/node@4.2.2': - resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - - '@tailwindcss/oxide-android-arm64@4.2.2': - resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.2.2': - resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.2.2': - resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.2.2': - resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': - resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': - resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.2.2': - resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} - engines: {node: '>= 20'} - - '@tailwindcss/postcss@4.2.2': - resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} - '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -858,17 +702,9 @@ packages: peerDependencies: '@types/react': ^19.0.0 - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - '@types/react@19.1.2': resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -1007,24 +843,12 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - autoprefixer@10.4.27: - resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - axios@1.11.0: resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.10.9: - resolution: {integrity: sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==} - engines: {node: '>=6.0.0'} - hasBin: true - birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} @@ -1036,11 +860,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1049,8 +868,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001780: - resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} + caniuse-lite@1.0.30001715: + resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1096,9 +915,6 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -1119,10 +935,6 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -1133,13 +945,6 @@ packages: electron-to-chromium@1.5.141: resolution: {integrity: sha512-qS+qH9oqVYc1ooubTiB9l904WVyM6qNYxtOEEGReoZXw3xlqeYdFr5GclNzbkAufWgwWLEPoDi3d9MoRwwIjGw==} - electron-to-chromium@1.5.321: - resolution: {integrity: sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==} - - enhanced-resolve@5.20.1: - resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} - engines: {node: '>=10.13.0'} - entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -1286,9 +1091,6 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} - fraction.js@5.3.4: - resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1329,9 +1131,6 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1390,10 +1189,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1427,76 +1222,6 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1566,9 +1291,6 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - oniguruma-parser@0.12.1: resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} @@ -1613,11 +1335,12 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -1720,13 +1443,6 @@ packages: tabbable@6.3.0: resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} - tailwindcss@4.2.2: - resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -1742,11 +1458,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -1768,12 +1479,6 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1907,8 +1612,6 @@ packages: snapshots: - '@alloc/quick-lru@5.2.0': {} - '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -2118,9 +1821,9 @@ snapshots: '@esbuild/win32-x64@0.25.3': optional: true - '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1)': dependencies: - eslint: 9.25.1(jiti@2.6.1) + eslint: 9.25.1 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -2189,24 +1892,21 @@ snapshots: '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} + '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.5.0 '@rolldown/pluginutils@1.0.0-beta.53': {} @@ -2374,75 +2074,6 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} - '@tailwindcss/node@4.2.2': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.1 - jiti: 2.6.1 - lightningcss: 1.32.0 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.2.2 - - '@tailwindcss/oxide-android-arm64@4.2.2': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.2.2': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.2.2': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - optional: true - - '@tailwindcss/oxide@4.2.2': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-x64': 4.2.2 - '@tailwindcss/oxide-freebsd-x64': 4.2.2 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-x64-musl': 4.2.2 - '@tailwindcss/oxide-wasm32-wasi': 4.2.2 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - - '@tailwindcss/postcss@4.2.2': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.2.2 - '@tailwindcss/oxide': 4.2.2 - postcss: 8.5.8 - tailwindcss: 4.2.2 - '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.0 @@ -2491,40 +2122,32 @@ snapshots: dependencies: '@types/react': 19.1.2 - '@types/react-dom@19.2.3(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - '@types/react@19.1.2': dependencies: csstype: 3.1.3 - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - '@types/unist@3.0.3': {} '@types/web-bluetooth@0.0.21': {} '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0))': + '@vitejs/plugin-react@4.4.1(vite@6.3.3)': dependencies: '@babel/core': 7.26.10 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) + vite: 6.3.3 transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.3(vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0))(vue@3.5.25(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.3(vite@7.2.7)(vue@3.5.25)': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.2.7(jiti@2.6.1)(lightningcss@1.32.0) - vue: 3.5.25(typescript@5.9.3) + vite: 7.2.7 + vue: 3.5.25 '@vue/compiler-core@3.5.25': dependencies: @@ -2548,7 +2171,7 @@ snapshots: '@vue/shared': 3.5.25 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.8 + postcss: 8.5.6 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.25': @@ -2590,35 +2213,35 @@ snapshots: '@vue/shared': 3.5.25 csstype: 3.1.3 - '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': + '@vue/server-renderer@3.5.25(vue@3.5.25)': dependencies: '@vue/compiler-ssr': 3.5.25 '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.25 '@vue/shared@3.5.25': {} - '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': + '@vueuse/core@14.1.0(vue@3.5.25)': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.1.0 - '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) - vue: 3.5.25(typescript@5.9.3) + '@vueuse/shared': 14.1.0(vue@3.5.25) + vue: 3.5.25 - '@vueuse/integrations@14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25(typescript@5.9.3))': + '@vueuse/integrations@14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25)': dependencies: - '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) - '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) - vue: 3.5.25(typescript@5.9.3) + '@vueuse/core': 14.1.0(vue@3.5.25) + '@vueuse/shared': 14.1.0(vue@3.5.25) + vue: 3.5.25 optionalDependencies: axios: 1.11.0 focus-trap: 7.6.6 '@vueuse/metadata@14.1.0': {} - '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': + '@vueuse/shared@14.1.0(vue@3.5.25)': dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.25 acorn-jsx@5.3.2(acorn@8.14.1): dependencies: @@ -2641,15 +2264,6 @@ snapshots: asynckit@0.4.0: {} - autoprefixer@10.4.27(postcss@8.5.8): - dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001780 - fraction.js: 5.3.4 - picocolors: 1.1.1 - postcss: 8.5.8 - postcss-value-parser: 4.2.0 - axios@1.11.0: dependencies: follow-redirects: 1.15.11 @@ -2660,8 +2274,6 @@ snapshots: balanced-match@1.0.2: {} - baseline-browser-mapping@2.10.9: {} - birpc@2.9.0: {} brace-expansion@1.1.11: @@ -2671,19 +2283,11 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001780 + caniuse-lite: 1.0.30001715 electron-to-chromium: 1.5.141 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.9 - caniuse-lite: 1.0.30001780 - electron-to-chromium: 1.5.321 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2691,7 +2295,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001780: {} + caniuse-lite@1.0.30001715: {} ccount@2.0.1: {} @@ -2732,8 +2336,6 @@ snapshots: csstype@3.1.3: {} - csstype@3.2.3: {} - debug@4.4.0: dependencies: ms: 2.1.3 @@ -2744,8 +2346,6 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.1.2: {} - devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -2758,13 +2358,6 @@ snapshots: electron-to-chromium@1.5.141: {} - electron-to-chromium@1.5.321: {} - - enhanced-resolve@5.20.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - entities@4.5.0: {} es-define-property@1.0.1: {} @@ -2814,13 +2407,13 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@5.2.0(eslint@9.25.1(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.25.1): dependencies: - eslint: 9.25.1(jiti@2.6.1) + eslint: 9.25.1 - eslint-plugin-react-refresh@0.4.20(eslint@9.25.1(jiti@2.6.1)): + eslint-plugin-react-refresh@0.4.20(eslint@9.25.1): dependencies: - eslint: 9.25.1(jiti@2.6.1) + eslint: 9.25.1 eslint-scope@8.3.0: dependencies: @@ -2831,9 +2424,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.25.1(jiti@2.6.1): + eslint@9.25.1: dependencies: - '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.1 @@ -2868,8 +2461,6 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -2937,8 +2528,6 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 - fraction.js@5.3.4: {} - fsevents@2.3.3: optional: true @@ -2976,8 +2565,6 @@ snapshots: gopd@1.2.0: {} - graceful-fs@4.2.11: {} - has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -3033,8 +2620,6 @@ snapshots: isexe@2.0.0: {} - jiti@2.6.1: {} - js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -3060,55 +2645,6 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -3178,8 +2714,6 @@ snapshots: node-releases@2.0.19: {} - node-releases@2.0.36: {} - oniguruma-parser@0.12.1: {} oniguruma-to-es@4.3.4: @@ -3221,9 +2755,13 @@ snapshots: picomatch@4.0.3: {} - postcss-value-parser@4.2.0: {} + postcss@8.5.3: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 - postcss@8.5.8: + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -3358,10 +2896,6 @@ snapshots: tabbable@6.3.0: {} - tailwindcss@4.2.2: {} - - tapable@2.3.0: {} - tinyglobby@0.2.13: dependencies: fdir: 6.4.4(picomatch@4.0.2) @@ -3378,8 +2912,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript@5.9.3: {} - unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -3409,12 +2941,6 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -3429,33 +2955,29 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0): + vite@6.3.3: dependencies: esbuild: 0.25.3 fdir: 6.4.4(picomatch@4.0.2) picomatch: 4.0.2 - postcss: 8.5.8 + postcss: 8.5.3 rollup: 4.40.0 tinyglobby: 0.2.13 optionalDependencies: fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.32.0 - vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0): + vite@7.2.7: dependencies: esbuild: 0.25.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.8 + postcss: 8.5.6 rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.32.0 - vitepress@2.0.0-alpha.15(axios@1.11.0)(jiti@2.6.1)(lightningcss@1.32.0)(postcss@8.5.8)(typescript@5.9.3): + vitepress@2.0.0-alpha.15(axios@1.11.0)(postcss@8.5.6): dependencies: '@docsearch/css': 4.3.2 '@docsearch/js': 4.3.2 @@ -3464,19 +2986,19 @@ snapshots: '@shikijs/transformers': 3.20.0 '@shikijs/types': 3.20.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 6.0.3(vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0))(vue@3.5.25(typescript@5.9.3)) + '@vitejs/plugin-vue': 6.0.3(vite@7.2.7)(vue@3.5.25) '@vue/devtools-api': 8.0.5 '@vue/shared': 3.5.25 - '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) - '@vueuse/integrations': 14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25(typescript@5.9.3)) + '@vueuse/core': 14.1.0(vue@3.5.25) + '@vueuse/integrations': 14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25) focus-trap: 7.6.6 mark.js: 8.11.1 minisearch: 7.2.0 shiki: 3.20.0 - vite: 7.2.7(jiti@2.6.1)(lightningcss@1.32.0) - vue: 3.5.25(typescript@5.9.3) + vite: 7.2.7 + vue: 3.5.25 optionalDependencies: - postcss: 8.5.8 + postcss: 8.5.6 transitivePeerDependencies: - '@types/node' - async-validator @@ -3502,15 +3024,13 @@ snapshots: - universal-cookie - yaml - vue@3.5.25(typescript@5.9.3): + vue@3.5.25: dependencies: '@vue/compiler-dom': 3.5.25 '@vue/compiler-sfc': 3.5.25 '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) + '@vue/server-renderer': 3.5.25(vue@3.5.25) '@vue/shared': 3.5.25 - optionalDependencies: - typescript: 5.9.3 which@2.0.2: dependencies: From a19592b5e22e44373e7112099d9f04f0a176ba8f Mon Sep 17 00:00:00 2001 From: darshak-7span Date: Fri, 20 Mar 2026 19:10:01 +0530 Subject: [PATCH 8/9] Reapply "Enhance playground and TypeScript setup: integrate Tailwind CSS, update dependencies, and add new components for improved list functionality." This reverts commit c7842fee441853a5ba079f2d5a72a626cae3a184. --- apps/playground-typescript/index.html | 14 + apps/playground-typescript/package.json | 29 + apps/playground-typescript/postcss.config.mjs | 6 + apps/playground-typescript/src/App.tsx | 6 + .../src/api/request-handler.ts | 87 +++ .../src/components/list-wrapper.tsx | 298 ++++++++ .../src/components/react-list.ts | 75 ++ apps/playground-typescript/src/index.css | 2 + apps/playground-typescript/src/main.tsx | 11 + apps/playground-typescript/tailwind.config.js | 8 + apps/playground-typescript/tsconfig.json | 16 + apps/playground-typescript/vite.config.ts | 7 + apps/playground/package.json | 10 +- apps/playground/postcss.config.js | 6 + .../src/components/list-wrapper.jsx | 654 ++++++++---------- apps/playground/src/index.css | 10 +- apps/playground/tailwind.config.js | 9 + packages/react-list/package.json | 21 +- .../react-list/src/components/attributes.jsx | 53 -- .../react-list/src/components/attributes.tsx | 87 +++ .../src/components/{empty.jsx => empty.tsx} | 6 +- .../src/components/{error.jsx => error.tsx} | 9 +- .../src/components/{go-to.jsx => go-to.tsx} | 20 +- .../src/components/initial-loader.jsx | 25 - .../src/components/initial-loader.tsx | 40 ++ .../src/components/{items.jsx => items.tsx} | 24 +- .../src/components/{list.jsx => list.tsx} | 94 ++- .../{load-more.jsx => load-more.tsx} | 14 +- packages/react-list/src/components/loader.jsx | 29 - packages/react-list/src/components/loader.tsx | 39 ++ .../{pagination.jsx => pagination.tsx} | 46 +- .../components/{per-page.jsx => per-page.tsx} | 48 +- .../components/{refresh.jsx => refresh.tsx} | 18 +- packages/react-list/src/components/search.jsx | 59 -- packages/react-list/src/components/search.tsx | 75 ++ .../components/{summary.jsx => summary.tsx} | 23 +- .../src/components/{utils.js => utils.ts} | 23 +- .../react-list/src/context/list-provider.jsx | 55 -- .../react-list/src/context/list-provider.tsx | 91 +++ .../react-list/src/{index.js => index.ts} | 22 + packages/react-list/src/types/index.ts | 22 + .../react-list/src/types/list-provider.ts | 156 +++++ packages/react-list/src/types/react-list.ts | 39 ++ .../react-list/src/{utils.js => utils.ts} | 0 packages/react-list/tsconfig.build.json | 18 + packages/react-list/tsconfig.json | 6 + pnpm-lock.yaml | 616 +++++++++++++++-- 47 files changed, 2303 insertions(+), 723 deletions(-) create mode 100644 apps/playground-typescript/index.html create mode 100644 apps/playground-typescript/package.json create mode 100644 apps/playground-typescript/postcss.config.mjs create mode 100644 apps/playground-typescript/src/App.tsx create mode 100644 apps/playground-typescript/src/api/request-handler.ts create mode 100644 apps/playground-typescript/src/components/list-wrapper.tsx create mode 100644 apps/playground-typescript/src/components/react-list.ts create mode 100644 apps/playground-typescript/src/index.css create mode 100644 apps/playground-typescript/src/main.tsx create mode 100644 apps/playground-typescript/tailwind.config.js create mode 100644 apps/playground-typescript/tsconfig.json create mode 100644 apps/playground-typescript/vite.config.ts create mode 100644 apps/playground/postcss.config.js create mode 100644 apps/playground/tailwind.config.js delete mode 100644 packages/react-list/src/components/attributes.jsx create mode 100644 packages/react-list/src/components/attributes.tsx rename packages/react-list/src/components/{empty.jsx => empty.tsx} (77%) rename packages/react-list/src/components/{error.jsx => error.tsx} (72%) rename packages/react-list/src/components/{go-to.jsx => go-to.tsx} (73%) delete mode 100644 packages/react-list/src/components/initial-loader.jsx create mode 100644 packages/react-list/src/components/initial-loader.tsx rename packages/react-list/src/components/{items.jsx => items.tsx} (64%) rename packages/react-list/src/components/{list.jsx => list.tsx} (81%) rename packages/react-list/src/components/{load-more.jsx => load-more.tsx} (71%) delete mode 100644 packages/react-list/src/components/loader.jsx create mode 100644 packages/react-list/src/components/loader.tsx rename packages/react-list/src/components/{pagination.jsx => pagination.tsx} (76%) rename packages/react-list/src/components/{per-page.jsx => per-page.tsx} (55%) rename packages/react-list/src/components/{refresh.jsx => refresh.tsx} (63%) delete mode 100644 packages/react-list/src/components/search.jsx create mode 100644 packages/react-list/src/components/search.tsx rename packages/react-list/src/components/{summary.jsx => summary.tsx} (72%) rename packages/react-list/src/components/{utils.js => utils.ts} (51%) delete mode 100644 packages/react-list/src/context/list-provider.jsx create mode 100644 packages/react-list/src/context/list-provider.tsx rename packages/react-list/src/{index.js => index.ts} (64%) create mode 100644 packages/react-list/src/types/index.ts create mode 100644 packages/react-list/src/types/list-provider.ts create mode 100644 packages/react-list/src/types/react-list.ts rename packages/react-list/src/{utils.js => utils.ts} (100%) create mode 100644 packages/react-list/tsconfig.build.json create mode 100644 packages/react-list/tsconfig.json diff --git a/apps/playground-typescript/index.html b/apps/playground-typescript/index.html new file mode 100644 index 0000000..fa41216 --- /dev/null +++ b/apps/playground-typescript/index.html @@ -0,0 +1,14 @@ + + + + + + + Vite + React (TypeScript) + + +
+ + + + diff --git a/apps/playground-typescript/package.json b/apps/playground-typescript/package.json new file mode 100644 index 0000000..3416511 --- /dev/null +++ b/apps/playground-typescript/package.json @@ -0,0 +1,29 @@ +{ + "name": "playground-typescript", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "typecheck": "tsc -p tsconfig.json --noEmit", + "preview": "vite preview" + }, + "dependencies": { + "@7span/react-list": "workspace:*", + "@iconify/react": "^5.2.1", + "react": "^19.0.0", + "react-dom": "^19.0.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.2.2", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.27", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", + "typescript": "^5.9.3", + "vite": "^6.3.1" + } +} diff --git a/apps/playground-typescript/postcss.config.mjs b/apps/playground-typescript/postcss.config.mjs new file mode 100644 index 0000000..51a6e4e --- /dev/null +++ b/apps/playground-typescript/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +}; diff --git a/apps/playground-typescript/src/App.tsx b/apps/playground-typescript/src/App.tsx new file mode 100644 index 0000000..92febc7 --- /dev/null +++ b/apps/playground-typescript/src/App.tsx @@ -0,0 +1,6 @@ +import ListWrapper from './components/list-wrapper'; + +export default function App() { + return ; +} + diff --git a/apps/playground-typescript/src/api/request-handler.ts b/apps/playground-typescript/src/api/request-handler.ts new file mode 100644 index 0000000..e6b611a --- /dev/null +++ b/apps/playground-typescript/src/api/request-handler.ts @@ -0,0 +1,87 @@ +import type { ReactListRequestArgs, ReactListResponse } from '@7span/react-list'; + +export type PlaygroundItem = { + id: number; + name: string; + status?: string; + date_updated?: string; + [key: string]: unknown; +}; + +type Filters = Record; + +const requestHandler = async ( + args: ReactListRequestArgs, +): Promise> => { + const { + endpoint, + page, + perPage, + search, + sortBy, + sortOrder, + filters, + meta, + } = args; + + const params = new URLSearchParams(); + + if (page && perPage) { + params.append('page', String(page)); + params.append('limit', String(perPage)); + } + + if (search) params.append('search', search); + + if (sortBy) { + params.append( + 'sort', + sortOrder === 'desc' ? `-${sortBy}` : sortBy, + ); + } + + if (filters && Object.keys(filters).length > 0) { + // Keep it simple for the playground. + for (const [key, value] of Object.entries(filters)) { + if (value === undefined || value === '') continue; + params.append(`filter[${key}][_eq]`, String(value)); + } + } + + // Example: meta support (not required by ReactList, just forwarded in args) + if (meta && typeof meta === 'object') { + // noop; you can add meta params here. + } + + const queryString = params.toString(); + const url = `https://everest.7span.in/items/${endpoint}${ + queryString ? `?${queryString}` : '' + }`; + + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`API request failed: ${response.status}`); + } + const data: any = await response.json(); + + return { + items: (data.data ?? []) as PlaygroundItem[], + count: + data.meta?.total_count ?? + data.meta?.filter_count ?? + 0, + meta: data.meta ?? {}, + }; + } catch (error) { + return { + items: [], + count: 0, + meta: {}, + error: error instanceof Error ? error : undefined, + } as unknown as ReactListResponse; + } +}; + +export default requestHandler; + diff --git a/apps/playground-typescript/src/components/list-wrapper.tsx b/apps/playground-typescript/src/components/list-wrapper.tsx new file mode 100644 index 0000000..02e2641 --- /dev/null +++ b/apps/playground-typescript/src/components/list-wrapper.tsx @@ -0,0 +1,298 @@ +import { useMemo, useState } from "react"; + +import ReactList, { + ReactListEmpty, + ReactListError, + ReactListGoTo, + ReactListInitialLoader, + ReactListItems, + ReactListLoader, + ReactListPagination, + ReactListPerPage, + ReactListProvider, + ReactListSearch, + ReactListSummary, +} from "@7span/react-list"; + +import { Icon } from "@iconify/react"; + +import reactListOptions from "./react-list"; +import type { PlaygroundItem } from "../api/request-handler"; + +type Filters = Record; + +export default function ListWrapper() { + const [filters, setFilters] = useState({}); + const paginationMode = "pagination" as const; + + // Stable render-prop children for the search component. + const searchChildren = useMemo( + () => + ({ + search, + setSearch, + }: { + search: string; + setSearch: (value: string) => void; + }) => ( +
+ setSearch(e.target.value)} + placeholder="Search skills..." + className="w-full rounded-md border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500" + /> +
+ ), + [], + ); + + return ( +
+
+ + +
+

+ React List TypeScript Playground +

+ +
+ {searchChildren} + + +
+
+ +
+ +
+
+
+ {[0, 1, 2, 3].map((i) => ( +
+ ))} +
+
+ + +
+
+ +
+
+ No data found +
+
+
+ + + {({ error }: { error: Error }) => ( +
+
+ +
+
{error.name}
+
{error.message}
+
+
+
+ )} +
+ + + {({ items }) => ( +
+ {items.map((item, idx) => { + const row = item as PlaygroundItem; + + return ( +
+
+
+ ID {row?.id} +
+ +
+ {row?.name} +
+ +
+ Updated:{" "} + {row?.date_updated + ? new Date( + row.date_updated, + ).toLocaleString() + : "-"} +
+
+ +
+ {row?.status ?? "-"} +
+
+ ); + })} +
+ )} +
+
+ +
+ + {({ isLoading }: { isLoading: boolean }) => + isLoading ? ( +
+ Loading... +
+ ) : null + } +
+
+
+ +
+
+ + {({ visibleCount, count }) => ( +
+ {visibleCount} results + {typeof count === "number" ? ` (total ${count})` : ""} +
+ )} +
+ +
+ + {({ perPage, setPerPage, options }) => ( + + )} + + + + {({ setPage, page, pagesCount }) => ( +
+ setPage(Number(e.target.value))} + className="w-20 rounded-md border border-gray-200 bg-white px-3 py-2 text-sm shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500" + /> + + of {pagesCount} + +
+ )} +
+ + + {({ + page, + pagesToDisplay, + hasPrev, + hasNext, + prev, + next, + first, + last, + setPage, + }) => ( +
+ + + + +
+ {pagesToDisplay.map((p) => ( + + ))} +
+ + + + +
+ )} +
+
+
+
+
+ + +
+
+ ); +} diff --git a/apps/playground-typescript/src/components/react-list.ts b/apps/playground-typescript/src/components/react-list.ts new file mode 100644 index 0000000..ed965c9 --- /dev/null +++ b/apps/playground-typescript/src/components/react-list.ts @@ -0,0 +1,75 @@ +import type { + ReactListProviderConfig, + ReactListRequestArgs, + ReactListResponse, + ReactListStateManager, +} from "@7span/react-list"; + +import requestHandler from "../api/request-handler"; +import type { PlaygroundItem } from "../api/request-handler"; + +type Filters = Record; + +const stateManagerKey = (endpoint: string, version: number) => + `react-list--${endpoint}--${version}`; + +const stateManager: ReactListStateManager = { + init(context: any) { + const { endpoint, version } = context; + const allKeys = `react-list--${endpoint}--`; + const latestKey = stateManagerKey(endpoint, version); + + const staleKeys = Object.keys(localStorage).filter( + (key) => key.startsWith(allKeys) && key !== latestKey, + ); + staleKeys.forEach((key) => localStorage.removeItem(key)); + }, + set(context: any) { + const { + endpoint, + version, + search, + page, + perPage, + sortBy, + sortOrder, + filters, + attrSettings, + } = context; + + const key = stateManagerKey(endpoint, version); + localStorage.setItem( + key, + JSON.stringify({ + search, + page, + perPage, + sortBy, + sortOrder, + filters, + attrSettings, + }), + ); + }, + get(context: any) { + const { endpoint, version } = context; + const key = stateManagerKey(endpoint, version); + + try { + const raw = localStorage.getItem(key); + if (!raw) return null; + return JSON.parse(raw) as any; + } catch { + return null; + } + }, +}; + +const config: ReactListProviderConfig = { + requestHandler: requestHandler as unknown as ( + args: ReactListRequestArgs, + ) => Promise>, + stateManager, +}; + +export default config; diff --git a/apps/playground-typescript/src/index.css b/apps/playground-typescript/src/index.css new file mode 100644 index 0000000..d1d9133 --- /dev/null +++ b/apps/playground-typescript/src/index.css @@ -0,0 +1,2 @@ +@import "tailwindcss"; +@source "../**/*.{js,jsx,ts,tsx}"; \ No newline at end of file diff --git a/apps/playground-typescript/src/main.tsx b/apps/playground-typescript/src/main.tsx new file mode 100644 index 0000000..0c5505f --- /dev/null +++ b/apps/playground-typescript/src/main.tsx @@ -0,0 +1,11 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; + +import App from "./App"; +import "./index.css"; + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/apps/playground-typescript/tailwind.config.js b/apps/playground-typescript/tailwind.config.js new file mode 100644 index 0000000..a117e69 --- /dev/null +++ b/apps/playground-typescript/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./index.html", "./src/**/*.{ts,tsx,jsx,js}"], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/apps/playground-typescript/tsconfig.json b/apps/playground-typescript/tsconfig.json new file mode 100644 index 0000000..e034b35 --- /dev/null +++ b/apps/playground-typescript/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "types": ["vite/client"], + "resolveJsonModule": true + }, + "include": ["src"] +} + diff --git a/apps/playground-typescript/vite.config.ts b/apps/playground-typescript/vite.config.ts new file mode 100644 index 0000000..f0c8be1 --- /dev/null +++ b/apps/playground-typescript/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], +}); + diff --git a/apps/playground/package.json b/apps/playground/package.json index c903db3..90148b5 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -10,21 +10,25 @@ "preview": "vite preview" }, "dependencies": { + "@7span/react-list": "workspace:*", + "@iconify/react": "^5.2.1", "axios": "1.11.0", "react": "^19.0.0", - "react-dom": "^19.0.0", - "@iconify/react": "^5.2.1", - "@7span/react-list": "workspace:*" + "react-dom": "^19.0.0" }, "devDependencies": { "@eslint/js": "^9.22.0", + "@tailwindcss/postcss": "^4.2.2", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.27", "eslint": "^9.22.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", + "postcss": "^8.5.8", + "tailwindcss": "^4.2.2", "vite": "^6.3.1" } } diff --git a/apps/playground/postcss.config.js b/apps/playground/postcss.config.js new file mode 100644 index 0000000..51a6e4e --- /dev/null +++ b/apps/playground/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +}; diff --git a/apps/playground/src/components/list-wrapper.jsx b/apps/playground/src/components/list-wrapper.jsx index a74d603..c8600b0 100644 --- a/apps/playground/src/components/list-wrapper.jsx +++ b/apps/playground/src/components/list-wrapper.jsx @@ -1,3 +1,5 @@ +import { useMemo, useState } from 'react'; + import ReactList, { ReactListEmpty, ReactListError, @@ -10,416 +12,334 @@ import ReactList, { ReactListProvider, ReactListSearch, ReactListSummary, -} from "@7span/react-list"; +} from '@7span/react-list'; + +import { Icon } from '@iconify/react'; -import { Icon } from "@iconify/react"; -import { useState } from "react"; +import reactListOptions from './react-list'; -import reactListOptions from "./react-list"; +const STATUS_OPTIONS = [ + { label: 'All Status', value: '' }, + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + { label: 'Archived', value: 'archived' }, +]; -import "../app.css"; +const COLOR_OPTIONS = [ + { label: 'All Colors', value: '' }, + { label: 'Red', value: '#FF9900' }, + { label: 'Blue', value: '#FFEB0F' }, + { label: 'Green', value: '#F7DF1E' }, + { label: 'Yellow', value: '#5E24FF' }, +]; -const ListWrapper = () => { +export default function ListWrapper() { const [filters, setFilters] = useState({}); + const paginationMode = 'pagination'; + + const searchChildren = useMemo( + () => + ({ search, setSearch }) => ( +
+ setSearch(e.target.value)} + placeholder="Search skills..." + className="w-full rounded-md border border-gray-700 bg-gray-900 px-3 py-2 text-sm text-gray-100 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20" + /> +
+ ), + [], + ); + return ( -
-

React List Playground

- - -
-
- {/* */} - - {({ search, setSearch }) => ( -
- { - setSearch(e.target.value); - }} - placeholder="Search skills..." - className="search-input" - /> -
- )} -
-
-
-
-
- +
+
+
+

+ React List Playground (Tailwind) +

+ +
+ + +
+ {searchChildren} + -
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- {[...Array(5)].map((_, index) => ( -
-
-
-
-
-
+ {COLOR_OPTIONS.map((opt) => ( + ))} -
-
-
-
- -
-
-
-
- -
-
- -

No Data Found

- -

- We couldn't find any matching records. Try adjusting your - search or filters. -

+ - -
-
- - {({ error }) => ( -
-
- -
-

Something went wrong

-

- {error.message || - "An unexpected error occurred while fetching data."} -

-
-

- {error.name}: {error.message} -

-
-
- )} -
- - {({ items, sort, setSort }) => { - return ( -
- -
-
- + +
+
+
+ {[0, 1, 2, 3].map((i) => ( +
+ ))} +
+
+ + +
+ +
+
+ No data found
- - - - - - - - - - - - {items.map((item) => ( - - - - - - - ))} - -
ID - Name{" "} - - Status - Update At{" "} - -
{item.id}{item.name}{item.status} - {new Date(item.date_updated).toLocaleString()} -
-
- ); - }} - - {/* Footer */} -
-
-
- - {({ visibleCount }) => ( - - {visibleCount} Results - - )} - -
+ + {({ items }) => ( +
+ {items.map((item, idx) => { + const row = item ?? {}; + return ( +
+
+
+ ID {row.id} +
-
- Page Size: - - {({ perPage, setPerPage, options }) => ( -
- -
- +
+ {row.name} +
+ +
+ Updated:{' '} + {row.date_updated + ? new Date( + row.date_updated, + ).toLocaleString() + : '-'} +
+
+ +
+ {row.status ?? '-'} +
+
+ ); + })}
-
- )} - -
+ )} + -
- - {({ setPage, page, pagesCount }) => ( -
- Go to: - { - const page = Number(e.target.value); - setPage(page); - }} - className="page-input" - /> - of {pagesCount} -
- )} -
-
-
+ + {({ isLoading }) => + isLoading ? ( +
+ Loading... +
+ ) : null + } +
+
- - {({ - page, - pagesToDisplay, - hasNext, - hasPrev, - prev, - next, - first, - last, - setPage, - }) => ( -
- +
+
+ + {({ visibleCount, count }) => ( +
+ {visibleCount} results + {typeof count === 'number' + ? ` (total ${count})` + : ''} +
+ )} +
- +
+ + {({ perPage, setPerPage, options }) => ( + + )} + -
- {pagesToDisplay.map((item, index) => { - const isActive = item === page; + + {({ setPage, page, pagesCount }) => ( +
+ + setPage(Number(e.target.value)) + } + className="w-20 rounded-md border border-gray-700 bg-gray-900 px-3 py-2 text-sm text-gray-100 shadow-sm outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20" + /> + + of {pagesCount} + +
+ )} +
- return ( - - ); - })} -
+ + {({ + page, + pagesToDisplay, + hasPrev, + hasNext, + first, + prev, + next, + last, + setPage, + }) => ( +
+ + - +
+ {pagesToDisplay.map((p) => ( + + ))} +
- + + +
+ )} +
+
+
- )} - -
+
+ +
- - +
+
); -}; +} -export default ListWrapper; diff --git a/apps/playground/src/index.css b/apps/playground/src/index.css index 08a3ac9..a50c033 100644 --- a/apps/playground/src/index.css +++ b/apps/playground/src/index.css @@ -1,3 +1,6 @@ +@import "tailwindcss"; +@source "../**/*.{js,jsx,ts,tsx}"; + :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -18,6 +21,7 @@ a { color: #646cff; text-decoration: inherit; } + a:hover { color: #535bf2; } @@ -46,9 +50,11 @@ button { cursor: pointer; transition: border-color 0.25s; } + button:hover { border-color: #646cff; } + button:focus, button:focus-visible { outline: 4px auto -webkit-focus-ring-color; @@ -59,10 +65,12 @@ button:focus-visible { color: #213547; background-color: #ffffff; } + a:hover { color: #747bff; } + button { background-color: #f9f9f9; } -} +} \ No newline at end of file diff --git a/apps/playground/tailwind.config.js b/apps/playground/tailwind.config.js new file mode 100644 index 0000000..524f96e --- /dev/null +++ b/apps/playground/tailwind.config.js @@ -0,0 +1,9 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +}; + diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 7423430..6163710 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -5,12 +5,22 @@ "type": "module", "scripts": { "dev": "vite", - "build": "vite build", + "build": "vite build && pnpm run build:types", + "build:types": "tsc -p tsconfig.build.json", "lint": "eslint .", "preview": "vite preview", - "prepublishOnly": "npm run build" + "prepublishOnly": "pnpm run build" + }, + "main": "dist/react-list.cjs", + "module": "dist/react-list.js", + "types": "dist/types/index.d.ts", + "exports": { + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/react-list.js", + "require": "./dist/react-list.cjs" + } }, - "main": "dist/react-list.js", "files": [ "dist" ], @@ -22,7 +32,10 @@ "react-dom": "^18.2.0 || ^19.0.0" }, "devDependencies": { + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^4.3.4", + "typescript": "^5.9.3", "vite": "^6.3.1" } -} +} \ No newline at end of file diff --git a/packages/react-list/src/components/attributes.jsx b/packages/react-list/src/components/attributes.jsx deleted file mode 100644 index b3fc189..0000000 --- a/packages/react-list/src/components/attributes.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import { memo, useCallback, useMemo } from "react"; -import { useListContext } from "../context/list-provider"; - -export const ReactListAttributes = memo(({ children, renderAttribute }) => { - const { listState } = useListContext(); - const { attrs, attrSettings, updateAttr } = listState; - - const handleAttrChange = useCallback( - (attrName) => (e) => { - updateAttr(attrName, "visible", e.target.checked); - }, - [updateAttr] - ); - - const scope = useMemo( - () => ({ - attrs, - attrSettings, - updateAttr, - }), - [attrs, attrSettings, updateAttr] - ); - - if (children) { - return children(scope); - } - - return ( -
- {attrs.map((attr, index) => { - if (renderAttribute) { - return renderAttribute({ - key: `attr-${index}`, - attr, - updateAttr, - attrSettings, - }); - } - - return ( - - ); - })} -
- ); -}); diff --git a/packages/react-list/src/components/attributes.tsx b/packages/react-list/src/components/attributes.tsx new file mode 100644 index 0000000..fa4e2d7 --- /dev/null +++ b/packages/react-list/src/components/attributes.tsx @@ -0,0 +1,87 @@ +import { memo, useCallback, useMemo } from "react"; +import { useListContext } from "../context/list-provider"; +import type { ReactListAttrSettings, ReactListAttribute } from "../types"; +import type { ChangeEvent, ReactNode } from "react"; + +type ReactListAttributesUpdateAttr = ( + attrName: string, + settingKey: string, + value: unknown, +) => void; + +type ReactListAttributesScope = { + attrs: ReactListAttribute[]; + attrSettings: ReactListAttrSettings; + updateAttr: ReactListAttributesUpdateAttr; +}; + +type ReactListAttributesRenderAttributeArgs = { + key: string; + attr: ReactListAttribute; + updateAttr: ReactListAttributesUpdateAttr; + attrSettings: ReactListAttrSettings; +}; + +type ReactListAttributesProps = { + children?: ReactNode | ((scope: ReactListAttributesScope) => ReactNode); + renderAttribute?: (args: ReactListAttributesRenderAttributeArgs) => ReactNode; +}; + +export const ReactListAttributes = memo( + ({ children, renderAttribute }: ReactListAttributesProps) => { + const { listState } = useListContext(); + const { attrs, attrSettings, updateAttr } = listState; + + const handleAttrChange = useCallback( + (attrName: string) => (e: ChangeEvent) => { + updateAttr(attrName, "visible", e.target.checked); + }, + [updateAttr], + ); + + const scope = useMemo( + () => ({ + attrs, + attrSettings, + updateAttr, + }), + [attrs, attrSettings, updateAttr], + ); + + if (typeof children === "function") { + return children(scope); + } + + if (children) return children; + + return ( +
+ {attrs.map((attr, index) => { + if (renderAttribute) { + return ( + + {renderAttribute({ + key: `attr-${index}`, + attr, + updateAttr, + attrSettings, + })} + + ); + } + + return ( + + ); + })} +
+ ); + }, +); diff --git a/packages/react-list/src/components/empty.jsx b/packages/react-list/src/components/empty.tsx similarity index 77% rename from packages/react-list/src/components/empty.jsx rename to packages/react-list/src/components/empty.tsx index 40dbeed..c97be07 100644 --- a/packages/react-list/src/components/empty.jsx +++ b/packages/react-list/src/components/empty.tsx @@ -1,7 +1,11 @@ import { memo } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListEmpty = memo(({ children }) => { +type ReactListEmptyProps = { + children?: React.ReactNode; +}; + +export const ReactListEmpty = memo(({ children }: ReactListEmptyProps) => { const { listState } = useListContext(); const { data: items, loader, error } = listState; const { isLoading, initialLoading } = loader; diff --git a/packages/react-list/src/components/error.jsx b/packages/react-list/src/components/error.tsx similarity index 72% rename from packages/react-list/src/components/error.jsx rename to packages/react-list/src/components/error.tsx index 957ad19..476b5d0 100644 --- a/packages/react-list/src/components/error.jsx +++ b/packages/react-list/src/components/error.tsx @@ -1,7 +1,14 @@ import { memo } from "react"; +import type { ReactNode } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListError = memo(({ children }) => { +type ReactListErrorProps = { + children?: + | ReactNode + | ((scope: { error: Error }) => ReactNode); +}; + +export const ReactListError = memo(({ children }: ReactListErrorProps) => { const { listState } = useListContext(); const { error, loader } = listState; const { isLoading } = loader; diff --git a/packages/react-list/src/components/go-to.jsx b/packages/react-list/src/components/go-to.tsx similarity index 73% rename from packages/react-list/src/components/go-to.jsx rename to packages/react-list/src/components/go-to.tsx index 361162b..a076d86 100644 --- a/packages/react-list/src/components/go-to.jsx +++ b/packages/react-list/src/components/go-to.tsx @@ -1,7 +1,21 @@ import { memo, useCallback, useMemo } from "react"; +import type { ReactNode } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListGoTo = memo(({ children }) => { +type ReactListGoToScope = { + setPage: (page: number, addContext?: Record) => void; + page: number; + pages: number[]; + pagesCount: number; +}; + +type ReactListGoToProps = { + children?: + | ReactNode + | ((scope: ReactListGoToScope) => ReactNode); +}; + +export const ReactListGoTo = memo(({ children }: ReactListGoToProps) => { const { listState } = useListContext(); const { data, count, pagination, setPage, loader, error } = listState; const { page, perPage } = pagination; @@ -42,8 +56,10 @@ export const ReactListGoTo = memo(({ children }) => { return (
- {children ? ( + {typeof children === "function" ? ( children(scope) + ) : children ? ( + children ) : ( handleChange(e.target.value)} - placeholder="Search..." - /> - )} -
- ); -}); diff --git a/packages/react-list/src/components/search.tsx b/packages/react-list/src/components/search.tsx new file mode 100644 index 0000000..0eb7d1c --- /dev/null +++ b/packages/react-list/src/components/search.tsx @@ -0,0 +1,75 @@ +import { memo, useEffect, useRef, useState } from "react"; +import type { ReactNode } from "react"; + +import { useListContext } from "../context/list-provider"; + +type ReactListSearchScope = { + search: string; + setSearch: (value: string) => void; +}; + +type ReactListSearchProps = { + debounceTime?: number; + children?: ReactNode | ((scope: ReactListSearchScope) => ReactNode); +}; + +export const ReactListSearch = memo( + ({ children, debounceTime = 500 }: ReactListSearchProps) => { + const { listState } = useListContext(); + const { search, setSearch } = listState; + + const [localSearch, setLocalSearch] = useState(search ?? ""); + const debounceTimerRef = useRef | null>(null); + + // Sync local state with context when the list search value changes. + useEffect(() => { + if (search !== localSearch) { + setLocalSearch(search ?? ""); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [search]); + + const handleChange = (value: string) => { + setLocalSearch(value); + + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current); + } + + debounceTimerRef.current = setTimeout(() => { + setSearch(value); + }, debounceTime); + }; + + useEffect(() => { + return () => { + if (debounceTimerRef.current) { + clearTimeout(debounceTimerRef.current); + } + }; + }, []); + + const scope: ReactListSearchScope = { + search: localSearch, + setSearch: handleChange, + }; + + return ( +
+ {typeof children === "function" ? ( + children(scope) + ) : children ? ( + children + ) : ( + handleChange(e.target.value)} + placeholder="Search..." + /> + )} +
+ ); + } +); + diff --git a/packages/react-list/src/components/summary.jsx b/packages/react-list/src/components/summary.tsx similarity index 72% rename from packages/react-list/src/components/summary.jsx rename to packages/react-list/src/components/summary.tsx index 284da5c..a360b0a 100644 --- a/packages/react-list/src/components/summary.jsx +++ b/packages/react-list/src/components/summary.tsx @@ -1,7 +1,21 @@ import { memo, useMemo } from "react"; import { useListContext } from "../context/list-provider"; -export const ReactListSummary = memo(({ children }) => { +import type { ReactNode } from "react"; + +type ReactListSummaryScope = { + from: number; + to: number; + visibleCount: number; + count: number; +}; + +type ReactListSummaryProps = { + children?: ReactNode | ((scope: ReactListSummaryScope) => ReactNode); +}; + +export const ReactListSummary = memo( + ({ children }: ReactListSummaryProps) => { const { listState } = useListContext(); const { data, count, pagination, loader, error } = listState; const { page, perPage } = pagination; @@ -35,8 +49,10 @@ export const ReactListSummary = memo(({ children }) => { return (
- {children ? ( + {typeof children === "function" ? ( children(scope) + ) : children ? ( + children ) : ( Showing {summaryData.visibleCount} items ( @@ -48,4 +64,5 @@ export const ReactListSummary = memo(({ children }) => { )}
); -}); + } +); diff --git a/packages/react-list/src/components/utils.js b/packages/react-list/src/components/utils.ts similarity index 51% rename from packages/react-list/src/components/utils.js rename to packages/react-list/src/components/utils.ts index f4a7279..e9f4e33 100644 --- a/packages/react-list/src/components/utils.js +++ b/packages/react-list/src/components/utils.ts @@ -1,10 +1,11 @@ -export const deepEqual = (obj1, obj2) => { +export const deepEqual = (obj1: unknown, obj2: unknown): boolean => { if (obj1 === obj2) return true; if (obj1 == null || obj2 == null) return obj1 === obj2; - if (typeof obj1 !== "object" || typeof obj2 !== "object") + if (typeof obj1 !== "object" || typeof obj2 !== "object") { return obj1 === obj2; + } if (Array.isArray(obj1) && Array.isArray(obj2)) { if (obj1.length !== obj2.length) return false; @@ -16,22 +17,28 @@ export const deepEqual = (obj1, obj2) => { if (Array.isArray(obj1) || Array.isArray(obj2)) return false; - const keys1 = Object.keys(obj1).filter((key) => obj1[key] !== undefined); - const keys2 = Object.keys(obj2).filter((key) => obj2[key] !== undefined); + const record1 = obj1 as Record; + const record2 = obj2 as Record; + + const keys1 = Object.keys(record1).filter((key) => record1[key] !== undefined); + const keys2 = Object.keys(record2).filter((key) => record2[key] !== undefined); if (keys1.length !== keys2.length) return false; - for (let key of keys1) { + for (const key of keys1) { if (!keys2.includes(key)) return false; - if (!deepEqual(obj1[key], obj2[key])) return false; + if (!deepEqual(record1[key], record2[key])) return false; } return true; }; -export const hasActiveFilters = (currentFilters, initialFilters) => { +export const hasActiveFilters = ( + currentFilters: Record | null | undefined, + initialFilters: Record | null | undefined +): boolean => { if (!initialFilters || Object.keys(initialFilters).length === 0) { - return currentFilters && Object.keys(currentFilters).length > 0; + return !!currentFilters && Object.keys(currentFilters).length > 0; } if (!currentFilters || Object.keys(currentFilters).length === 0) { diff --git a/packages/react-list/src/context/list-provider.jsx b/packages/react-list/src/context/list-provider.jsx deleted file mode 100644 index bd4e21a..0000000 --- a/packages/react-list/src/context/list-provider.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import { createContext, useContext, useMemo, useState } from "react"; - -const ListContext = createContext(null); - -export const ReactListProvider = ({ children, config }) => { - const { requestHandler, stateManager = {} } = config; - const [listState, setListState] = useState({ - data: [], - response: null, - error: null, - count: 0, - selection: [], - pagination: { - page: 1, - perPage: 25, - }, - loader: { - isLoading: false, - initialLoading: true, - }, - sort: { - sortBy: null, - sortOrder: "desc", - }, - search: "", - filters: {}, - attrs: [], - isEmpty: true, - isInitializing: true, - }); - - if (!requestHandler) { - throw new Error("ListProvider: requestHandler is required."); - } - - const value = useMemo( - () => ({ - requestHandler, - stateManager, - listState, - setListState, - }), - [requestHandler, stateManager, listState] - ); - - return {children}; -}; - -export const useListContext = () => { - const context = useContext(ListContext); - if (!context) { - throw new Error("useListContext must be used within a ListProvider"); - } - return context; -}; diff --git a/packages/react-list/src/context/list-provider.tsx b/packages/react-list/src/context/list-provider.tsx new file mode 100644 index 0000000..0182397 --- /dev/null +++ b/packages/react-list/src/context/list-provider.tsx @@ -0,0 +1,91 @@ +import { createContext, useContext, useMemo, useState } from "react"; +import type { ReactNode } from "react"; + +import type { + ReactListContextValue, + ReactListFilters, + ReactListItem, + ReactListItemId, + ReactListListState, + ReactListProviderConfig, + ReactListResponse, + ReactListRequestHandler, + ReactListStateManager, +} from "../types"; + +const ListContext = createContext(null); + +type ReactListProviderProps = { + children: ReactNode; + config: ReactListProviderConfig; +}; + +const noop = () => {}; + +export const ReactListProvider = ({ children, config }: ReactListProviderProps) => { + const { requestHandler, stateManager = {} } = config; + + if (!requestHandler) { + throw new Error("ListProvider: requestHandler is required."); + } + + const [listState, setListState] = useState>({ + data: [], + response: null as ReactListResponse | null, + error: null, + count: 0, + selection: [] as ReactListItemId[], + pagination: { + page: 1, + perPage: 25, + hasMore: false, + }, + loader: { + isLoading: false, + initialLoading: true, + }, + sort: { + sortBy: "", + sortOrder: "desc", + }, + hasActiveFilters: false, + search: "", + filters: {}, + attrs: [], + attrSettings: {}, + isEmpty: true, + + // These actions are replaced by `ReactList` once it mounts. + setPage: noop, + setPerPage: noop, + setSearch: noop, + setSort: noop, + loadMore: noop, + clearFilters: noop, + refresh: noop, + setFilters: noop, + updateAttr: noop, + updateItemById: noop, + setSelection: noop, + }); + + const value: ReactListContextValue = useMemo( + () => ({ + requestHandler: requestHandler as ReactListRequestHandler, + stateManager: stateManager as ReactListStateManager, + listState, + setListState, + }), + [requestHandler, stateManager, listState] + ); + + return {children}; +}; + +export const useListContext = (): ReactListContextValue => { + const context = useContext(ListContext); + if (!context) { + throw new Error("useListContext must be used within a ListProvider"); + } + return context; +}; diff --git a/packages/react-list/src/index.js b/packages/react-list/src/index.ts similarity index 64% rename from packages/react-list/src/index.js rename to packages/react-list/src/index.ts index d132e3f..65eca60 100644 --- a/packages/react-list/src/index.js +++ b/packages/react-list/src/index.ts @@ -13,3 +13,25 @@ export { ReactListRefresh } from "./components/refresh"; export { ReactListSearch } from "./components/search"; export { ReactListSummary } from "./components/summary"; export { ReactListProvider } from "./context/list-provider"; + +export type { + ReactListAttrSettings, + ReactListContext, + ReactListContextValue, + ReactListFilters, + ReactListAttribute, + ReactListProps, + ReactListPaginationMode, + ReactListItem, + ReactListItemId, + ReactListListState, + ReactListLoaderState, + ReactListPaginationState, + ReactListProviderConfig, + ReactListRequestArgs, + ReactListRequestHandler, + ReactListResponse, + ReactListSort, + ReactListSortOrder, + ReactListStateManager, +} from "./types"; diff --git a/packages/react-list/src/types/index.ts b/packages/react-list/src/types/index.ts new file mode 100644 index 0000000..d27aaf5 --- /dev/null +++ b/packages/react-list/src/types/index.ts @@ -0,0 +1,22 @@ +export type { + ReactListAttrSettings, + ReactListContext, + ReactListContextValue, + ReactListItem, + ReactListItemId, + ReactListListState, + ReactListLoaderState, + ReactListPaginationState, + ReactListProviderConfig, + ReactListRequestArgs, + ReactListRequestHandler, + ReactListResponse, + ReactListSort, + ReactListSortOrder, + ReactListStateManager, + ReactListFilters, + ReactListAttribute, +} from './list-provider.ts'; + +export type { ReactListProps, ReactListPaginationMode } from './react-list'; + diff --git a/packages/react-list/src/types/list-provider.ts b/packages/react-list/src/types/list-provider.ts new file mode 100644 index 0000000..795ddbd --- /dev/null +++ b/packages/react-list/src/types/list-provider.ts @@ -0,0 +1,156 @@ +import type * as React from 'react'; + +export type ReactListItemId = string | number; + +export type ReactListItem = Record & { + id?: ReactListItemId; +}; + +export type ReactListFilters = Record; + +export type ReactListSortOrder = '' | 'asc' | 'desc' | (string & {}); + +export type ReactListAttrSettings = Record< + string, + { + visible: boolean; + } +>; + +export type ReactListRequestArgs< + TFilters extends ReactListFilters = ReactListFilters, +> = { + endpoint: string; + version: number; + meta: Record; + page: number; + perPage: number; + search: string; + sortBy: string; + sortOrder: ReactListSortOrder; + filters: TFilters; +} & Record; + +export type ReactListResponse = { + items: TItem[]; + count: number; + meta?: unknown; + [key: string]: unknown; +}; + +export type ReactListRequestHandler< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = (args: ReactListRequestArgs) => Promise>; + +export type ReactListPersistedState< + TFilters extends ReactListFilters = ReactListFilters, +> = { + page?: number; + perPage?: number; + sortBy?: string; + sortOrder?: ReactListSortOrder; + search?: string; + attrSettings?: ReactListAttrSettings; + filters?: TFilters; +}; + +export type ReactListContext = { + endpoint: string; + version: number; + meta: Record; + search: string; + page: number; + perPage: number; + sortBy: string; + sortOrder: ReactListSortOrder; + filters: TFilters; + attrSettings: ReactListAttrSettings; + isRefresh: boolean; +}; + +export type ReactListStateManager< + TFilters extends ReactListFilters = ReactListFilters, +> = { + init?: (context: ReactListContext) => void; + get?: (context: ReactListContext) => ReactListPersistedState | null; + set?: (context: ReactListContext) => void; +}; + +export type ReactListProviderConfig< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + requestHandler: ReactListRequestHandler; + stateManager?: ReactListStateManager; +}; + +export type ReactListPaginationState = { + page: number; + perPage: number; + hasMore: boolean; +}; + +export type ReactListLoaderState = { + isLoading: boolean; + initialLoading: boolean; +}; + +export type ReactListSort = { + sortBy: string; + sortOrder: ReactListSortOrder; +}; + +export type ReactListAttribute = { + name: string; + label?: string; +}; + +export type ReactListActions< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + setPage: (value: number, addContext?: Record) => void; + setPerPage: (value: number) => void; + setSearch: (value: string) => void; + setSort: (args: { by: string; order: ReactListSortOrder }) => void; + loadMore: () => void; + clearFilters: () => void; + refresh: (addContext?: Record) => void; + setFilters: (filters: TFilters) => void; + updateAttr: (attrName: string, settingKey: string, value: unknown) => void; + updateItemById: (item: Partial, id: ReactListItemId) => void; + setSelection: (selection: ReactListItemId[]) => void; +}; + +export type ReactListListState< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + data: TItem[]; + response: ReactListResponse | null; + error: Error | null; + count: number; + selection: ReactListItemId[]; + pagination: ReactListPaginationState; + loader: ReactListLoaderState; + sort: ReactListSort; + hasActiveFilters: boolean; + search: string; + filters: TFilters; + attrs: ReactListAttribute[]; + attrSettings: ReactListAttrSettings; + isEmpty: boolean; + // Actions are appended by the main `ReactList` component. +} & ReactListActions; + +export type ReactListContextValue< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + requestHandler: ReactListRequestHandler; + stateManager: ReactListStateManager; + listState: ReactListListState; + setListState: React.Dispatch>>; +}; + diff --git a/packages/react-list/src/types/react-list.ts b/packages/react-list/src/types/react-list.ts new file mode 100644 index 0000000..4ec6d6c --- /dev/null +++ b/packages/react-list/src/types/react-list.ts @@ -0,0 +1,39 @@ +import type { ReactNode } from 'react'; + +import type { + ReactListAttribute, + ReactListFilters, + ReactListItem, + ReactListListState, + ReactListResponse, + ReactListSortOrder, +} from './list-provider'; + +export type ReactListPaginationMode = 'pagination' | 'loadMore'; + +export type ReactListProps< + TItem = ReactListItem, + TFilters extends ReactListFilters = ReactListFilters, +> = { + initialItems?: TItem[]; + children?: + | ReactNode + | ((scope: ReactListListState) => ReactNode); + + endpoint: string; + page?: number; + perPage?: number; + sortBy?: string; + sortOrder?: ReactListSortOrder; + count?: number; + search?: string; + filters?: TFilters; + attrs?: Array; + version?: number; + paginationMode?: ReactListPaginationMode; + meta?: Record; + onResponse?: (res: ReactListResponse) => void; + afterPageChange?: (res: ReactListResponse) => void; + afterLoadMore?: (res: ReactListResponse) => void; +}; + diff --git a/packages/react-list/src/utils.js b/packages/react-list/src/utils.ts similarity index 100% rename from packages/react-list/src/utils.js rename to packages/react-list/src/utils.ts diff --git a/packages/react-list/tsconfig.build.json b/packages/react-list/tsconfig.build.json new file mode 100644 index 0000000..b96c8ea --- /dev/null +++ b/packages/react-list/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "allowJs": true, + "checkJs": false, + "declaration": true, + "emitDeclarationOnly": true, + "declarationMap": true, + "outDir": "dist/types", + "strict": false, + "skipLibCheck": true + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/react-list/tsconfig.json b/packages/react-list/tsconfig.json new file mode 100644 index 0000000..5c29504 --- /dev/null +++ b/packages/react-list/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "noEmit": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ee8495..a620d7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,7 +12,7 @@ importers: devDependencies: vitepress: specifier: ^2.0.0-alpha.15 - version: 2.0.0-alpha.15(axios@1.11.0)(postcss@8.5.6) + version: 2.0.0-alpha.15(axios@1.11.0)(jiti@2.6.1)(lightningcss@1.32.0)(postcss@8.5.8)(typescript@5.9.3) apps/playground: dependencies: @@ -35,6 +35,9 @@ importers: '@eslint/js': specifier: ^9.22.0 version: 9.25.1 + '@tailwindcss/postcss': + specifier: ^4.2.2 + version: 4.2.2 '@types/react': specifier: ^19.0.10 version: 19.1.2 @@ -43,22 +46,74 @@ importers: version: 19.1.2(@types/react@19.1.2) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3) + version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) + autoprefixer: + specifier: ^10.4.27 + version: 10.4.27(postcss@8.5.8) eslint: specifier: ^9.22.0 - version: 9.25.1 + version: 9.25.1(jiti@2.6.1) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.25.1) + version: 5.2.0(eslint@9.25.1(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: ^0.4.19 - version: 0.4.20(eslint@9.25.1) + version: 0.4.20(eslint@9.25.1(jiti@2.6.1)) globals: specifier: ^16.0.0 version: 16.0.0 + postcss: + specifier: ^8.5.8 + version: 8.5.8 + tailwindcss: + specifier: ^4.2.2 + version: 4.2.2 vite: specifier: ^6.3.1 - version: 6.3.3 + version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) + + apps/playground-typescript: + dependencies: + '@7span/react-list': + specifier: workspace:* + version: link:../../packages/react-list + '@iconify/react': + specifier: ^5.2.1 + version: 5.2.1(react@19.1.0) + react: + specifier: ^19.0.0 + version: 19.1.0 + react-dom: + specifier: ^19.0.0 + version: 19.1.0(react@19.1.0) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.2.2 + version: 4.2.2 + '@types/react': + specifier: ^19.0.10 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.0.4 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) + autoprefixer: + specifier: ^10.4.27 + version: 10.4.27(postcss@8.5.8) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + tailwindcss: + specifier: ^4.2.2 + version: 4.2.2 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^6.3.1 + version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) packages/react-list: dependencies: @@ -69,15 +124,28 @@ importers: specifier: ^18.2.0 || ^19.0.0 version: 19.1.0(react@19.1.0) devDependencies: + '@types/react': + specifier: ^19.1.13 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.1.9 + version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.4.1(vite@6.3.3) + version: 4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0)) + typescript: + specifier: ^5.9.3 + version: 5.9.3 vite: specifier: ^6.3.1 - version: 6.3.3 + version: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) packages: + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -407,6 +475,9 @@ packages: resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -415,9 +486,6 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -661,6 +729,94 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@tailwindcss/node@4.2.2': + resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} + + '@tailwindcss/oxide-android-arm64@4.2.2': + resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.2.2': + resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.2.2': + resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.2.2': + resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -702,9 +858,17 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react@19.1.2': resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -843,12 +1007,24 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + axios@1.11.0: resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + baseline-browser-mapping@2.10.9: + resolution: {integrity: sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==} + engines: {node: '>=6.0.0'} + hasBin: true + birpc@2.9.0: resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} @@ -860,6 +1036,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -868,8 +1049,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001715: - resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} + caniuse-lite@1.0.30001780: + resolution: {integrity: sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -915,6 +1096,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -935,6 +1119,10 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -945,6 +1133,13 @@ packages: electron-to-chromium@1.5.141: resolution: {integrity: sha512-qS+qH9oqVYc1ooubTiB9l904WVyM6qNYxtOEEGReoZXw3xlqeYdFr5GclNzbkAufWgwWLEPoDi3d9MoRwwIjGw==} + electron-to-chromium@1.5.321: + resolution: {integrity: sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==} + + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -1091,6 +1286,9 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1131,6 +1329,9 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1189,6 +1390,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1222,6 +1427,76 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1291,6 +1566,9 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + oniguruma-parser@0.12.1: resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} @@ -1335,12 +1613,11 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} - engines: {node: ^10 || ^12 || >=14} + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -1443,6 +1720,13 @@ packages: tabbable@6.3.0: resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} @@ -1458,6 +1742,11 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -1479,6 +1768,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -1612,6 +1907,8 @@ packages: snapshots: + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 @@ -1821,9 +2118,9 @@ snapshots: '@esbuild/win32-x64@0.25.3': optional: true - '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1)': + '@eslint-community/eslint-utils@4.6.1(eslint@9.25.1(jiti@2.6.1))': dependencies: - eslint: 9.25.1 + eslint: 9.25.1(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -1892,21 +2189,24 @@ snapshots: '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} - '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@rolldown/pluginutils@1.0.0-beta.53': {} @@ -2074,6 +2374,75 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} + '@tailwindcss/node@4.2.2': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.20.1 + jiti: 2.6.1 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.2.2 + + '@tailwindcss/oxide-android-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.2.2': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.2.2': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.2.2': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.2.2': + optional: true + + '@tailwindcss/oxide@4.2.2': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-arm64': 4.2.2 + '@tailwindcss/oxide-darwin-x64': 4.2.2 + '@tailwindcss/oxide-freebsd-x64': 4.2.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 + '@tailwindcss/oxide-linux-x64-musl': 4.2.2 + '@tailwindcss/oxide-wasm32-wasi': 4.2.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 + + '@tailwindcss/postcss@4.2.2': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.2.2 + '@tailwindcss/oxide': 4.2.2 + postcss: 8.5.8 + tailwindcss: 4.2.2 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.0 @@ -2122,32 +2491,40 @@ snapshots: dependencies: '@types/react': 19.1.2 + '@types/react-dom@19.2.3(@types/react@19.2.14)': + dependencies: + '@types/react': 19.2.14 + '@types/react@19.1.2': dependencies: csstype: 3.1.3 + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + '@types/unist@3.0.3': {} '@types/web-bluetooth@0.0.21': {} '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-react@4.4.1(vite@6.3.3)': + '@vitejs/plugin-react@4.4.1(vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: '@babel/core': 7.26.10 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.3.3 + vite: 6.3.3(jiti@2.6.1)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.3(vite@7.2.7)(vue@3.5.25)': + '@vitejs/plugin-vue@6.0.3(vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0))(vue@3.5.25(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.2.7 - vue: 3.5.25 + vite: 7.2.7(jiti@2.6.1)(lightningcss@1.32.0) + vue: 3.5.25(typescript@5.9.3) '@vue/compiler-core@3.5.25': dependencies: @@ -2171,7 +2548,7 @@ snapshots: '@vue/shared': 3.5.25 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.6 + postcss: 8.5.8 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.25': @@ -2213,35 +2590,35 @@ snapshots: '@vue/shared': 3.5.25 csstype: 3.1.3 - '@vue/server-renderer@3.5.25(vue@3.5.25)': + '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': dependencies: '@vue/compiler-ssr': 3.5.25 '@vue/shared': 3.5.25 - vue: 3.5.25 + vue: 3.5.25(typescript@5.9.3) '@vue/shared@3.5.25': {} - '@vueuse/core@14.1.0(vue@3.5.25)': + '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.1.0 - '@vueuse/shared': 14.1.0(vue@3.5.25) - vue: 3.5.25 + '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) - '@vueuse/integrations@14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25)': + '@vueuse/integrations@14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25(typescript@5.9.3))': dependencies: - '@vueuse/core': 14.1.0(vue@3.5.25) - '@vueuse/shared': 14.1.0(vue@3.5.25) - vue: 3.5.25 + '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) + '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: axios: 1.11.0 focus-trap: 7.6.6 '@vueuse/metadata@14.1.0': {} - '@vueuse/shared@14.1.0(vue@3.5.25)': + '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': dependencies: - vue: 3.5.25 + vue: 3.5.25(typescript@5.9.3) acorn-jsx@5.3.2(acorn@8.14.1): dependencies: @@ -2264,6 +2641,15 @@ snapshots: asynckit@0.4.0: {} + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001780 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + axios@1.11.0: dependencies: follow-redirects: 1.15.11 @@ -2274,6 +2660,8 @@ snapshots: balanced-match@1.0.2: {} + baseline-browser-mapping@2.10.9: {} + birpc@2.9.0: {} brace-expansion@1.1.11: @@ -2283,11 +2671,19 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001715 + caniuse-lite: 1.0.30001780 electron-to-chromium: 1.5.141 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.9 + caniuse-lite: 1.0.30001780 + electron-to-chromium: 1.5.321 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -2295,7 +2691,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001715: {} + caniuse-lite@1.0.30001780: {} ccount@2.0.1: {} @@ -2336,6 +2732,8 @@ snapshots: csstype@3.1.3: {} + csstype@3.2.3: {} + debug@4.4.0: dependencies: ms: 2.1.3 @@ -2346,6 +2744,8 @@ snapshots: dequal@2.0.3: {} + detect-libc@2.1.2: {} + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -2358,6 +2758,13 @@ snapshots: electron-to-chromium@1.5.141: {} + electron-to-chromium@1.5.321: {} + + enhanced-resolve@5.20.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + entities@4.5.0: {} es-define-property@1.0.1: {} @@ -2407,13 +2814,13 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@5.2.0(eslint@9.25.1): + eslint-plugin-react-hooks@5.2.0(eslint@9.25.1(jiti@2.6.1)): dependencies: - eslint: 9.25.1 + eslint: 9.25.1(jiti@2.6.1) - eslint-plugin-react-refresh@0.4.20(eslint@9.25.1): + eslint-plugin-react-refresh@0.4.20(eslint@9.25.1(jiti@2.6.1)): dependencies: - eslint: 9.25.1 + eslint: 9.25.1(jiti@2.6.1) eslint-scope@8.3.0: dependencies: @@ -2424,9 +2831,9 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.25.1: + eslint@9.25.1(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1) + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.1(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.1 @@ -2461,6 +2868,8 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -2528,6 +2937,8 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + fraction.js@5.3.4: {} + fsevents@2.3.3: optional: true @@ -2565,6 +2976,8 @@ snapshots: gopd@1.2.0: {} + graceful-fs@4.2.11: {} + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -2620,6 +3033,8 @@ snapshots: isexe@2.0.0: {} + jiti@2.6.1: {} + js-tokens@4.0.0: {} js-yaml@4.1.0: @@ -2645,6 +3060,55 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -2714,6 +3178,8 @@ snapshots: node-releases@2.0.19: {} + node-releases@2.0.36: {} + oniguruma-parser@0.12.1: {} oniguruma-to-es@4.3.4: @@ -2755,13 +3221,9 @@ snapshots: picomatch@4.0.3: {} - postcss@8.5.3: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 + postcss-value-parser@4.2.0: {} - postcss@8.5.6: + postcss@8.5.8: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 @@ -2896,6 +3358,10 @@ snapshots: tabbable@6.3.0: {} + tailwindcss@4.2.2: {} + + tapable@2.3.0: {} + tinyglobby@0.2.13: dependencies: fdir: 6.4.4(picomatch@4.0.2) @@ -2912,6 +3378,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + typescript@5.9.3: {} + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -2941,6 +3409,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -2955,29 +3429,33 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@6.3.3: + vite@6.3.3(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.25.3 fdir: 6.4.4(picomatch@4.0.2) picomatch: 4.0.2 - postcss: 8.5.3 + postcss: 8.5.8 rollup: 4.40.0 tinyglobby: 0.2.13 optionalDependencies: fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 - vite@7.2.7: + vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.25.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.32.0 - vitepress@2.0.0-alpha.15(axios@1.11.0)(postcss@8.5.6): + vitepress@2.0.0-alpha.15(axios@1.11.0)(jiti@2.6.1)(lightningcss@1.32.0)(postcss@8.5.8)(typescript@5.9.3): dependencies: '@docsearch/css': 4.3.2 '@docsearch/js': 4.3.2 @@ -2986,19 +3464,19 @@ snapshots: '@shikijs/transformers': 3.20.0 '@shikijs/types': 3.20.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 6.0.3(vite@7.2.7)(vue@3.5.25) + '@vitejs/plugin-vue': 6.0.3(vite@7.2.7(jiti@2.6.1)(lightningcss@1.32.0))(vue@3.5.25(typescript@5.9.3)) '@vue/devtools-api': 8.0.5 '@vue/shared': 3.5.25 - '@vueuse/core': 14.1.0(vue@3.5.25) - '@vueuse/integrations': 14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25) + '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) + '@vueuse/integrations': 14.1.0(axios@1.11.0)(focus-trap@7.6.6)(vue@3.5.25(typescript@5.9.3)) focus-trap: 7.6.6 mark.js: 8.11.1 minisearch: 7.2.0 shiki: 3.20.0 - vite: 7.2.7 - vue: 3.5.25 + vite: 7.2.7(jiti@2.6.1)(lightningcss@1.32.0) + vue: 3.5.25(typescript@5.9.3) optionalDependencies: - postcss: 8.5.6 + postcss: 8.5.8 transitivePeerDependencies: - '@types/node' - async-validator @@ -3024,13 +3502,15 @@ snapshots: - universal-cookie - yaml - vue@3.5.25: + vue@3.5.25(typescript@5.9.3): dependencies: '@vue/compiler-dom': 3.5.25 '@vue/compiler-sfc': 3.5.25 '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25) + '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) '@vue/shared': 3.5.25 + optionalDependencies: + typescript: 5.9.3 which@2.0.2: dependencies: From eade9e4abf59f2a652f000bd008159ffcb48bf53 Mon Sep 17 00:00:00 2001 From: darshak-7span Date: Fri, 20 Mar 2026 19:11:55 +0530 Subject: [PATCH 9/9] Update package version to 1.1.0 for @7span/react-list --- packages/react-list/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-list/package.json b/packages/react-list/package.json index 6163710..9ed6aa8 100644 --- a/packages/react-list/package.json +++ b/packages/react-list/package.json @@ -1,6 +1,6 @@ { "name": "@7span/react-list", - "version": "1.0.2", + "version": "1.1.0", "description": "A simple and reusable list component for React", "type": "module", "scripts": {