@jinaan/uikit 0.1.1 → 0.1.3
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/README.md +0 -28
- package/dist/data-table.d.ts.map +1 -1
- package/dist/index.js +573 -569
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/data-table.tsx +77 -75
- package/src/dropdown-menu.tsx +6 -6
- package/src/input.tsx +9 -9
- package/styles.css +2 -1
package/package.json
CHANGED
package/src/data-table.tsx
CHANGED
|
@@ -145,9 +145,6 @@ interface DataTableProps<T> {
|
|
|
145
145
|
const HEADER_CELL =
|
|
146
146
|
"h-[var(--table-header-h)] whitespace-nowrap px-[var(--table-pad-x)] text-left align-middle text-[0.8125rem] font-medium";
|
|
147
147
|
|
|
148
|
-
const TOOLBAR_BUTTON =
|
|
149
|
-
"rounded-[6px] bg-surface text-fg shadow-xs ring-1 ring-line hover:bg-elevated hover:text-fg active:bg-elevated";
|
|
150
|
-
|
|
151
148
|
function initials(name: string): string {
|
|
152
149
|
return name
|
|
153
150
|
.split(/\s+/)
|
|
@@ -356,7 +353,6 @@ export function DataTable<T>({
|
|
|
356
353
|
<div className="flex flex-wrap items-center gap-2">
|
|
357
354
|
{search && (
|
|
358
355
|
<Input
|
|
359
|
-
size="sm"
|
|
360
356
|
type="search"
|
|
361
357
|
aria-label={search.placeholder ?? "Search"}
|
|
362
358
|
placeholder={search.placeholder ?? "Search..."}
|
|
@@ -373,10 +369,9 @@ export function DataTable<T>({
|
|
|
373
369
|
<DropdownMenuTrigger asChild>
|
|
374
370
|
<Button
|
|
375
371
|
variant="secondary"
|
|
376
|
-
size="
|
|
372
|
+
size="md"
|
|
377
373
|
leadingIcon={<ColumnsIcon />}
|
|
378
374
|
trailingIcon={<CaretDown />}
|
|
379
|
-
className={TOOLBAR_BUTTON}
|
|
380
375
|
>
|
|
381
376
|
Columns
|
|
382
377
|
</Button>
|
|
@@ -419,10 +414,9 @@ export function DataTable<T>({
|
|
|
419
414
|
<DropdownMenuTrigger asChild>
|
|
420
415
|
<Button
|
|
421
416
|
variant="secondary"
|
|
422
|
-
size="
|
|
417
|
+
size="md"
|
|
423
418
|
iconOnly
|
|
424
419
|
aria-label="Add filter"
|
|
425
|
-
className={TOOLBAR_BUTTON}
|
|
426
420
|
>
|
|
427
421
|
<FunnelSimple />
|
|
428
422
|
</Button>
|
|
@@ -443,70 +437,74 @@ export function DataTable<T>({
|
|
|
443
437
|
</DropdownMenuContent>
|
|
444
438
|
</DropdownMenu>
|
|
445
439
|
) : null}
|
|
446
|
-
{toolbarEnd ?
|
|
447
|
-
<div className="flex-0 sm:ml-auto [&_button]:h-8 [&_button]:rounded-[6px]">
|
|
448
|
-
{toolbarEnd}
|
|
449
|
-
</div>
|
|
450
|
-
) : null}
|
|
440
|
+
{toolbarEnd ? <div className="flex-0 sm:ml-auto">{toolbarEnd}</div> : null}
|
|
451
441
|
</div>
|
|
452
442
|
)}
|
|
453
443
|
|
|
454
444
|
{activeFilters.length > 0 ? (
|
|
455
445
|
<div className="flex flex-wrap items-center gap-2">
|
|
456
|
-
{activeFilters.map((filter) =>
|
|
457
|
-
|
|
458
|
-
|
|
446
|
+
{activeFilters.map((filter) => {
|
|
447
|
+
const clear = () => {
|
|
448
|
+
filter.onChange([]);
|
|
449
|
+
setActiveFilterIds((prev) => prev.filter((id) => id !== filter.id));
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
return (
|
|
453
|
+
<div key={filter.id} className="inline-flex items-center">
|
|
459
454
|
<Button
|
|
460
|
-
variant="
|
|
461
|
-
size="
|
|
462
|
-
|
|
455
|
+
variant="secondary"
|
|
456
|
+
size="md"
|
|
457
|
+
iconOnly
|
|
458
|
+
aria-label={`Remove ${filter.label} filter`}
|
|
459
|
+
className="rounded-r-none"
|
|
460
|
+
onClick={clear}
|
|
463
461
|
>
|
|
464
|
-
<
|
|
465
|
-
<span className="font-medium">{filter.label}</span>
|
|
466
|
-
<span className="h-4 w-px bg-line" aria-hidden />
|
|
467
|
-
<span className="text-muted">
|
|
468
|
-
{filter.value.length > 0
|
|
469
|
-
? `${filter.value.length} selected`
|
|
470
|
-
: "Enter value"}
|
|
471
|
-
</span>
|
|
472
|
-
<CaretDown className="text-muted" />
|
|
462
|
+
<X />
|
|
473
463
|
</Button>
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
464
|
+
<DropdownMenu>
|
|
465
|
+
<DropdownMenuTrigger asChild>
|
|
466
|
+
<Button variant="secondary" size="md" className="rounded-l-none pl-2">
|
|
467
|
+
<FunnelSimple />
|
|
468
|
+
<span className="font-medium">{filter.label}</span>
|
|
469
|
+
<span className="h-4 w-px bg-line" aria-hidden />
|
|
470
|
+
<span className="text-muted">
|
|
471
|
+
{filter.value.length > 0
|
|
472
|
+
? `${filter.value.length} selected`
|
|
473
|
+
: "Enter value"}
|
|
474
|
+
</span>
|
|
475
|
+
<CaretDown className="text-muted" />
|
|
476
|
+
</Button>
|
|
477
|
+
</DropdownMenuTrigger>
|
|
478
|
+
<DropdownMenuContent align="start" className="w-56">
|
|
479
|
+
<DropdownMenuLabel className="text-[13px]">
|
|
480
|
+
Filter by {filter.label}
|
|
481
|
+
</DropdownMenuLabel>
|
|
482
|
+
{filter.options.map((option) => {
|
|
483
|
+
const checked = filter.value.includes(option.value);
|
|
484
|
+
return (
|
|
485
|
+
<DropdownMenuCheckboxItem
|
|
486
|
+
key={option.value}
|
|
487
|
+
checked={checked}
|
|
488
|
+
onCheckedChange={() =>
|
|
489
|
+
filter.onChange(
|
|
490
|
+
checked
|
|
491
|
+
? filter.value.filter((value) => value !== option.value)
|
|
492
|
+
: [...filter.value, option.value],
|
|
493
|
+
)
|
|
494
|
+
}
|
|
495
|
+
onSelect={(e) => e.preventDefault()}
|
|
496
|
+
>
|
|
497
|
+
{option.label}
|
|
498
|
+
</DropdownMenuCheckboxItem>
|
|
499
|
+
);
|
|
500
|
+
})}
|
|
501
|
+
<DropdownMenuSeparator />
|
|
502
|
+
<DropdownMenuItem onSelect={clear}>Clear filter</DropdownMenuItem>
|
|
503
|
+
</DropdownMenuContent>
|
|
504
|
+
</DropdownMenu>
|
|
505
|
+
</div>
|
|
506
|
+
);
|
|
507
|
+
})}
|
|
510
508
|
<button
|
|
511
509
|
type="button"
|
|
512
510
|
onClick={() => {
|
|
@@ -529,7 +527,7 @@ export function DataTable<T>({
|
|
|
529
527
|
{(bulkActions ?? []).map((a) => (
|
|
530
528
|
<Button
|
|
531
529
|
key={a.label}
|
|
532
|
-
size="
|
|
530
|
+
size="md"
|
|
533
531
|
variant={a.variant ?? "outline"}
|
|
534
532
|
disabled={a.disabled}
|
|
535
533
|
onClick={() => void a.onRun(selectedRows)}
|
|
@@ -567,7 +565,7 @@ export function DataTable<T>({
|
|
|
567
565
|
<thead>
|
|
568
566
|
<tr>
|
|
569
567
|
{selectable && (
|
|
570
|
-
<th className="h-
|
|
568
|
+
<th className="h-(--table-header-h) w-11 px-4 align-middle">
|
|
571
569
|
<Checkbox
|
|
572
570
|
aria-label="Select all rows"
|
|
573
571
|
checked={allSelected ? true : someSelected ? "indeterminate" : false}
|
|
@@ -581,12 +579,16 @@ export function DataTable<T>({
|
|
|
581
579
|
className={cn(HEADER_CELL, c.align === "right" && "text-right", c.className)}
|
|
582
580
|
>
|
|
583
581
|
{c.sortable ? (
|
|
584
|
-
<
|
|
582
|
+
<Button
|
|
585
583
|
type="button"
|
|
584
|
+
variant="ghost"
|
|
585
|
+
size="xs"
|
|
586
586
|
aria-label={`Sort by ${c.header}`}
|
|
587
587
|
onClick={() => toggleSort(c)}
|
|
588
588
|
className={cn(
|
|
589
|
-
"
|
|
589
|
+
"h-auto gap-1.5 rounded-none px-0 py-0 text-[0.8125rem] text-table-header transition-colors [&_svg]:size-3.5",
|
|
590
|
+
"hover:bg-transparent hover:text-table-header-active hover:shadow-none",
|
|
591
|
+
"active:scale-100 active:bg-transparent active:shadow-none",
|
|
590
592
|
sort?.id === c.id && "text-table-header-active",
|
|
591
593
|
)}
|
|
592
594
|
>
|
|
@@ -600,14 +602,14 @@ export function DataTable<T>({
|
|
|
600
602
|
) : (
|
|
601
603
|
<CaretUpDown className="size-3.5 opacity-50" />
|
|
602
604
|
)}
|
|
603
|
-
</
|
|
605
|
+
</Button>
|
|
604
606
|
) : (
|
|
605
607
|
c.header
|
|
606
608
|
)}
|
|
607
609
|
</th>
|
|
608
610
|
))}
|
|
609
611
|
{rowActions && (
|
|
610
|
-
<th className="h-
|
|
612
|
+
<th className="h-(--table-header-h) w-44 px-4 align-middle">
|
|
611
613
|
<span className="sr-only">Actions</span>
|
|
612
614
|
</th>
|
|
613
615
|
)}
|
|
@@ -623,8 +625,8 @@ export function DataTable<T>({
|
|
|
623
625
|
))}
|
|
624
626
|
</div>
|
|
625
627
|
) : error ? (
|
|
626
|
-
<div className="flex min-h-
|
|
627
|
-
<div className="flex size-
|
|
628
|
+
<div className="flex min-h-88 flex-col items-center justify-center gap-4 px-6 py-16 text-center">
|
|
629
|
+
<div className="flex size-(--table-empty-icon) items-center justify-center rounded-2xl border border-table-empty-icon-border bg-table-empty-icon text-error [&_svg]:size-8">
|
|
628
630
|
<WarningCircle weight="duotone" />
|
|
629
631
|
</div>
|
|
630
632
|
<div className="space-y-2">
|
|
@@ -714,7 +716,7 @@ export function DataTable<T>({
|
|
|
714
716
|
</span>
|
|
715
717
|
<div className="flex items-center gap-2">
|
|
716
718
|
<Select value={String(pageSize)} onValueChange={(v) => setPageSize(Number(v))}>
|
|
717
|
-
<SelectTrigger aria-label="Rows per page" className="
|
|
719
|
+
<SelectTrigger aria-label="Rows per page" className="w-27.5">
|
|
718
720
|
<SelectValue />
|
|
719
721
|
</SelectTrigger>
|
|
720
722
|
<SelectContent>
|
|
@@ -727,7 +729,7 @@ export function DataTable<T>({
|
|
|
727
729
|
</Select>
|
|
728
730
|
<Button
|
|
729
731
|
variant="outline"
|
|
730
|
-
size="
|
|
732
|
+
size="md"
|
|
731
733
|
disabled={page <= 0}
|
|
732
734
|
onClick={() => setPage((p) => Math.max(0, p - 1))}
|
|
733
735
|
>
|
|
@@ -735,7 +737,7 @@ export function DataTable<T>({
|
|
|
735
737
|
</Button>
|
|
736
738
|
<Button
|
|
737
739
|
variant="outline"
|
|
738
|
-
size="
|
|
740
|
+
size="md"
|
|
739
741
|
disabled={page >= pageCount - 1}
|
|
740
742
|
onClick={() => setPage((p) => Math.min(pageCount - 1, p + 1))}
|
|
741
743
|
>
|
package/src/dropdown-menu.tsx
CHANGED
|
@@ -22,7 +22,7 @@ export const DropdownMenuContent = forwardRef<
|
|
|
22
22
|
ref={ref}
|
|
23
23
|
sideOffset={sideOffset}
|
|
24
24
|
className={cn(
|
|
25
|
-
"z-50 min-w-48 overflow-hidden rounded-lg border border-line bg-
|
|
25
|
+
"z-50 min-w-48 overflow-hidden rounded-lg border border-line bg-[var(--button-secondary-bg)] p-1 shadow-md",
|
|
26
26
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
27
27
|
"data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0",
|
|
28
28
|
"data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95",
|
|
@@ -45,7 +45,7 @@ export const DropdownMenuItem = forwardRef<
|
|
|
45
45
|
ref={ref}
|
|
46
46
|
className={cn(
|
|
47
47
|
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm text-fg outline-none transition-colors",
|
|
48
|
-
"focus:bg-
|
|
48
|
+
"focus:bg-[var(--menu-highlight)] data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
49
49
|
"[&_svg]:size-4 [&_svg]:text-muted",
|
|
50
50
|
inset && "pl-8",
|
|
51
51
|
className,
|
|
@@ -62,15 +62,15 @@ export const DropdownMenuCheckboxItem = forwardRef<
|
|
|
62
62
|
<DropdownMenuPrimitive.CheckboxItem
|
|
63
63
|
ref={ref}
|
|
64
64
|
className={cn(
|
|
65
|
-
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm text-fg outline-none transition-colors focus:bg-
|
|
65
|
+
"group relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm text-fg outline-none transition-colors focus:bg-[var(--menu-highlight)]",
|
|
66
66
|
className,
|
|
67
67
|
)}
|
|
68
68
|
checked={checked}
|
|
69
69
|
{...props}
|
|
70
70
|
>
|
|
71
|
-
<span className="absolute left-2 flex size-4 items-center justify-center">
|
|
72
|
-
<DropdownMenuPrimitive.ItemIndicator>
|
|
73
|
-
<Check className="size-3
|
|
71
|
+
<span className="absolute left-2 flex size-4 shrink-0 items-center justify-center rounded border border-line-strong bg-transparent transition-colors group-data-[state=checked]:border-primary">
|
|
72
|
+
<DropdownMenuPrimitive.ItemIndicator className="btn-fill btn-inner-border flex size-full items-center justify-center rounded-[3px] border-0 bg-[var(--button-primary-bg)] text-[var(--button-primary-fg)] [--button-inner:var(--button-primary-inner)]">
|
|
73
|
+
<Check className="size-3" weight="bold" />
|
|
74
74
|
</DropdownMenuPrimitive.ItemIndicator>
|
|
75
75
|
</span>
|
|
76
76
|
{children}
|
package/src/input.tsx
CHANGED
|
@@ -110,17 +110,17 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
110
110
|
: undefined
|
|
111
111
|
}
|
|
112
112
|
className={cn(
|
|
113
|
-
"flex w-full rounded-
|
|
113
|
+
"flex w-full rounded-(--control-radius) border bg-(--input-bg) text-(--input-fg) transition-colors",
|
|
114
114
|
HEIGHT[size],
|
|
115
115
|
PAD_X[size],
|
|
116
|
-
"placeholder:text-
|
|
117
|
-
"hover:border-
|
|
118
|
-
"focus-visible:outline-none focus-visible:border-
|
|
116
|
+
"placeholder:text-(--input-placeholder)",
|
|
117
|
+
"hover:border-(--input-border-hover)",
|
|
118
|
+
"focus-visible:outline-none focus-visible:border-(--input-border-focus) focus-visible:ring-2 focus-visible:ring-focus/30",
|
|
119
119
|
error &&
|
|
120
120
|
"border-error hover:border-error focus-visible:border-error focus-visible:ring-error/30",
|
|
121
|
-
!error && "border-
|
|
121
|
+
!error && "border-(--input-border)",
|
|
122
122
|
disabled &&
|
|
123
|
-
"cursor-not-allowed bg-
|
|
123
|
+
"cursor-not-allowed bg-(--input-bg-disabled) opacity-60 hover:border-(--input-border)",
|
|
124
124
|
readOnly && "cursor-default focus-visible:ring-0",
|
|
125
125
|
className,
|
|
126
126
|
)}
|
|
@@ -141,7 +141,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
141
141
|
{leadingIcon ? (
|
|
142
142
|
<span
|
|
143
143
|
className={cn(
|
|
144
|
-
"pointer-events-none absolute inset-y-0 flex items-center text-
|
|
144
|
+
"pointer-events-none absolute inset-y-0 flex items-center text-(--input-placeholder)",
|
|
145
145
|
LEAD_INSET[size],
|
|
146
146
|
)}
|
|
147
147
|
aria-hidden
|
|
@@ -158,7 +158,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
158
158
|
aria-label="Clear search"
|
|
159
159
|
onClick={onClear}
|
|
160
160
|
className={cn(
|
|
161
|
-
"absolute inset-y-0 flex items-center text-
|
|
161
|
+
"absolute inset-y-0 flex items-center text-(--input-placeholder) transition-colors hover:text-(--input-fg)",
|
|
162
162
|
TRAIL_INSET[size],
|
|
163
163
|
)}
|
|
164
164
|
>
|
|
@@ -169,7 +169,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
|
169
169
|
) : trailingIcon ? (
|
|
170
170
|
<span
|
|
171
171
|
className={cn(
|
|
172
|
-
"pointer-events-none absolute inset-y-0 flex items-center text-
|
|
172
|
+
"pointer-events-none absolute inset-y-0 flex items-center text-(--input-placeholder)",
|
|
173
173
|
TRAIL_INSET[size],
|
|
174
174
|
)}
|
|
175
175
|
aria-hidden
|
package/styles.css
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
/* Data tables: header band is the darkest layer, the body panel sits above it
|
|
43
43
|
and the page is lighter than the header. */
|
|
44
|
-
--table-container-bg: #
|
|
44
|
+
--table-container-bg: #e9e9ec;
|
|
45
45
|
--table-panel-bg: #ffffff;
|
|
46
46
|
--table-panel-border: #e3e3e7;
|
|
47
47
|
--table-header-text: #5f5f6f;
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
--button-surface-hover: #f1f1f3;
|
|
106
106
|
--button-surface-active: #e9e9ec;
|
|
107
107
|
--button-ghost-hover: var(--button-surface-hover);
|
|
108
|
+
--menu-highlight: color-mix(in oklab, var(--button-secondary-bg) 85%, black);
|
|
108
109
|
--button-destructive-bg: var(--error);
|
|
109
110
|
--button-destructive-fg: #ffffff;
|
|
110
111
|
/* Destructive keeps its red identity; hover/pressed are red-shifted. */
|