@jcoder-stack/registry 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jcoder-stack/registry",
3
3
  "description": "Copy-in sources for the auth shell and shadcn blocks: login/callback/logout handlers, the callAbp proxy, route guards, and TanStack wiring",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "auth",
@@ -14,7 +14,7 @@
14
14
  "postpack": "node ../scripts/restore-publish-config.mjs"
15
15
  },
16
16
  "dependencies": {
17
- "@jcoder-stack/abp-react": "^0.4.0",
17
+ "@jcoder-stack/abp-react": "^0.4.1",
18
18
  "@tanstack/react-router": "^1.0.0",
19
19
  "@tanstack/react-start": "^1.0.0",
20
20
  "zod": "^4.0.0"
@@ -54,7 +54,7 @@
54
54
  },
55
55
  {
56
56
  "path": "ui/blocks/data-table/data-table-footer.tsx",
57
- "content": "import { useLocalization } from \"@jcoder-stack/abp-react/react\";\nimport type { PaginationState, RowData } from \"@tanstack/react-table\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { type ReactNode, useMemo } from \"react\";\nimport type { TableInstance } from \"@/components/data-table/table-core\";\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n} from \"@/components/ui/pagination\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\n\nconst DEFAULT_PAGE_SIZES = [10, 20, 50];\nconst PAGE_WINDOW_THRESHOLD = 7;\n\n/** 0-based 页码窗口:总页 ≤7 全显;否则首页/末页恒在,加当前页及左右各一页,其余折叠为省略号。 */\nexport function getPageItems(pageIndex: number, pageCount: number): (number | \"ellipsis\")[] {\n const totalPages = Math.max(pageCount, 1);\n if (totalPages <= PAGE_WINDOW_THRESHOLD) {\n return Array.from({ length: totalPages }, (_, i) => i);\n }\n\n const current = Math.min(Math.max(pageIndex, 0), totalPages - 1);\n const keep = new Set<number>([0, totalPages - 1, current]);\n if (current - 1 >= 0) keep.add(current - 1);\n if (current + 1 <= totalPages - 1) keep.add(current + 1);\n const sorted = [...keep].sort((a, b) => a - b);\n\n const items: (number | \"ellipsis\")[] = [];\n let previous: number | undefined;\n for (const page of sorted) {\n if (previous !== undefined && page - previous > 1) items.push(\"ellipsis\");\n items.push(page);\n previous = page;\n }\n return items;\n}\n\n/** 内建页脚:总条数 + 每页行数下拉 + 分页器。与表体正交,单独成文件降低 fork 进入成本。 */\nexport function DataTableFooter<TData extends RowData>(props: {\n table: TableInstance<TData>;\n pagination: PaginationState;\n pageCount: number;\n rowCount?: number;\n pageSizes?: number[];\n}): ReactNode {\n const L = useLocalization();\n const { table } = props;\n const canPrev = table.getCanPreviousPage();\n const canNext = table.getCanNextPage();\n const pageItems = getPageItems(props.pagination.pageIndex, props.pageCount);\n\n const sizeOptions = useMemo(() => {\n const merged = new Set([...(props.pageSizes ?? DEFAULT_PAGE_SIZES), props.pagination.pageSize]);\n return [...merged].sort((a, b) => a - b);\n }, [props.pageSizes, props.pagination.pageSize]);\n\n const prevItem = (\n <PaginationItem>\n <PaginationLink\n size=\"icon\"\n className={cn(\"size-8\", !canPrev && \"pointer-events-none opacity-50\")}\n aria-label={L(\"Table:Previous\")}\n aria-disabled={!canPrev}\n href={canPrev ? \"#\" : undefined}\n onClick={(e) => {\n e.preventDefault();\n if (canPrev) table.previousPage();\n }}\n >\n <ChevronLeft />\n </PaginationLink>\n </PaginationItem>\n );\n\n const nextItem = (\n <PaginationItem>\n <PaginationLink\n size=\"icon\"\n className={cn(\"size-8\", !canNext && \"pointer-events-none opacity-50\")}\n aria-label={L(\"Table:Next\")}\n aria-disabled={!canNext}\n href={canNext ? \"#\" : undefined}\n onClick={(e) => {\n e.preventDefault();\n if (canNext) table.nextPage();\n }}\n >\n <ChevronRight />\n </PaginationLink>\n </PaginationItem>\n );\n\n return (\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2 text-sm tabular-nums text-muted-foreground\">\n {props.rowCount !== undefined && props.rowCount > 0 && (\n <span>{L(\"Table:Total\", props.rowCount)}</span>\n )}\n <span>{L(\"Table:RowsPerPage\")}</span>\n <Select\n value={String(props.pagination.pageSize)}\n onValueChange={(v: string) => table.setPagination({ pageIndex: 0, pageSize: Number(v) })}\n >\n <SelectTrigger size=\"sm\" className=\"tabular-nums\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent className=\"tabular-nums\">\n {sizeOptions.map((size) => (\n <SelectItem key={size} value={String(size)}>\n {size}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm tabular-nums text-muted-foreground md:hidden\">\n {L(\"Table:PageOf\", props.pagination.pageIndex + 1, Math.max(props.pageCount, 1))}\n </span>\n <Pagination className=\"mx-0 w-auto md:hidden\">\n <PaginationContent>\n {prevItem}\n {nextItem}\n </PaginationContent>\n </Pagination>\n <Pagination className=\"mx-0 hidden w-auto md:flex\">\n <PaginationContent>\n {prevItem}\n {pageItems.map((item, i) =>\n item === \"ellipsis\" ? (\n // biome-ignore lint/suspicious/noArrayIndexKey: 省略号在窗口内位置固定,不参与重排\n <PaginationItem key={`ellipsis-${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={item}>\n <PaginationLink\n size=\"icon\"\n className={cn(\n \"size-8 tabular-nums\",\n item === props.pagination.pageIndex &&\n \"border-primary bg-primary text-primary-foreground hover:bg-primary-hover hover:text-primary-foreground dark:border-primary dark:bg-primary dark:hover:bg-primary-hover\",\n )}\n isActive={item === props.pagination.pageIndex}\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n table.setPageIndex(item);\n }}\n >\n {item + 1}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n {nextItem}\n </PaginationContent>\n </Pagination>\n </div>\n </div>\n );\n}\n",
57
+ "content": "import { useLocalization } from \"@jcoder-stack/abp-react/react\";\nimport type { PaginationState, RowData } from \"@tanstack/react-table\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { type ReactNode, useMemo } from \"react\";\nimport type { TableInstance } from \"@/components/data-table/table-core\";\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n} from \"@/components/ui/pagination\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport { cn } from \"@/lib/utils\";\n\nconst DEFAULT_PAGE_SIZES = [10, 20, 50];\nconst PAGE_WINDOW_THRESHOLD = 7;\n\n/**\n * 0-based 页码窗口:总页 ≤7 全显;否则**恒定 7 个槽位**,首页与末页占两端,中间五槽随当前页滑动。\n *\n * 槽位数必须恒定:数量随当前页变化时,翻一页整排页码就会左右平移,按钮跑到光标底下换了张脸,\n * 连点下一页看起来像在闪烁。宁可多显示一个省略号,也不让已经画出来的页码挪位置。\n */\nexport function getPageItems(pageIndex: number, pageCount: number): (number | \"ellipsis\")[] {\n const totalPages = Math.max(pageCount, 1);\n if (totalPages <= PAGE_WINDOW_THRESHOLD) {\n return Array.from({ length: totalPages }, (_, i) => i);\n }\n\n const last = totalPages - 1;\n const current = Math.min(Math.max(pageIndex, 0), last);\n\n if (current <= 3) return [0, 1, 2, 3, 4, \"ellipsis\", last];\n if (current >= last - 3) return [0, \"ellipsis\", last - 4, last - 3, last - 2, last - 1, last];\n return [0, \"ellipsis\", current - 1, current, current + 1, \"ellipsis\", last];\n}\n\n/** 内建页脚:总条数 + 每页行数下拉 + 分页器。与表体正交,单独成文件降低 fork 进入成本。 */\nexport function DataTableFooter<TData extends RowData>(props: {\n table: TableInstance<TData>;\n pagination: PaginationState;\n pageCount: number;\n rowCount?: number;\n pageSizes?: number[];\n}): ReactNode {\n const L = useLocalization();\n const { table } = props;\n const canPrev = table.getCanPreviousPage();\n const canNext = table.getCanNextPage();\n const pageItems = getPageItems(props.pagination.pageIndex, props.pageCount);\n\n const sizeOptions = useMemo(() => {\n const merged = new Set([...(props.pageSizes ?? DEFAULT_PAGE_SIZES), props.pagination.pageSize]);\n return [...merged].sort((a, b) => a - b);\n }, [props.pageSizes, props.pagination.pageSize]);\n\n const prevItem = (\n <PaginationItem>\n <PaginationLink\n size=\"icon\"\n className={cn(\"size-8\", !canPrev && \"pointer-events-none opacity-50\")}\n aria-label={L(\"Table:Previous\")}\n aria-disabled={!canPrev}\n href={canPrev ? \"#\" : undefined}\n onClick={(e) => {\n e.preventDefault();\n if (canPrev) table.previousPage();\n }}\n >\n <ChevronLeft />\n </PaginationLink>\n </PaginationItem>\n );\n\n const nextItem = (\n <PaginationItem>\n <PaginationLink\n size=\"icon\"\n className={cn(\"size-8\", !canNext && \"pointer-events-none opacity-50\")}\n aria-label={L(\"Table:Next\")}\n aria-disabled={!canNext}\n href={canNext ? \"#\" : undefined}\n onClick={(e) => {\n e.preventDefault();\n if (canNext) table.nextPage();\n }}\n >\n <ChevronRight />\n </PaginationLink>\n </PaginationItem>\n );\n\n return (\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-2 text-sm tabular-nums text-muted-foreground\">\n {props.rowCount !== undefined && props.rowCount > 0 && (\n <span>{L(\"Table:Total\", props.rowCount)}</span>\n )}\n <span>{L(\"Table:RowsPerPage\")}</span>\n <Select\n value={String(props.pagination.pageSize)}\n onValueChange={(v: string) => table.setPagination({ pageIndex: 0, pageSize: Number(v) })}\n >\n <SelectTrigger size=\"sm\" className=\"tabular-nums\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent className=\"tabular-nums\">\n {sizeOptions.map((size) => (\n <SelectItem key={size} value={String(size)}>\n {size}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm tabular-nums text-muted-foreground md:hidden\">\n {L(\"Table:PageOf\", props.pagination.pageIndex + 1, Math.max(props.pageCount, 1))}\n </span>\n <Pagination className=\"mx-0 w-auto md:hidden\">\n <PaginationContent>\n {prevItem}\n {nextItem}\n </PaginationContent>\n </Pagination>\n <Pagination className=\"mx-0 hidden w-auto md:flex\">\n <PaginationContent>\n {prevItem}\n {pageItems.map((item, i) =>\n item === \"ellipsis\" ? (\n // biome-ignore lint/suspicious/noArrayIndexKey: 省略号在窗口内位置固定,不参与重排\n <PaginationItem key={`ellipsis-${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={item}>\n <PaginationLink\n size=\"icon\"\n className={cn(\n \"size-8 tabular-nums\",\n item === props.pagination.pageIndex &&\n \"border-primary bg-primary text-primary-foreground hover:bg-primary-hover hover:text-primary-foreground dark:border-primary dark:bg-primary dark:hover:bg-primary-hover\",\n )}\n isActive={item === props.pagination.pageIndex}\n href=\"#\"\n onClick={(e) => {\n e.preventDefault();\n table.setPageIndex(item);\n }}\n >\n {item + 1}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n {nextItem}\n </PaginationContent>\n </Pagination>\n </div>\n </div>\n );\n}\n",
58
58
  "type": "registry:component",
59
59
  "target": "components/data-table/data-table-footer.tsx"
60
60
  },