@jinaan/uikit 0.1.21 → 0.1.24
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/data-table.d.ts.map +1 -1
- package/dist/dropdown-menu.d.ts.map +1 -1
- package/dist/index.js +941 -900
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/data-table.tsx +80 -18
- package/src/dropdown-menu.tsx +4 -1
- package/src/select.tsx +1 -1
- package/src/utils.ts +11 -0
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ClassValue } from "clsx";
|
|
2
2
|
/** Merge conditional class names with Tailwind conflict resolution. */
|
|
3
3
|
export declare function cn(...inputs: ClassValue[]): string;
|
|
4
|
+
/** Move the id at `from` so it sits at `to`; no-op when indexes match. */
|
|
5
|
+
export declare function reorderIds(ids: string[], from: number, to: number): string[];
|
|
4
6
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C,uEAAuE;AACvE,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAElD"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C,uEAAuE;AACvE,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAElD;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ5E"}
|
package/package.json
CHANGED
package/src/data-table.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
CaretUp,
|
|
4
4
|
CaretUpDown,
|
|
5
5
|
Columns as ColumnsIcon,
|
|
6
|
+
DotsSixVertical,
|
|
6
7
|
FunnelSimple,
|
|
7
8
|
Lock,
|
|
8
9
|
MagnifyingGlass,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
DropdownMenu,
|
|
20
21
|
DropdownMenuCheckboxItem,
|
|
21
22
|
DropdownMenuContent,
|
|
23
|
+
DropdownMenuChevron,
|
|
22
24
|
DropdownMenuItem,
|
|
23
25
|
DropdownMenuLabel,
|
|
24
26
|
DropdownMenuSeparator,
|
|
@@ -38,7 +40,7 @@ import {
|
|
|
38
40
|
type TableSurfaceAction,
|
|
39
41
|
type TableSurfaceTone,
|
|
40
42
|
} from "./table-surface";
|
|
41
|
-
import { cn } from "./utils";
|
|
43
|
+
import { cn, reorderIds } from "./utils";
|
|
42
44
|
|
|
43
45
|
export interface Column<T> {
|
|
44
46
|
id: string;
|
|
@@ -210,6 +212,9 @@ export function DataTable<T>({
|
|
|
210
212
|
columns.filter((c) => c.defaultHidden && !c.required).map((c) => [c.id, true]),
|
|
211
213
|
),
|
|
212
214
|
);
|
|
215
|
+
// Column order and runtime pins are per-mount, like `hidden`.
|
|
216
|
+
const [order, setOrder] = useState<string[] | null>(null);
|
|
217
|
+
const [dragId, setDragId] = useState<string | null>(null);
|
|
213
218
|
const [sort, setSort] = useState<{ id: string; dir: "asc" | "desc" } | null>(
|
|
214
219
|
defaultSort ?? null,
|
|
215
220
|
);
|
|
@@ -218,8 +223,31 @@ export function DataTable<T>({
|
|
|
218
223
|
const [selected, setSelected] = useState<Set<string>>(new Set());
|
|
219
224
|
const [activeFilterIds, setActiveFilterIds] = useState<string[]>([]);
|
|
220
225
|
|
|
221
|
-
const
|
|
222
|
-
const
|
|
226
|
+
const propOrder = columns.map((c) => c.id);
|
|
227
|
+
const byId = new Map(columns.map((c) => [c.id, c] as const));
|
|
228
|
+
const orderedColumns = order
|
|
229
|
+
? order.map((id) => byId.get(id)).filter((c): c is Column<T> => Boolean(c))
|
|
230
|
+
: columns;
|
|
231
|
+
const visibleColumns = orderedColumns.filter((c) => !hidden[c.id]);
|
|
232
|
+
const hiddenColumns = orderedColumns.filter((c) => hidden[c.id] && !c.required);
|
|
233
|
+
// ponytail: mouse-only drag reorder; add keyboard move (Alt+Arrow) if asked.
|
|
234
|
+
const isPinned = (c: Column<T>) => Boolean(c.required);
|
|
235
|
+
const columnAt = (id: string) => byId.get(id);
|
|
236
|
+
|
|
237
|
+
const moveBefore = (draggedId: string, targetId: string) => {
|
|
238
|
+
const target = targetId ? columnAt(targetId) : undefined;
|
|
239
|
+
if (!target || isPinned(target) || draggedId === targetId) return;
|
|
240
|
+
setOrder((prev) => {
|
|
241
|
+
const ids = prev ?? propOrder;
|
|
242
|
+
return reorderIds(ids, ids.indexOf(draggedId), ids.indexOf(targetId));
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const showColumn = (id: string) => {
|
|
247
|
+
setHidden((prev) => ({ ...prev, [id]: false }));
|
|
248
|
+
// Re-showing appends at the end of the current order.
|
|
249
|
+
setOrder((prev) => (prev && prev.includes(id) ? prev : [...(prev ?? propOrder), id]));
|
|
250
|
+
};
|
|
223
251
|
const activeFilters = (filters ?? []).filter((f) => activeFilterIds.includes(f.id));
|
|
224
252
|
const filterSignature = (filters ?? [])
|
|
225
253
|
.map((f) => `${f.id}:${f.value.join(",")}`)
|
|
@@ -371,26 +399,60 @@ export function DataTable<T>({
|
|
|
371
399
|
variant="secondary"
|
|
372
400
|
size="md"
|
|
373
401
|
leadingIcon={<ColumnsIcon />}
|
|
374
|
-
trailingIcon={<
|
|
402
|
+
trailingIcon={<DropdownMenuChevron />}
|
|
375
403
|
>
|
|
376
404
|
Columns
|
|
377
405
|
</Button>
|
|
378
406
|
</DropdownMenuTrigger>
|
|
379
407
|
<DropdownMenuContent align="end" className="w-54">
|
|
380
408
|
<DropdownMenuLabel className="text-[13px]">Active columns</DropdownMenuLabel>
|
|
381
|
-
{visibleColumns.map((c) =>
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
409
|
+
{visibleColumns.map((c) => {
|
|
410
|
+
const pinned = isPinned(c);
|
|
411
|
+
return (
|
|
412
|
+
<DropdownMenuCheckboxItem
|
|
413
|
+
key={c.id}
|
|
414
|
+
checked
|
|
415
|
+
draggable={!pinned}
|
|
416
|
+
onDragStart={(e) => {
|
|
417
|
+
if (pinned) {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
e.dataTransfer.effectAllowed = "move";
|
|
422
|
+
e.dataTransfer.setData("text/plain", c.id);
|
|
423
|
+
setDragId(c.id);
|
|
424
|
+
}}
|
|
425
|
+
onDragOver={(e) => {
|
|
426
|
+
if (dragId) {
|
|
427
|
+
e.preventDefault();
|
|
428
|
+
moveBefore(dragId, c.id);
|
|
429
|
+
}
|
|
430
|
+
}}
|
|
431
|
+
onDrop={(e) => e.preventDefault()}
|
|
432
|
+
onDragEnd={() => setDragId(null)}
|
|
433
|
+
onCheckedChange={(next) => {
|
|
434
|
+
if (!next && !pinned) {
|
|
435
|
+
setHidden((prev) => ({ ...prev, [c.id]: true }));
|
|
436
|
+
}
|
|
437
|
+
}}
|
|
438
|
+
onSelect={(e) => e.preventDefault()}
|
|
439
|
+
className="justify-between"
|
|
440
|
+
>
|
|
441
|
+
<span className="truncate">{c.header}</span>
|
|
442
|
+
{pinned ? (
|
|
443
|
+
<Lock className="size-3.5 shrink-0 text-subtle" aria-hidden />
|
|
444
|
+
) : (
|
|
445
|
+
<DotsSixVertical
|
|
446
|
+
aria-hidden
|
|
447
|
+
className={cn(
|
|
448
|
+
"size-3.5 shrink-0",
|
|
449
|
+
dragId === c.id ? "text-primary" : "text-subtle",
|
|
450
|
+
)}
|
|
451
|
+
/>
|
|
452
|
+
)}
|
|
453
|
+
</DropdownMenuCheckboxItem>
|
|
454
|
+
);
|
|
455
|
+
})}
|
|
394
456
|
{hiddenColumns.length > 0 ? (
|
|
395
457
|
<>
|
|
396
458
|
<DropdownMenuSeparator />
|
|
@@ -399,7 +461,7 @@ export function DataTable<T>({
|
|
|
399
461
|
<DropdownMenuCheckboxItem
|
|
400
462
|
key={c.id}
|
|
401
463
|
checked={false}
|
|
402
|
-
onCheckedChange={() =>
|
|
464
|
+
onCheckedChange={() => showColumn(c.id)}
|
|
403
465
|
onSelect={(e) => e.preventDefault()}
|
|
404
466
|
>
|
|
405
467
|
{c.header}
|
package/src/dropdown-menu.tsx
CHANGED
|
@@ -35,12 +35,15 @@ export function DropdownMenu({
|
|
|
35
35
|
export const DropdownMenuTrigger = forwardRef<
|
|
36
36
|
ElementRef<typeof DropdownMenuPrimitive.Trigger>,
|
|
37
37
|
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
|
|
38
|
-
>(({ disabled, ...props }, ref) => {
|
|
38
|
+
>(({ className, disabled, ...props }, ref) => {
|
|
39
39
|
const empty = useContext(DropdownMenuEmptyContext);
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<DropdownMenuPrimitive.Trigger
|
|
43
43
|
ref={ref}
|
|
44
|
+
// `group` lets DropdownMenuChevron rotate with the open state, even
|
|
45
|
+
// when the trigger renders through asChild onto a custom button.
|
|
46
|
+
className={cn("group", className)}
|
|
44
47
|
disabled={disabled || empty}
|
|
45
48
|
{...props}
|
|
46
49
|
/>
|
package/src/select.tsx
CHANGED
|
@@ -54,7 +54,7 @@ export const SelectTrigger = forwardRef<
|
|
|
54
54
|
>
|
|
55
55
|
<span className="min-w-0 flex-1 truncate text-left">{children}</span>
|
|
56
56
|
<SelectPrimitive.Icon asChild>
|
|
57
|
-
<CaretDown className="ml-auto size-3.5 shrink-0 text-
|
|
57
|
+
<CaretDown className="ml-auto size-3.5 shrink-0 text-muted transition-transform duration-200 ease-out group-data-[state=open]:rotate-180 motion-reduce:transition-none" />
|
|
58
58
|
</SelectPrimitive.Icon>
|
|
59
59
|
</SelectPrimitive.Trigger>
|
|
60
60
|
));
|
package/src/utils.ts
CHANGED
|
@@ -5,3 +5,14 @@ import { twMerge } from "tailwind-merge";
|
|
|
5
5
|
export function cn(...inputs: ClassValue[]): string {
|
|
6
6
|
return twMerge(clsx(inputs));
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
/** Move the id at `from` so it sits at `to`; no-op when indexes match. */
|
|
10
|
+
export function reorderIds(ids: string[], from: number, to: number): string[] {
|
|
11
|
+
if (from === to || from < 0 || to < 0 || from >= ids.length || to >= ids.length) {
|
|
12
|
+
return ids;
|
|
13
|
+
}
|
|
14
|
+
const next = [...ids];
|
|
15
|
+
const [moved] = next.splice(from, 1);
|
|
16
|
+
next.splice(to, 0, moved);
|
|
17
|
+
return next;
|
|
18
|
+
}
|