@moontra/moonui 6.3.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/index.global.js +29 -0
- package/dist/hooks/index.global.js.map +1 -1
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.global.js +345 -10
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +344 -288
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +299 -253
- package/dist/index.mjs.map +1 -1
- package/dist/lib/theme.global.js +37 -0
- package/dist/lib/theme.global.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ui/__tests__/table-sortable.test.tsx +159 -0
- package/src/components/ui/index.ts +15 -0
- package/src/components/ui/table.tsx +125 -23
|
@@ -7,6 +7,32 @@ import { cn } from "../../lib/utils";
|
|
|
7
7
|
|
|
8
8
|
export type SortDirection = "asc" | "desc" | null;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Tablo düzeyi kontrollü sıralama bağlamı (#321).
|
|
12
|
+
*
|
|
13
|
+
* `Table`'daki `sortColumn`/`sortDirection`/`onSortChange` deklare edilmişti ama
|
|
14
|
+
* destructure'da yoruma alındığı için `...props` içinde kalıp native <table>'a
|
|
15
|
+
* sızıyordu (ölçüldü: `sortcolumn`/`sortdirection` geçersiz DOM attribute +
|
|
16
|
+
* 4 React uyarısı). Artık gerçekten bağlılar.
|
|
17
|
+
*
|
|
18
|
+
* `TableHead`'in mevcut `sorted`/`onSort` prop'ları KORUNUR ve önceliklidir —
|
|
19
|
+
* elle bağlayan tüketici kırılmaz. `columnId` verildiğinde bağlam devreye girer.
|
|
20
|
+
*/
|
|
21
|
+
interface TableSortContextValue {
|
|
22
|
+
sortColumn?: string;
|
|
23
|
+
sortDirection?: SortDirection;
|
|
24
|
+
onSortChange?: (column: string, direction: SortDirection) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const TableSortContext = React.createContext<TableSortContextValue | null>(null);
|
|
28
|
+
|
|
29
|
+
/** asc → desc → null → asc döngüsü */
|
|
30
|
+
function nextSortDirection(current: SortDirection): SortDirection {
|
|
31
|
+
if (current === "asc") return "desc";
|
|
32
|
+
if (current === "desc") return null;
|
|
33
|
+
return "asc";
|
|
34
|
+
}
|
|
35
|
+
|
|
10
36
|
const tableVariants = cva(
|
|
11
37
|
"w-full caption-bottom text-sm",
|
|
12
38
|
{
|
|
@@ -72,18 +98,30 @@ const Table = React.forwardRef<
|
|
|
72
98
|
size,
|
|
73
99
|
loading,
|
|
74
100
|
emptyContent,
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
101
|
+
// #321: Bunlar eskiden yoruma alınmıştı ve `...props` içinde kalıp native
|
|
102
|
+
// <table>'a sızıyordu (ölçüldü: `sortcolumn`/`sortdirection` geçersiz DOM
|
|
103
|
+
// attribute olarak basılıyor + 4 React uyarısı). Artık destructure ediliyorlar:
|
|
104
|
+
// • sıralama üçlüsü GERÇEKTEN bağlandı (aşağıdaki TableSortContext)
|
|
105
|
+
// • seçim dörtlüsü yalnız DOM'dan ÇIKARILIYOR — bağlanamazlar, çünkü `Table`
|
|
106
|
+
// veri almıyor (tamamen kompozisyonel) ve `getRowId(row)` bir veri satırı
|
|
107
|
+
// ister. Satır seçimi için veri-güdümlü `DataTable` kullanılmalı.
|
|
108
|
+
sortColumn,
|
|
109
|
+
sortDirection,
|
|
110
|
+
onSortChange,
|
|
111
|
+
selectedRowIds: _selectedRowIds,
|
|
112
|
+
onRowSelectionChange: _onRowSelectionChange,
|
|
113
|
+
disableRowSelection: _disableRowSelection,
|
|
114
|
+
getRowId: _getRowId,
|
|
83
115
|
...props
|
|
84
116
|
}, ref) => {
|
|
85
117
|
// Apply striped styles to the tbody via a class name
|
|
86
118
|
const striped = variant === "striped";
|
|
119
|
+
|
|
120
|
+
// #321: sıralama prop'ları alt başlıklara bağlam üzerinden ulaşır
|
|
121
|
+
const sortContextValue = React.useMemo<TableSortContextValue>(
|
|
122
|
+
() => ({ sortColumn, sortDirection, onSortChange }),
|
|
123
|
+
[sortColumn, sortDirection, onSortChange]
|
|
124
|
+
);
|
|
87
125
|
|
|
88
126
|
// Çocukları güvenli bir şekilde işle ve tip kontrollerini doğru yap
|
|
89
127
|
const childrenWithProps = React.Children.map(props.children, (child) => {
|
|
@@ -108,17 +146,19 @@ const Table = React.forwardRef<
|
|
|
108
146
|
</div>
|
|
109
147
|
)}
|
|
110
148
|
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
149
|
+
<TableSortContext.Provider value={sortContextValue}>
|
|
150
|
+
<table
|
|
151
|
+
ref={ref}
|
|
152
|
+
className={cn(
|
|
153
|
+
tableVariants({ variant, size }),
|
|
154
|
+
loading && "opacity-70",
|
|
155
|
+
className
|
|
156
|
+
)}
|
|
157
|
+
{...props}
|
|
158
|
+
>
|
|
159
|
+
{childrenWithProps}
|
|
160
|
+
</table>
|
|
161
|
+
</TableSortContext.Provider>
|
|
122
162
|
|
|
123
163
|
</div>
|
|
124
164
|
);
|
|
@@ -207,12 +247,43 @@ interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
|
|
|
207
247
|
sorted?: SortDirection;
|
|
208
248
|
/** Sıralama değiştiğinde çağrılacak fonksiyon */
|
|
209
249
|
onSort?: () => void;
|
|
250
|
+
/**
|
|
251
|
+
* Tablo düzeyi kontrollü sıralamada bu sütunun kimliği (#321).
|
|
252
|
+
*
|
|
253
|
+
* Verildiğinde `Table`'ın `sortColumn`/`sortDirection`/`onSortChange`
|
|
254
|
+
* prop'larıyla otomatik bağlanır: yön bağlamdan okunur, tıklama/klavye
|
|
255
|
+
* `onSortChange(columnId, sonrakiYön)` çağırır.
|
|
256
|
+
*
|
|
257
|
+
* Elle bağlayan mevcut kullanım (`sorted` + `onSort`) ÖNCELİKLİDİR ve
|
|
258
|
+
* çalışmaya devam eder — bu prop eklemeli, kırıcı değil.
|
|
259
|
+
*/
|
|
260
|
+
columnId?: string;
|
|
210
261
|
/** Text alignment */
|
|
211
262
|
align?: 'left' | 'center' | 'right';
|
|
212
263
|
}
|
|
213
264
|
|
|
214
265
|
const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
|
|
215
|
-
({ className, sortable, sorted, onSort, align = 'left', children, ...props }, ref) => {
|
|
266
|
+
({ className, sortable, sorted, onSort, columnId, align = 'left', children, ...props }, ref) => {
|
|
267
|
+
const sortCtx = React.useContext(TableSortContext);
|
|
268
|
+
|
|
269
|
+
// Elle verilen `sorted`/`onSort` önceliklidir; yoksa bağlamdan türetilir.
|
|
270
|
+
const ctxSorted: SortDirection =
|
|
271
|
+
columnId && sortCtx && sortCtx.sortColumn === columnId
|
|
272
|
+
? sortCtx.sortDirection ?? null
|
|
273
|
+
: null;
|
|
274
|
+
const effectiveSorted: SortDirection = sorted !== undefined ? sorted : ctxSorted;
|
|
275
|
+
|
|
276
|
+
const handleSort = React.useCallback(() => {
|
|
277
|
+
if (onSort) {
|
|
278
|
+
onSort();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (columnId && sortCtx?.onSortChange) {
|
|
282
|
+
sortCtx.onSortChange(columnId, nextSortDirection(ctxSorted));
|
|
283
|
+
}
|
|
284
|
+
}, [onSort, columnId, sortCtx, ctxSorted]);
|
|
285
|
+
|
|
286
|
+
const isInteractive = Boolean(sortable && (onSort || (columnId && sortCtx?.onSortChange)));
|
|
216
287
|
// Sıralama için simgeler
|
|
217
288
|
const renderSortIcon = () => {
|
|
218
289
|
if (!sortable) return null;
|
|
@@ -282,11 +353,41 @@ const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
|
|
|
282
353
|
sortable && "cursor-pointer hover:text-foreground select-none",
|
|
283
354
|
className
|
|
284
355
|
)}
|
|
285
|
-
|
|
356
|
+
/* #321: sıralama durumu ekran okuyucuya YANSIMIYORDU (`aria-sort`
|
|
357
|
+
grep'i 0 idi) — yalnız görsel ok ikonu değişiyordu. Sıralanamayan
|
|
358
|
+
sütunda öznitelik hiç basılmaz. */
|
|
359
|
+
aria-sort={
|
|
360
|
+
sortable
|
|
361
|
+
? effectiveSorted === "asc"
|
|
362
|
+
? "ascending"
|
|
363
|
+
: effectiveSorted === "desc"
|
|
364
|
+
? "descending"
|
|
365
|
+
: "none"
|
|
366
|
+
: undefined
|
|
367
|
+
}
|
|
368
|
+
onClick={isInteractive ? handleSort : undefined}
|
|
286
369
|
{...props}
|
|
287
370
|
>
|
|
288
371
|
{sortable || align !== 'left' ? (
|
|
289
|
-
<div
|
|
372
|
+
<div
|
|
373
|
+
className={cn("flex items-center", alignmentClasses[align].split(' ')[1])}
|
|
374
|
+
/* #321: sıralama kontrolü yalnız fareyle çalışıyordu (dosyada
|
|
375
|
+
`tabIndex` grep'i 0, `onKeyDown` yok). Görsel olarak div kalır ama
|
|
376
|
+
role/tabIndex/onKeyDown ile gerçek düğme gibi davranır; erişilebilir
|
|
377
|
+
adı sütun başlığıdır. Pro DataTable'da aynı düzeltme #291'de yapıldı. */
|
|
378
|
+
role={isInteractive ? "button" : undefined}
|
|
379
|
+
tabIndex={isInteractive ? 0 : undefined}
|
|
380
|
+
onKeyDown={
|
|
381
|
+
isInteractive
|
|
382
|
+
? (e) => {
|
|
383
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
384
|
+
e.preventDefault();
|
|
385
|
+
handleSort();
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
: undefined
|
|
389
|
+
}
|
|
390
|
+
>
|
|
290
391
|
{children}
|
|
291
392
|
{sortable && renderSortIcon()}
|
|
292
393
|
</div>
|
|
@@ -347,4 +448,5 @@ export {
|
|
|
347
448
|
TableCaption,
|
|
348
449
|
};
|
|
349
450
|
|
|
350
|
-
|
|
451
|
+
// #321: TableProps/TableHeadProps/TableCellProps export edilmiyordu
|
|
452
|
+
export type { TableProps, TableBodyProps, TableHeadProps, TableCellProps };
|