@sarunyu/system-one 4.0.4 → 4.1.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/dist/index.cjs +19 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/src/components/table.d.ts +2 -0
- package/dist/src/components/table.d.ts.map +1 -1
- package/llms.txt +147 -5
- package/package.json +1 -1
|
@@ -41,6 +41,8 @@ export interface TableCellProps extends TdHTMLAttributes<HTMLTableCellElement> {
|
|
|
41
41
|
export declare const Table: import('react').ForwardRefExoticComponent<TableProps & import('react').RefAttributes<HTMLTableElement>>;
|
|
42
42
|
export interface TableRowProps extends HTMLAttributes<HTMLTableRowElement> {
|
|
43
43
|
selected?: boolean;
|
|
44
|
+
/** Fires when a `<TableCell type="checkbox" />` inside this row is toggled. Set this together with `selected` to make rows selectable — the cell's checkbox is wired automatically. */
|
|
45
|
+
onSelectedChange?: (next: boolean) => void;
|
|
44
46
|
/** Enables built-in hover state propagation to cells in this row. */
|
|
45
47
|
hoverable?: boolean;
|
|
46
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/components/table.tsx"],"names":[],"mappings":"AAGA,OAAO,EAQL,KAAK,cAAc,EAEnB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAO,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAG7C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACxD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAChE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC5G,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,kBAAkB,CAAC;AAEzE,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACvE,sFAAsF;IACtF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB,CAAC,oBAAoB,CAAC;IAClF,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACxC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,KAAK,IAAI,CAAC;IACvD,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB,CAAC,oBAAoB,CAAC;IAC5E,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/components/table.tsx"],"names":[],"mappings":"AAGA,OAAO,EAQL,KAAK,cAAc,EAEnB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAO,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAG7C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACxD,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;AAChE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC5G,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,kBAAkB,CAAC;AAEzE,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACvE,sFAAsF;IACtF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB,CAAC,oBAAoB,CAAC;IAClF,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACxC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,KAAK,IAAI,CAAC;IACvD,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB,CAAC,oBAAoB,CAAC;IAC5E,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAuED,eAAO,MAAM,KAAK,yGA0DhB,CAAC;AAEH,MAAM,WAAW,aAAc,SAAQ,cAAc,CAAC,mBAAmB,CAAC;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uLAAuL;IACvL,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3C,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,QAAQ,+GA0CpB,CAAC;AAEF,eAAO,MAAM,eAAe,uHAwH3B,CAAC;AAEF,eAAO,MAAM,SAAS,iHA8JpB,CAAC"}
|
package/llms.txt
CHANGED
|
@@ -439,6 +439,117 @@ Data tables. Compose with TableRow + TableHeaderCell + TableCell.
|
|
|
439
439
|
|
|
440
440
|
Align numeric columns `right`, status center. Don't stuff StatusTag inside the Table header.
|
|
441
441
|
|
|
442
|
+
**TableCell content** — pass content as children (`<TableCell>{u.name}</TableCell>`).
|
|
443
|
+
Do NOT pass a `label` prop for dynamic data — if children are omitted, the cell
|
|
444
|
+
shows the placeholder `"Text label"`.
|
|
445
|
+
|
|
446
|
+
**Sorting is not automatic.** `TableHeaderCell` is a UI primitive — it only
|
|
447
|
+
toggles its own arrow icon. The parent must own sort state AND sort the data.
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
import { useMemo, useState } from "react";
|
|
451
|
+
import { Table, TableRow, TableHeaderCell, TableCell } from "@sarunyu/system-one";
|
|
452
|
+
|
|
453
|
+
type SortDir = "none" | "asc" | "desc";
|
|
454
|
+
|
|
455
|
+
export function UsersTable({ users }: { users: User[] }) {
|
|
456
|
+
const [sortKey, setSortKey] = useState<keyof User | null>(null);
|
|
457
|
+
const [sortDir, setSortDir] = useState<SortDir>("none");
|
|
458
|
+
|
|
459
|
+
const sorted = useMemo(() => {
|
|
460
|
+
if (!sortKey || sortDir === "none") return users;
|
|
461
|
+
const copy = [...users];
|
|
462
|
+
copy.sort((a, b) => {
|
|
463
|
+
const av = a[sortKey]; const bv = b[sortKey];
|
|
464
|
+
if (av < bv) return sortDir === "asc" ? -1 : 1;
|
|
465
|
+
if (av > bv) return sortDir === "asc" ? 1 : -1;
|
|
466
|
+
return 0;
|
|
467
|
+
});
|
|
468
|
+
return copy;
|
|
469
|
+
}, [users, sortKey, sortDir]);
|
|
470
|
+
|
|
471
|
+
const dirFor = (k: keyof User): SortDir => (sortKey === k ? sortDir : "none");
|
|
472
|
+
const handleSort = (k: keyof User) => (next: SortDir) => {
|
|
473
|
+
setSortKey(next === "none" ? null : k);
|
|
474
|
+
setSortDir(next);
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
return (
|
|
478
|
+
<Table>
|
|
479
|
+
<TableRow header>
|
|
480
|
+
<TableHeaderCell sortDirection={dirFor("name")} onSortChange={handleSort("name")}>Name</TableHeaderCell>
|
|
481
|
+
<TableHeaderCell sortDirection={dirFor("role")} onSortChange={handleSort("role")}>Role</TableHeaderCell>
|
|
482
|
+
<TableHeaderCell sortable={false}>Status</TableHeaderCell>
|
|
483
|
+
</TableRow>
|
|
484
|
+
{sorted.map(u => (
|
|
485
|
+
<TableRow key={u.id}>
|
|
486
|
+
<TableCell>{u.name}</TableCell>
|
|
487
|
+
<TableCell>{u.role}</TableCell>
|
|
488
|
+
<TableCell><StatusTag type={u.status} /></TableCell>
|
|
489
|
+
</TableRow>
|
|
490
|
+
))}
|
|
491
|
+
</Table>
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Key rules for sort:
|
|
497
|
+
- Parent owns `sortKey` + `sortDir` state.
|
|
498
|
+
- Parent derives `sorted` data via `useMemo` — the Table never mutates data.
|
|
499
|
+
- Pass `sortDirection` (controlled) + `onSortChange` to every sortable header.
|
|
500
|
+
- Only one column sorts at a time — when a column's `sortKey` changes, previous columns naturally read `"none"` via the `dirFor` helper.
|
|
501
|
+
- Columns that shouldn't sort (status, actions) → `sortable={false}`.
|
|
502
|
+
|
|
503
|
+
**Selectable rows.** To make rows selectable with checkboxes, pair `<TableRow selected onSelectedChange>` with a `<TableCell type="checkbox" />`. The cell renders its own checkbox wired to the row — **do not put a `<Checkbox>` inside the cell yourself.** The row background turns brand-tinted automatically when `selected` is true.
|
|
504
|
+
|
|
505
|
+
```tsx
|
|
506
|
+
import { useMemo, useState } from "react";
|
|
507
|
+
import { Table, TableRow, TableHeaderCell, TableCell } from "@sarunyu/system-one";
|
|
508
|
+
|
|
509
|
+
export function SelectableTable({ rows }: { rows: Row[] }) {
|
|
510
|
+
const [selected, setSelected] = useState<Set<string>>(new Set());
|
|
511
|
+
|
|
512
|
+
const toggle = (id: string) => (next: boolean) =>
|
|
513
|
+
setSelected(prev => {
|
|
514
|
+
const copy = new Set(prev);
|
|
515
|
+
next ? copy.add(id) : copy.delete(id);
|
|
516
|
+
return copy;
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
const headerState =
|
|
520
|
+
selected.size === 0 ? false : selected.size === rows.length ? true : "indeterminate";
|
|
521
|
+
const toggleAll = (next: boolean) =>
|
|
522
|
+
setSelected(next ? new Set(rows.map(r => r.id)) : new Set());
|
|
523
|
+
|
|
524
|
+
return (
|
|
525
|
+
<Table>
|
|
526
|
+
<TableRow header>
|
|
527
|
+
<TableHeaderCell type="check" checkState={headerState} onCheckChange={toggleAll} />
|
|
528
|
+
<TableHeaderCell>Symbol</TableHeaderCell>
|
|
529
|
+
<TableHeaderCell>Name</TableHeaderCell>
|
|
530
|
+
</TableRow>
|
|
531
|
+
{rows.map(r => (
|
|
532
|
+
<TableRow
|
|
533
|
+
key={r.id}
|
|
534
|
+
selected={selected.has(r.id)}
|
|
535
|
+
onSelectedChange={toggle(r.id)}
|
|
536
|
+
>
|
|
537
|
+
<TableCell type="checkbox" />
|
|
538
|
+
<TableCell>{r.symbol}</TableCell>
|
|
539
|
+
<TableCell>{r.name}</TableCell>
|
|
540
|
+
</TableRow>
|
|
541
|
+
))}
|
|
542
|
+
</Table>
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Props:
|
|
548
|
+
- `Table` — `className`, native `<table>` props.
|
|
549
|
+
- `TableRow` — `header?`, `selected?`, `onSelectedChange?(next: boolean)` (fires when a `type="checkbox"` cell in this row is toggled), `hoverable?` (default `true`), `onClick`, `className`.
|
|
550
|
+
- `TableHeaderCell` — `children` (label), `type?: "text" | "icon" | "check"` (use `"check"` for select-all column), `checkState?: boolean | "indeterminate"`, `onCheckChange?(next)`, `sortable?` (default `true`, set `false` to hide the arrow), `sortDirection?: "none" | "asc" | "desc"`, `onSortChange?(next)`, `contentAlign?: "start" | "center" | "end"`, `className`.
|
|
551
|
+
- `TableCell` — `children` (content), `type?: "default" | "text-icon" | "text-image" | "tag" | "icon" | "button" | "checkbox"`, `contentAlign?`, `fixed?`, `className`. For `type="checkbox"` the cell renders its own checkbox — bind selection via the parent `TableRow`, not by nesting a `<Checkbox>`.
|
|
552
|
+
|
|
442
553
|
---
|
|
443
554
|
|
|
444
555
|
### DateInput / TimeInput
|
|
@@ -657,11 +768,42 @@ export function SettingsPage() {
|
|
|
657
768
|
### Data table page
|
|
658
769
|
|
|
659
770
|
```tsx
|
|
771
|
+
import { useMemo, useState } from "react";
|
|
660
772
|
import {
|
|
661
773
|
SearchInput, Button, Table, TableRow, TableHeaderCell, TableCell, StatusTag,
|
|
662
774
|
} from "@sarunyu/system-one";
|
|
663
775
|
|
|
776
|
+
type SortDir = "none" | "asc" | "desc";
|
|
777
|
+
type OrderKey = "id" | "customer" | "amount";
|
|
778
|
+
|
|
664
779
|
export function OrdersPage() {
|
|
780
|
+
const [q, setQ] = useState("");
|
|
781
|
+
const [sortKey, setSortKey] = useState<OrderKey | null>(null);
|
|
782
|
+
const [sortDir, setSortDir] = useState<SortDir>("none");
|
|
783
|
+
|
|
784
|
+
const filtered = useMemo(
|
|
785
|
+
() => orders.filter(o => o.customer.toLowerCase().includes(q.toLowerCase())),
|
|
786
|
+
[q],
|
|
787
|
+
);
|
|
788
|
+
|
|
789
|
+
const sorted = useMemo(() => {
|
|
790
|
+
if (!sortKey || sortDir === "none") return filtered;
|
|
791
|
+
const copy = [...filtered];
|
|
792
|
+
copy.sort((a, b) => {
|
|
793
|
+
const av = a[sortKey]; const bv = b[sortKey];
|
|
794
|
+
if (av < bv) return sortDir === "asc" ? -1 : 1;
|
|
795
|
+
if (av > bv) return sortDir === "asc" ? 1 : -1;
|
|
796
|
+
return 0;
|
|
797
|
+
});
|
|
798
|
+
return copy;
|
|
799
|
+
}, [filtered, sortKey, sortDir]);
|
|
800
|
+
|
|
801
|
+
const dirFor = (k: OrderKey): SortDir => (sortKey === k ? sortDir : "none");
|
|
802
|
+
const handleSort = (k: OrderKey) => (next: SortDir) => {
|
|
803
|
+
setSortKey(next === "none" ? null : k);
|
|
804
|
+
setSortDir(next);
|
|
805
|
+
};
|
|
806
|
+
|
|
665
807
|
return (
|
|
666
808
|
<main className="mx-auto w-full max-w-[1200px] px-6 py-10 flex flex-col gap-6">
|
|
667
809
|
<header className="flex items-center justify-between">
|
|
@@ -673,12 +815,12 @@ export function OrdersPage() {
|
|
|
673
815
|
</div>
|
|
674
816
|
<Table>
|
|
675
817
|
<TableRow header>
|
|
676
|
-
<TableHeaderCell>Order</TableHeaderCell>
|
|
677
|
-
<TableHeaderCell>Customer</TableHeaderCell>
|
|
678
|
-
<TableHeaderCell>Amount</TableHeaderCell>
|
|
679
|
-
<TableHeaderCell>Status</TableHeaderCell>
|
|
818
|
+
<TableHeaderCell sortDirection={dirFor("id")} onSortChange={handleSort("id")}>Order</TableHeaderCell>
|
|
819
|
+
<TableHeaderCell sortDirection={dirFor("customer")} onSortChange={handleSort("customer")}>Customer</TableHeaderCell>
|
|
820
|
+
<TableHeaderCell sortDirection={dirFor("amount")} onSortChange={handleSort("amount")}>Amount</TableHeaderCell>
|
|
821
|
+
<TableHeaderCell sortable={false}>Status</TableHeaderCell>
|
|
680
822
|
</TableRow>
|
|
681
|
-
{
|
|
823
|
+
{sorted.map(o => (
|
|
682
824
|
<TableRow key={o.id}>
|
|
683
825
|
<TableCell>#{o.id}</TableCell>
|
|
684
826
|
<TableCell>{o.customer}</TableCell>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sarunyu/system-one",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A production-ready React design system built for AI-powered web generation tools (Figma Make, Lovable, V0). Tailwind CSS v4 + CSS custom properties for full theming support.",
|
|
6
6
|
"keywords": [
|