blunt-ui 0.3.1 → 0.3.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/README.md +101 -1
- package/dist/components/DataTable/DataTable.stories.d.ts +1 -0
- package/dist/components/DataTable/DataTable.types.d.ts +5 -0
- package/dist/components/DataTable/index.d.ts +1 -1
- package/dist/components/Table/Table.stories.d.ts +1 -10
- package/dist/components/Table/Table.types.d.ts +1 -1
- package/dist/components/Table/index.d.ts +2 -0
- package/dist/components/Table/useTable.d.ts +12 -0
- package/dist/components/Table/useTableSort.d.ts +1 -1
- package/dist/index.cjs +86 -81
- package/dist/index.d.ts +3 -3
- package/dist/index.js +687 -648
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# blunt-ui
|
|
2
2
|
|
|
3
|
-
React + TypeScript + styled-components. Thick borders, offset shadows, no fluff.
|
|
3
|
+
React + TypeScript + styled-components. Thick borders, offset shadows, no fluff. 11 components, 3 hooks.
|
|
4
4
|
|
|
5
5
|
**Live demo:** https://blunt-ui.vercel.app/
|
|
6
6
|
|
|
@@ -179,6 +179,106 @@ const { values, errors, handleChange, handleBlur, handleSubmit, reset } =
|
|
|
179
179
|
|
|
180
180
|
The `name` on each input needs to match the key in `initialValues`. Use `reset()` to clear everything back to the start.
|
|
181
181
|
|
|
182
|
+
## Table
|
|
183
|
+
|
|
184
|
+
Read-only table with sorting and pagination. You define columns, pass data, done. Sorting and pagination work in both uncontrolled mode (component handles state internally) and controlled mode (you own the state, useful when data comes from an API).
|
|
185
|
+
|
|
186
|
+
Sizes: `sm`, `md`, `lg`.
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
const columns = [
|
|
190
|
+
{ key: "name", header: "Name", sortable: true },
|
|
191
|
+
{ key: "role", header: "Role" },
|
|
192
|
+
{ key: "status", header: "Status", render: (v) => <Badge>{v}</Badge> },
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
<Table
|
|
196
|
+
columns={columns}
|
|
197
|
+
data={rows}
|
|
198
|
+
rowKey="id"
|
|
199
|
+
striped
|
|
200
|
+
bordered
|
|
201
|
+
pageSize={10}
|
|
202
|
+
emptyMessage="No results"
|
|
203
|
+
/>;
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Sorting** — add `sortable: true` to any column. By default the table sorts client-side. If you want to handle it yourself (e.g. send a query param to your backend), pass `sort` + `onSortChange` and it becomes controlled — the table just shows the sort indicator and tells you when it changed, you bring the sorted data.
|
|
207
|
+
|
|
208
|
+
**Pagination** — set `pageSize` and the table slices the data automatically. For server-side pagination, also pass `totalRows` so it knows how many pages there are, and control `page` + `onPageChange` yourself. If you need both sort and page in one callback, use `onChange` instead.
|
|
209
|
+
|
|
210
|
+
**Other stuff** — `loading` replaces rows with skeleton cells while data is loading. `stickyHeader` keeps the header in view when the table scrolls. `caption` adds a proper `<caption>` for accessibility.
|
|
211
|
+
|
|
212
|
+
Color props: `borderColor`, `headerColor`, `rowColor`, `stripeColor`.
|
|
213
|
+
|
|
214
|
+
## DataTable
|
|
215
|
+
|
|
216
|
+
Editable table — good for things like spreadsheet-style input or inline CRUD. Each column can be editable or not, and you can mix text inputs with dropdowns.
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
const columns = [
|
|
220
|
+
{ key: "name", header: "Name", editable: true },
|
|
221
|
+
{ key: "qty", header: "Qty", editable: true, width: "80px" },
|
|
222
|
+
{
|
|
223
|
+
key: "status",
|
|
224
|
+
header: "Status",
|
|
225
|
+
editable: true,
|
|
226
|
+
options: [
|
|
227
|
+
{ value: "todo", label: "To do" },
|
|
228
|
+
{ value: "in_progress", label: "In progress" },
|
|
229
|
+
{ value: "done", label: "Done" },
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
<DataTable
|
|
235
|
+
columns={columns}
|
|
236
|
+
defaultData={[{ name: "Widget", qty: "1", status: "todo" }]}
|
|
237
|
+
onChange={(rows) => console.log(rows)}
|
|
238
|
+
deletable
|
|
239
|
+
addRowLabel="Add item"
|
|
240
|
+
/>;
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Editing** — click a text cell to start editing, Enter to confirm, Escape to cancel. For select cells (columns with `options`), one click opens the dropdown directly; picking an option saves immediately. Tab and Shift+Tab move between editable cells. Tab past the last cell adds a new row automatically.
|
|
244
|
+
|
|
245
|
+
**Select columns** — add `options: [{ value, label }]` to a column. The cell stores the `value` but displays the `label`. The column still needs `editable: true`.
|
|
246
|
+
|
|
247
|
+
**Controlled vs uncontrolled** — same pattern as the rest of the library. Pass `defaultData` and forget about it, or pass `data` + `onChange` if you need to keep the data in your own state.
|
|
248
|
+
|
|
249
|
+
**Per-cell editability** — `editable` can be a function `(row, rowIndex) => boolean` if you need some cells to be editable based on row content.
|
|
250
|
+
|
|
251
|
+
`deletable` adds a remove button per row. `newRowFactory` lets you control what an empty new row looks like (useful if you need generated IDs or default values).
|
|
252
|
+
|
|
253
|
+
Color props: `borderColor`, `headerColor`.
|
|
254
|
+
|
|
255
|
+
## useTable
|
|
256
|
+
|
|
257
|
+
Helper hook for when your table data comes from a server. It keeps track of the current sort and page so you can use them in a fetch call, and passes them back to `<Table>` as controlled props.
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
const { sort, page, onSortChange, onPageChange } = useTable({
|
|
261
|
+
defaultPage: 1,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
fetchProducts({ sort, page });
|
|
266
|
+
}, [sort, page]);
|
|
267
|
+
|
|
268
|
+
<Table
|
|
269
|
+
columns={columns}
|
|
270
|
+
data={serverData}
|
|
271
|
+
sort={sort}
|
|
272
|
+
onSortChange={onSortChange}
|
|
273
|
+
page={page}
|
|
274
|
+
onPageChange={onPageChange}
|
|
275
|
+
pageSize={20}
|
|
276
|
+
totalRows={totalCount}
|
|
277
|
+
/>;
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
When the user changes the sort column, the page resets to 1 automatically — that's usually what you want so you don't end up on page 5 of a different sort order. Pass `defaultSort` if you need a column sorted on first load.
|
|
281
|
+
|
|
182
282
|
## Design tokens
|
|
183
283
|
|
|
184
284
|
Colors, spacing, font sizes, and border radius live in `src/consts.ts`. All components pull from there, so changing a token updates everything at once.
|
|
@@ -9,5 +9,6 @@ export declare const MixedEditable: Story;
|
|
|
9
9
|
export declare const PerCellEditable: Story;
|
|
10
10
|
export declare const CustomColors: Story;
|
|
11
11
|
export declare const KeyboardNavigation: Story;
|
|
12
|
+
export declare const WithSelectColumn: Story;
|
|
12
13
|
export declare const StartsEmpty: Story;
|
|
13
14
|
export declare const Controlled: Story;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { TableSizes } from '../Table/Table.types';
|
|
3
3
|
export type { TableSizes };
|
|
4
|
+
export interface DataTableSelectOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
4
8
|
export interface DataTableColumn<T = Record<string, unknown>> {
|
|
5
9
|
key: keyof T & string;
|
|
6
10
|
header: string;
|
|
7
11
|
width?: string;
|
|
8
12
|
editable?: boolean | ((row: T, rowIndex: number) => boolean);
|
|
13
|
+
options?: DataTableSelectOption[];
|
|
9
14
|
render?: (value: unknown, row: T, rowIndex: number) => ReactNode;
|
|
10
15
|
}
|
|
11
16
|
export interface DataTableProps<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { DataTable } from './DataTable';
|
|
2
|
-
export type { DataTableProps, DataTableColumn } from './DataTable.types';
|
|
2
|
+
export type { DataTableProps, DataTableColumn, DataTableSelectOption, } from './DataTable.types';
|
|
@@ -4,22 +4,13 @@ declare const meta: Meta<typeof Table>;
|
|
|
4
4
|
export default meta;
|
|
5
5
|
type Story = StoryObj<typeof Table>;
|
|
6
6
|
export declare const Default: Story;
|
|
7
|
-
export declare const Striped: Story;
|
|
8
|
-
export declare const Bordered: Story;
|
|
9
7
|
export declare const StripedAndBordered: Story;
|
|
10
|
-
export declare const Small: Story;
|
|
11
|
-
export declare const Large: Story;
|
|
12
|
-
export declare const WithCaption: Story;
|
|
13
8
|
export declare const WithCustomRender: Story;
|
|
14
9
|
export declare const Sortable: Story;
|
|
15
10
|
export declare const SortableControlled: Story;
|
|
11
|
+
export declare const WithUseTable: Story;
|
|
16
12
|
export declare const Loading: Story;
|
|
17
13
|
export declare const Empty: Story;
|
|
18
14
|
export declare const Paginated: Story;
|
|
19
|
-
export declare const PaginatedSortable: Story;
|
|
20
15
|
export declare const StickyHeader: Story;
|
|
21
|
-
export declare const ColumnWidths: Story;
|
|
22
|
-
export declare const CustomBorderColor: Story;
|
|
23
|
-
export declare const CustomHeaderColor: Story;
|
|
24
|
-
export declare const CustomRowColors: Story;
|
|
25
16
|
export declare const FullyCustomized: Story;
|
|
@@ -27,7 +27,7 @@ export interface TableProps<T extends Record<string, unknown> = Record<string, u
|
|
|
27
27
|
caption?: string;
|
|
28
28
|
emptyMessage?: string;
|
|
29
29
|
loading?: boolean;
|
|
30
|
-
sort?: SortState;
|
|
30
|
+
sort?: SortState | null;
|
|
31
31
|
defaultSort?: SortState;
|
|
32
32
|
onSortChange?: (sort: SortState | null) => void;
|
|
33
33
|
pageSize?: number;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SortState } from './Table.types';
|
|
2
|
+
export interface UseTableOptions {
|
|
3
|
+
defaultSort?: SortState;
|
|
4
|
+
defaultPage?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface UseTableReturn {
|
|
7
|
+
sort: SortState | null;
|
|
8
|
+
page: number;
|
|
9
|
+
onSortChange: (sort: SortState | null) => void;
|
|
10
|
+
onPageChange: (page: number) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function useTable({ defaultSort, defaultPage, }?: UseTableOptions): UseTableReturn;
|