minka-ds 0.1.0 → 0.1.2

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,6 +1,6 @@
1
1
  {
2
2
  "name": "minka-ds",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Minka product design system — tokenized component library",
5
5
  "license": "MIT",
6
6
  "files": ["src", "tokens"],
@@ -25,8 +25,6 @@ const badgeVariants = cva(
25
25
  "bg-[var(--color-bg-error)] text-[var(--color-feedback-error)] border-transparent",
26
26
  info:
27
27
  "bg-[var(--color-bg-info)] text-[var(--color-feedback-info)] border-transparent",
28
- pending:
29
- "bg-[var(--color-bg-warning)] text-[var(--color-text-default)] border-transparent",
30
28
  outline:
31
29
  "border-[var(--color-border-default)] text-[var(--color-text-default)] [a&]:hover:bg-[var(--color-action-ghost-hover)]",
32
30
  ghost:
@@ -24,15 +24,15 @@ function TextStack({ primary, secondary, className }: TextStackProps) {
24
24
  )
25
25
  }
26
26
 
27
- // ── MonoCell ──────────────────────────────────────────────────────────────────
28
- // Single-line monospace text. Use for IDs, codes, hashes.
27
+ // ── DataCell ──────────────────────────────────────────────────────────────────
28
+ // Single-line plain data value. Use for IDs, timestamps, codes.
29
29
 
30
- interface MonoCellProps {
30
+ interface DataCellProps {
31
31
  children: React.ReactNode
32
32
  className?: string
33
33
  }
34
34
 
35
- function MonoCell({ children, className }: MonoCellProps) {
35
+ function DataCell({ children, className }: DataCellProps) {
36
36
  return (
37
37
  <span
38
38
  className={cn(
@@ -94,10 +94,10 @@ function ActionCell({ children, className }: ActionCellProps) {
94
94
  )
95
95
  }
96
96
 
97
- export { TextStack, MonoCell, AmountCell, BadgeCell, ActionCell }
97
+ export { TextStack, DataCell, AmountCell, BadgeCell, ActionCell }
98
98
  export type {
99
99
  TextStackProps,
100
- MonoCellProps,
100
+ DataCellProps,
101
101
  AmountCellProps,
102
102
  BadgeCellProps,
103
103
  ActionCellProps,
@@ -7,7 +7,6 @@ import {
7
7
  VisibilityState,
8
8
  flexRender,
9
9
  getCoreRowModel,
10
- getPaginationRowModel,
11
10
  getSortedRowModel,
12
11
  useReactTable,
13
12
  type Table as TanstackTable,
@@ -16,15 +15,6 @@ import { ChevronsUpDown, ChevronUp, ChevronDown, Columns3Cog } from "lucide-reac
16
15
 
17
16
  import { cn } from "../../lib/utils"
18
17
  import { Button } from "./button"
19
- import {
20
- Pagination,
21
- PaginationContent,
22
- PaginationEllipsis,
23
- PaginationItem,
24
- PaginationLink,
25
- PaginationNext,
26
- PaginationPrevious,
27
- } from "./pagination"
28
18
  import {
29
19
  DropdownMenu,
30
20
  DropdownMenuCheckboxItem,
@@ -44,12 +34,6 @@ import {
44
34
 
45
35
  // ── Column header with sort control ──────────────────────────────────────────
46
36
 
47
- interface DataTableColumnHeaderProps<TData, TValue>
48
- extends React.HTMLAttributes<HTMLDivElement> {
49
- column: TanstackTable<TData>["getColumn"] extends (id: string) => infer C ? NonNullable<C> : never
50
- title: string
51
- }
52
-
53
37
  function DataTableColumnHeader<TData, TValue>({
54
38
  column,
55
39
  title,
@@ -117,106 +101,61 @@ function DataTableColumnToggle<TData>({
117
101
  )
118
102
  }
119
103
 
120
- // ── Pagination ────────────────────────────────────────────────────────────────
121
-
122
- function getPageNumbers(currentPage: number, totalPages: number): (number | "ellipsis")[] {
123
- if (totalPages <= 7) return Array.from({ length: totalPages }, (_, i) => i + 1)
124
- const pages: (number | "ellipsis")[] = [1]
125
- if (currentPage > 3) pages.push("ellipsis")
126
- const start = Math.max(2, currentPage - 1)
127
- const end = Math.min(totalPages - 1, currentPage + 1)
128
- for (let i = start; i <= end; i++) pages.push(i)
129
- if (currentPage < totalPages - 2) pages.push("ellipsis")
130
- pages.push(totalPages)
131
- return pages
132
- }
133
-
134
- function DataTablePagination<TData>({
135
- table,
136
- }: {
137
- table: TanstackTable<TData>
138
- }) {
139
- const currentPage = table.getState().pagination.pageIndex + 1
140
- const totalPages = table.getPageCount()
141
- const pages = getPageNumbers(currentPage, totalPages)
142
-
143
- return (
144
- <div className="flex items-center justify-between">
145
- <p className="text-body-sm text-[var(--color-text-muted)]">
146
- Page {currentPage} of {totalPages}
147
- </p>
148
- <Pagination className="mx-0 w-auto justify-end">
149
- <PaginationContent>
150
- <PaginationItem>
151
- <PaginationPrevious
152
- onClick={() => table.previousPage()}
153
- aria-disabled={!table.getCanPreviousPage()}
154
- className={cn(!table.getCanPreviousPage() && "pointer-events-none opacity-50")}
155
- />
156
- </PaginationItem>
157
- {pages.map((page, i) =>
158
- page === "ellipsis" ? (
159
- <PaginationItem key={`ellipsis-${i}`}>
160
- <PaginationEllipsis />
161
- </PaginationItem>
162
- ) : (
163
- <PaginationItem key={page}>
164
- <PaginationLink
165
- isActive={page === currentPage}
166
- onClick={() => table.setPageIndex(page - 1)}
167
- className="cursor-pointer"
168
- >
169
- {page}
170
- </PaginationLink>
171
- </PaginationItem>
172
- )
173
- )}
174
- <PaginationItem>
175
- <PaginationNext
176
- onClick={() => table.nextPage()}
177
- aria-disabled={!table.getCanNextPage()}
178
- className={cn(!table.getCanNextPage() && "pointer-events-none opacity-50")}
179
- />
180
- </PaginationItem>
181
- </PaginationContent>
182
- </Pagination>
183
- </div>
184
- )
185
- }
186
-
187
104
  // ── DataTable ─────────────────────────────────────────────────────────────────
188
105
 
189
106
  interface DataTableProps<TData, TValue> {
190
107
  columns: ColumnDef<TData, TValue>[]
191
108
  data: TData[]
192
- pageSize?: number
109
+ batchSize?: number
110
+ onRowClick?: (row: TData) => void
111
+ className?: string
193
112
  }
194
113
 
195
114
  function DataTable<TData, TValue>({
196
115
  columns,
197
116
  data,
198
- pageSize = 10,
117
+ batchSize = 20,
118
+ onRowClick,
119
+ className,
199
120
  }: DataTableProps<TData, TValue>) {
200
121
  const [sorting, setSorting] = React.useState<SortingState>([])
201
122
  const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})
123
+ const [displayCount, setDisplayCount] = React.useState(batchSize)
124
+ const [hasMore, setHasMore] = React.useState(data.length > batchSize)
125
+
126
+ const displayedData = React.useMemo(
127
+ () => data.slice(0, displayCount),
128
+ [data, displayCount]
129
+ )
202
130
 
203
131
  const table = useReactTable({
204
- data,
132
+ data: displayedData,
205
133
  columns,
206
134
  getCoreRowModel: getCoreRowModel(),
207
- getPaginationRowModel: getPaginationRowModel(),
208
135
  getSortedRowModel: getSortedRowModel(),
209
136
  onSortingChange: setSorting,
210
137
  onColumnVisibilityChange: setColumnVisibility,
211
- initialState: { pagination: { pageSize } },
212
138
  state: { sorting, columnVisibility },
213
139
  })
214
140
 
141
+ function handleScroll(e: React.UIEvent<HTMLDivElement>) {
142
+ const { scrollTop, scrollHeight, clientHeight } = e.currentTarget
143
+ const remaining = scrollHeight - scrollTop - clientHeight
144
+ setHasMore(remaining > 2 || displayCount < data.length)
145
+ if (remaining < 120) {
146
+ setDisplayCount((c) => Math.min(c + batchSize, data.length))
147
+ }
148
+ }
149
+
215
150
  return (
216
- <div className="space-y-4">
217
- <div className="rounded-[var(--radius-card)] border border-[var(--color-border-default)] bg-[var(--color-bg-raised)] overflow-hidden">
151
+ <div className={cn("relative flex flex-col min-h-0", className)}>
152
+ <div
153
+ onScroll={handleScroll}
154
+ className="flex-1 min-h-0 overflow-auto rounded-[var(--radius-card)] border border-[var(--color-border-default)] bg-[var(--color-bg-raised)] [&_[data-slot=table-container]]:overflow-visible"
155
+ >
156
+
218
157
  <Table className="[&_th:first-child]:pl-4 [&_td:first-child]:pl-4">
219
- <TableHeader className="bg-[var(--color-bg-base)]">
158
+ <TableHeader className="sticky top-0 z-10 bg-[var(--color-bg-base)]">
220
159
  {table.getHeaderGroups().map((headerGroup) => (
221
160
  <TableRow key={headerGroup.id}>
222
161
  {headerGroup.headers.map((header, index) => (
@@ -240,6 +179,8 @@ function DataTable<TData, TValue>({
240
179
  <TableRow
241
180
  key={row.id}
242
181
  data-state={row.getIsSelected() ? "selected" : undefined}
182
+ onClick={onRowClick ? () => onRowClick(row.original) : undefined}
183
+ className={onRowClick ? "cursor-pointer" : undefined}
243
184
  >
244
185
  {row.getVisibleCells().map((cell) => (
245
186
  <TableCell key={cell.id}>
@@ -261,15 +202,15 @@ function DataTable<TData, TValue>({
261
202
  </TableBody>
262
203
  </Table>
263
204
  </div>
264
- <DataTablePagination table={table} />
205
+ {hasMore && (
206
+ <div className="pointer-events-none absolute bottom-0 left-0 right-0 h-16 rounded-b-[var(--radius-card)] bg-gradient-to-t from-[var(--color-bg-raised)] to-transparent" />
207
+ )}
265
208
  </div>
266
209
  )
267
-
268
210
  }
269
211
 
270
212
  export {
271
213
  DataTable,
272
214
  DataTableColumnHeader,
273
215
  DataTableColumnToggle,
274
- DataTablePagination,
275
216
  }
@@ -0,0 +1,15 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ export function Kbd({ children, className }: { children: React.ReactNode; className?: string }) {
5
+ return (
6
+ <kbd
7
+ className={cn(
8
+ "inline-flex items-center gap-1 h-5 font-sans [border-radius:var(--radius-tooltip)] border border-[var(--color-border-default)] bg-[var(--color-bg-canvas)] px-1.5 text-caption text-[var(--color-text-muted)]",
9
+ className
10
+ )}
11
+ >
12
+ {children}
13
+ </kbd>
14
+ )
15
+ }
@@ -0,0 +1,11 @@
1
+ import * as React from "react"
2
+
3
+ export function usePlatform() {
4
+ const [isMac, setIsMac] = React.useState(true)
5
+
6
+ React.useEffect(() => {
7
+ setIsMac(navigator.userAgent.includes("Mac"))
8
+ }, [])
9
+
10
+ return { isMac }
11
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  // Utilities
2
2
  export { cn } from "./lib/utils"
3
3
 
4
+ // Hooks
5
+ export { usePlatform } from "./hooks/use-platform"
6
+
4
7
  // Components
5
8
  export * from "./components/ui/badge"
6
9
  export * from "./components/ui/cell"
@@ -15,6 +18,7 @@ export * from "./components/ui/dialog"
15
18
  export * from "./components/ui/dropdown-menu"
16
19
  export * from "./components/ui/input"
17
20
  export * from "./components/ui/input-group"
21
+ export * from "./components/ui/kbd"
18
22
  export * from "./components/ui/label"
19
23
  export * from "./components/ui/pagination"
20
24
  export * from "./components/ui/select"