@roadlittledawn/docs-design-system-react 0.8.0 → 0.9.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/components/Table.d.ts +81 -0
- package/dist/components/Table.js +93 -0
- package/dist/components/Table.stories.d.ts +44 -0
- package/dist/components/Table.stories.js +258 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +188 -0
- package/package.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type SortDirection = 'asc' | 'desc' | null;
|
|
3
|
+
export interface TableProps {
|
|
4
|
+
/** Children — typically TableHead and TableBody */
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* Visual variant of the table.
|
|
8
|
+
* `"default"` renders all borders; `"borderless"` shows only row top/bottom borders.
|
|
9
|
+
*/
|
|
10
|
+
variant?: 'default' | 'borderless';
|
|
11
|
+
/**
|
|
12
|
+
* When true the thead sticks to the top of the scroll container while scrolling.
|
|
13
|
+
* Pair with the `style` prop (e.g. `style={{ maxHeight: '400px' }}`) to constrain
|
|
14
|
+
* the table height so that the header can stick.
|
|
15
|
+
*/
|
|
16
|
+
stickyHeader?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Background color applied to the header row.
|
|
19
|
+
* Accepts any valid CSS color value (e.g. `"#f0f4ff"`, `"var(--my-color)"`).
|
|
20
|
+
* Overrides the default token value.
|
|
21
|
+
*/
|
|
22
|
+
headerBg?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Callback fired when a sortable column header is clicked.
|
|
25
|
+
* Useful for server-side sorting. Receives the column key and new direction.
|
|
26
|
+
*/
|
|
27
|
+
onSort?: (key: string, direction: SortDirection) => void;
|
|
28
|
+
/** Additional CSS classes applied to the outer wrapper */
|
|
29
|
+
className?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Inline styles applied to the outer wrapper.
|
|
32
|
+
* Use `maxHeight` here to constrain the table height when `stickyHeader` is true.
|
|
33
|
+
*/
|
|
34
|
+
style?: React.CSSProperties;
|
|
35
|
+
}
|
|
36
|
+
export declare function Table({ children, variant, stickyHeader, headerBg, onSort, className, style, }: TableProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export interface TableHeadProps {
|
|
38
|
+
/** Header rows — typically one TableRow containing TableHeaderCells */
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
/** Additional CSS classes */
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function TableHead({ children, className }: TableHeadProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export interface TableBodyProps {
|
|
45
|
+
/** Table body rows */
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
/** Additional CSS classes */
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function TableBody({ children, className }: TableBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
export interface TableRowProps {
|
|
52
|
+
/** Cells in this row */
|
|
53
|
+
children: React.ReactNode;
|
|
54
|
+
/** Additional CSS classes */
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
export declare function TableRow({ children, className }: TableRowProps): import("react/jsx-runtime").JSX.Element;
|
|
58
|
+
export interface TableHeaderCellProps {
|
|
59
|
+
/** Cell content / column label */
|
|
60
|
+
children: React.ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Unique key used to identify this column when sorting.
|
|
63
|
+
* When provided the column becomes sortable.
|
|
64
|
+
*/
|
|
65
|
+
sortKey?: string;
|
|
66
|
+
/** Text alignment of the column */
|
|
67
|
+
align?: 'left' | 'center' | 'right';
|
|
68
|
+
/** Additional CSS classes */
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
export declare function TableHeaderCell({ children, sortKey, align, className, }: TableHeaderCellProps): import("react/jsx-runtime").JSX.Element;
|
|
72
|
+
export interface TableCellProps {
|
|
73
|
+
/** Cell content */
|
|
74
|
+
children?: React.ReactNode;
|
|
75
|
+
/** Text alignment */
|
|
76
|
+
align?: 'left' | 'center' | 'right';
|
|
77
|
+
/** Additional CSS classes */
|
|
78
|
+
className?: string;
|
|
79
|
+
}
|
|
80
|
+
export declare function TableCell({ children, align, className }: TableCellProps): import("react/jsx-runtime").JSX.Element;
|
|
81
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, createContext, useContext } from 'react';
|
|
4
|
+
var TableContext = createContext(null);
|
|
5
|
+
function useTableContext() {
|
|
6
|
+
var ctx = useContext(TableContext);
|
|
7
|
+
if (!ctx) {
|
|
8
|
+
throw new Error('Table sub-components must be used within a Table component');
|
|
9
|
+
}
|
|
10
|
+
return ctx;
|
|
11
|
+
}
|
|
12
|
+
export function Table(_a) {
|
|
13
|
+
var children = _a.children, _b = _a.variant, variant = _b === void 0 ? 'default' : _b, _c = _a.stickyHeader, stickyHeader = _c === void 0 ? false : _c, headerBg = _a.headerBg, onSort = _a.onSort, _d = _a.className, className = _d === void 0 ? '' : _d, style = _a.style;
|
|
14
|
+
var _e = useState(null), sortKey = _e[0], setSortKey = _e[1];
|
|
15
|
+
var _f = useState(null), sortDirection = _f[0], setSortDirection = _f[1];
|
|
16
|
+
var handleSort = function (key) {
|
|
17
|
+
var nextDirection;
|
|
18
|
+
if (sortKey === key) {
|
|
19
|
+
nextDirection = sortDirection === 'asc' ? 'desc' : sortDirection === 'desc' ? null : 'asc';
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
nextDirection = 'asc';
|
|
23
|
+
}
|
|
24
|
+
setSortKey(nextDirection === null ? null : key);
|
|
25
|
+
setSortDirection(nextDirection);
|
|
26
|
+
onSort === null || onSort === void 0 ? void 0 : onSort(key, nextDirection);
|
|
27
|
+
};
|
|
28
|
+
var wrapperClasses = [
|
|
29
|
+
'dds-table-wrapper',
|
|
30
|
+
stickyHeader ? 'dds-table-scrollable' : '',
|
|
31
|
+
variant === 'borderless' ? 'dds-table-borderless' : '',
|
|
32
|
+
className,
|
|
33
|
+
]
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.join(' ');
|
|
36
|
+
return (_jsx(TableContext.Provider, { value: { sortKey: sortKey, sortDirection: sortDirection, onSort: handleSort, stickyHeader: stickyHeader, variant: variant, headerBg: headerBg }, children: _jsx("div", { className: wrapperClasses, style: style, children: _jsx("table", { className: "dds-table", children: children }) }) }));
|
|
37
|
+
}
|
|
38
|
+
export function TableHead(_a) {
|
|
39
|
+
var children = _a.children, _b = _a.className, className = _b === void 0 ? '' : _b;
|
|
40
|
+
var _c = useTableContext(), stickyHeader = _c.stickyHeader, headerBg = _c.headerBg;
|
|
41
|
+
var classes = ['dds-table-head', stickyHeader ? 'dds-table-head-sticky' : '', className]
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.join(' ');
|
|
44
|
+
var style = headerBg ? { backgroundColor: headerBg } : {};
|
|
45
|
+
return (_jsx("thead", { className: classes, style: style, children: children }));
|
|
46
|
+
}
|
|
47
|
+
export function TableBody(_a) {
|
|
48
|
+
var children = _a.children, _b = _a.className, className = _b === void 0 ? '' : _b;
|
|
49
|
+
return _jsx("tbody", { className: ['dds-table-body', className].filter(Boolean).join(' '), children: children });
|
|
50
|
+
}
|
|
51
|
+
export function TableRow(_a) {
|
|
52
|
+
var children = _a.children, _b = _a.className, className = _b === void 0 ? '' : _b;
|
|
53
|
+
return _jsx("tr", { className: ['dds-table-row', className].filter(Boolean).join(' '), children: children });
|
|
54
|
+
}
|
|
55
|
+
export function TableHeaderCell(_a) {
|
|
56
|
+
var children = _a.children, sortKey = _a.sortKey, _b = _a.align, align = _b === void 0 ? 'left' : _b, _c = _a.className, className = _c === void 0 ? '' : _c;
|
|
57
|
+
var _d = useTableContext(), activeSortKey = _d.sortKey, sortDirection = _d.sortDirection, onSort = _d.onSort;
|
|
58
|
+
var isSortable = Boolean(sortKey);
|
|
59
|
+
var isActive = isSortable && activeSortKey === sortKey;
|
|
60
|
+
var classes = [
|
|
61
|
+
'dds-table-th',
|
|
62
|
+
isSortable ? 'dds-table-th-sortable' : '',
|
|
63
|
+
isActive ? 'dds-table-th-active' : '',
|
|
64
|
+
"dds-table-align-".concat(align),
|
|
65
|
+
className,
|
|
66
|
+
]
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.join(' ');
|
|
69
|
+
var handleClick = function () {
|
|
70
|
+
if (sortKey) {
|
|
71
|
+
onSort(sortKey);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var handleKeyDown = function (e) {
|
|
75
|
+
if (isSortable && (e.key === 'Enter' || e.key === ' ')) {
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
handleClick();
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var ariaSort = isActive
|
|
81
|
+
? sortDirection === 'asc'
|
|
82
|
+
? 'ascending'
|
|
83
|
+
: sortDirection === 'desc'
|
|
84
|
+
? 'descending'
|
|
85
|
+
: 'none'
|
|
86
|
+
: 'none';
|
|
87
|
+
return (_jsx("th", { className: classes, scope: "col", "aria-sort": isSortable ? ariaSort : undefined, onClick: isSortable ? handleClick : undefined, onKeyDown: isSortable ? handleKeyDown : undefined, tabIndex: isSortable ? 0 : undefined, children: _jsxs("span", { className: "dds-table-th-content", children: [children, isSortable && (_jsx("span", { className: "dds-table-sort-icon", "aria-hidden": "true", children: isActive && sortDirection === 'asc' ? '↑' : isActive && sortDirection === 'desc' ? '↓' : '↕' }))] }) }));
|
|
88
|
+
}
|
|
89
|
+
export function TableCell(_a) {
|
|
90
|
+
var children = _a.children, _b = _a.align, align = _b === void 0 ? 'left' : _b, _c = _a.className, className = _c === void 0 ? '' : _c;
|
|
91
|
+
var classes = ['dds-table-td', "dds-table-align-".concat(align), className].filter(Boolean).join(' ');
|
|
92
|
+
return _jsx("td", { className: classes, children: children });
|
|
93
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Table } from "./Table";
|
|
3
|
+
/**
|
|
4
|
+
* Table displays structured data in rows and columns. It supports sortable
|
|
5
|
+
* columns, a sticky header, a borderless variant, and responsive horizontal
|
|
6
|
+
* scrolling for mobile viewports.
|
|
7
|
+
*/
|
|
8
|
+
declare const meta: Meta<typeof Table>;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof Table>;
|
|
11
|
+
/**
|
|
12
|
+
* A basic table with all borders (the default variant).
|
|
13
|
+
*/
|
|
14
|
+
export declare const Default: Story;
|
|
15
|
+
/**
|
|
16
|
+
* Borderless variant — only row dividers are shown; no outer or column borders.
|
|
17
|
+
* Common in modern documentation sites.
|
|
18
|
+
*/
|
|
19
|
+
export declare const Borderless: Story;
|
|
20
|
+
/**
|
|
21
|
+
* Sortable columns — clicking a column header sorts the table ascending then
|
|
22
|
+
* descending, and a third click resets sort order.
|
|
23
|
+
*/
|
|
24
|
+
export declare const Sortable: Story;
|
|
25
|
+
/**
|
|
26
|
+
* Sticky header — the thead stays fixed at the top of the scroll container as
|
|
27
|
+
* the user scrolls through a long table. Use `style={{ maxHeight: '...' }}` to
|
|
28
|
+
* constrain the table height so the header can stick.
|
|
29
|
+
*/
|
|
30
|
+
export declare const StickyHeader: Story;
|
|
31
|
+
/**
|
|
32
|
+
* A custom header background color applied via the `headerBg` prop.
|
|
33
|
+
*/
|
|
34
|
+
export declare const CustomHeaderBg: Story;
|
|
35
|
+
/**
|
|
36
|
+
* Column cells can be aligned left (default), center, or right using the
|
|
37
|
+
* `align` prop on `TableHeaderCell` and `TableCell`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const ColumnAlignment: Story;
|
|
40
|
+
/**
|
|
41
|
+
* A typical API-reference table for documenting component props or
|
|
42
|
+
* configuration options.
|
|
43
|
+
*/
|
|
44
|
+
export declare const ApiReference: Story;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
13
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
14
|
+
if (ar || !(i in from)) {
|
|
15
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
16
|
+
ar[i] = from[i];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
20
|
+
};
|
|
21
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
+
import { useState } from "react";
|
|
23
|
+
import { Table, TableHead, TableBody, TableRow, TableHeaderCell, TableCell, } from "./Table";
|
|
24
|
+
/**
|
|
25
|
+
* Table displays structured data in rows and columns. It supports sortable
|
|
26
|
+
* columns, a sticky header, a borderless variant, and responsive horizontal
|
|
27
|
+
* scrolling for mobile viewports.
|
|
28
|
+
*/
|
|
29
|
+
var meta = {
|
|
30
|
+
title: "Components/Table",
|
|
31
|
+
component: Table,
|
|
32
|
+
tags: ["autodocs"],
|
|
33
|
+
argTypes: {
|
|
34
|
+
variant: {
|
|
35
|
+
control: "radio",
|
|
36
|
+
options: ["default", "borderless"],
|
|
37
|
+
description: '`"default"` renders all borders; `"borderless"` shows only row top/bottom borders.',
|
|
38
|
+
table: { defaultValue: { summary: '"default"' } },
|
|
39
|
+
},
|
|
40
|
+
stickyHeader: {
|
|
41
|
+
control: "boolean",
|
|
42
|
+
description: "When true the thead sticks to the top of the viewport while scrolling.",
|
|
43
|
+
table: { defaultValue: { summary: "false" } },
|
|
44
|
+
},
|
|
45
|
+
headerBg: {
|
|
46
|
+
control: "color",
|
|
47
|
+
description: "Background color applied to the header row. Accepts any valid CSS color value.",
|
|
48
|
+
},
|
|
49
|
+
onSort: {
|
|
50
|
+
control: false,
|
|
51
|
+
description: "Callback fired when a sortable column header is clicked. Useful for server-side sorting.",
|
|
52
|
+
},
|
|
53
|
+
children: {
|
|
54
|
+
control: false,
|
|
55
|
+
description: "Table content — typically `TableHead` and `TableBody`.",
|
|
56
|
+
},
|
|
57
|
+
className: {
|
|
58
|
+
control: "text",
|
|
59
|
+
description: "Additional CSS classes applied to the outer wrapper.",
|
|
60
|
+
table: { defaultValue: { summary: '""' } },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
parameters: {
|
|
64
|
+
docs: {
|
|
65
|
+
description: {
|
|
66
|
+
component: "\nTable displays structured, relational data in rows and columns for technical documentation pages.\n\n## When to Use\n\n- Displaying configuration options, API parameters, or reference data\n- Comparing multiple items across the same set of attributes\n- Presenting tabular data that users may want to sort or scan quickly\n\n## When Not to Use\n\n- For layout purposes \u2014 use CSS Grid or Flexbox instead\n- When data has fewer than two columns (use a list instead)\n- When rows have vastly different data shapes\n\n## Accessibility\n\n- `<th>` elements have `scope=\"col\"` for screen readers\n- Sortable headers expose `aria-sort` (`ascending`, `descending`, or `none`)\n- Sortable headers are focusable via keyboard and respond to Enter/Space\n ",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
export default meta;
|
|
72
|
+
var employees = [
|
|
73
|
+
{ name: "Alice Johnson", role: "Engineer", department: "Platform", status: "Active" },
|
|
74
|
+
{ name: "Bob Smith", role: "Designer", department: "UX", status: "Active" },
|
|
75
|
+
{ name: "Carol White", role: "Manager", department: "Platform", status: "On Leave" },
|
|
76
|
+
{ name: "Dan Brown", role: "Engineer", department: "Frontend", status: "Active" },
|
|
77
|
+
{ name: "Eve Davis", role: "Analyst", department: "Data", status: "Inactive" },
|
|
78
|
+
];
|
|
79
|
+
// -----------------------------------------------------------------------
|
|
80
|
+
// Default
|
|
81
|
+
// -----------------------------------------------------------------------
|
|
82
|
+
/**
|
|
83
|
+
* A basic table with all borders (the default variant).
|
|
84
|
+
*/
|
|
85
|
+
export var Default = {
|
|
86
|
+
args: {
|
|
87
|
+
variant: "default",
|
|
88
|
+
stickyHeader: false,
|
|
89
|
+
},
|
|
90
|
+
parameters: {
|
|
91
|
+
docs: {
|
|
92
|
+
source: {
|
|
93
|
+
code: "<Table>\n <TableHead>\n <TableRow>\n <TableHeaderCell>Name</TableHeaderCell>\n <TableHeaderCell>Role</TableHeaderCell>\n <TableHeaderCell>Department</TableHeaderCell>\n <TableHeaderCell>Status</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n <TableRow>\n <TableCell>Alice Johnson</TableCell>\n <TableCell>Engineer</TableCell>\n <TableCell>Platform</TableCell>\n <TableCell>Active</TableCell>\n </TableRow>\n </TableBody>\n</Table>",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
render: function (args) { return (_jsxs(Table, __assign({}, args, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { children: "Name" }), _jsx(TableHeaderCell, { children: "Role" }), _jsx(TableHeaderCell, { children: "Department" }), _jsx(TableHeaderCell, { children: "Status" })] }) }), _jsx(TableBody, { children: employees.map(function (e) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: e.name }), _jsx(TableCell, { children: e.role }), _jsx(TableCell, { children: e.department }), _jsx(TableCell, { children: e.status })] }, e.name)); }) })] }))); },
|
|
98
|
+
};
|
|
99
|
+
// -----------------------------------------------------------------------
|
|
100
|
+
// Borderless
|
|
101
|
+
// -----------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Borderless variant — only row dividers are shown; no outer or column borders.
|
|
104
|
+
* Common in modern documentation sites.
|
|
105
|
+
*/
|
|
106
|
+
export var Borderless = {
|
|
107
|
+
args: {
|
|
108
|
+
variant: "borderless",
|
|
109
|
+
},
|
|
110
|
+
parameters: {
|
|
111
|
+
docs: {
|
|
112
|
+
source: {
|
|
113
|
+
code: "<Table variant=\"borderless\">\n <TableHead>\n <TableRow>\n <TableHeaderCell>Name</TableHeaderCell>\n <TableHeaderCell>Role</TableHeaderCell>\n <TableHeaderCell>Department</TableHeaderCell>\n <TableHeaderCell>Status</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {/* rows */}\n </TableBody>\n</Table>",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
render: function (args) { return (_jsxs(Table, __assign({}, args, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { children: "Name" }), _jsx(TableHeaderCell, { children: "Role" }), _jsx(TableHeaderCell, { children: "Department" }), _jsx(TableHeaderCell, { children: "Status" })] }) }), _jsx(TableBody, { children: employees.map(function (e) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: e.name }), _jsx(TableCell, { children: e.role }), _jsx(TableCell, { children: e.department }), _jsx(TableCell, { children: e.status })] }, e.name)); }) })] }))); },
|
|
118
|
+
};
|
|
119
|
+
// -----------------------------------------------------------------------
|
|
120
|
+
// Sortable (client-side)
|
|
121
|
+
// -----------------------------------------------------------------------
|
|
122
|
+
/**
|
|
123
|
+
* Sortable columns — clicking a column header sorts the table ascending then
|
|
124
|
+
* descending, and a third click resets sort order.
|
|
125
|
+
*/
|
|
126
|
+
export var Sortable = {
|
|
127
|
+
parameters: {
|
|
128
|
+
docs: {
|
|
129
|
+
source: {
|
|
130
|
+
code: "function SortableExample() {\n const [rows, setRows] = React.useState(data);\n\n const handleSort = (key, direction) => {\n if (!direction) {\n setRows(data);\n return;\n }\n const sorted = [...rows].sort((a, b) => {\n const cmp = a[key].localeCompare(b[key]);\n return direction === 'asc' ? cmp : -cmp;\n });\n setRows(sorted);\n };\n\n return (\n <Table onSort={handleSort}>\n <TableHead>\n <TableRow>\n <TableHeaderCell sortKey=\"name\">Name</TableHeaderCell>\n <TableHeaderCell sortKey=\"role\">Role</TableHeaderCell>\n <TableHeaderCell sortKey=\"department\">Department</TableHeaderCell>\n <TableHeaderCell sortKey=\"status\">Status</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {rows.map((e) => (\n <TableRow key={e.name}>\n <TableCell>{e.name}</TableCell>\n <TableCell>{e.role}</TableCell>\n <TableCell>{e.department}</TableCell>\n <TableCell>{e.status}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n );\n}",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
render: function SortableExample() {
|
|
135
|
+
var _a = useState(employees), rows = _a[0], setRows = _a[1];
|
|
136
|
+
var handleSort = function (key, direction) {
|
|
137
|
+
if (!direction) {
|
|
138
|
+
setRows(employees);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
var sorted = __spreadArray([], rows, true).sort(function (a, b) {
|
|
142
|
+
var aVal = a[key];
|
|
143
|
+
var bVal = b[key];
|
|
144
|
+
var cmp = aVal.localeCompare(bVal);
|
|
145
|
+
return direction === "asc" ? cmp : -cmp;
|
|
146
|
+
});
|
|
147
|
+
setRows(sorted);
|
|
148
|
+
};
|
|
149
|
+
return (_jsxs(Table, { onSort: handleSort, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { sortKey: "name", children: "Name" }), _jsx(TableHeaderCell, { sortKey: "role", children: "Role" }), _jsx(TableHeaderCell, { sortKey: "department", children: "Department" }), _jsx(TableHeaderCell, { sortKey: "status", children: "Status" })] }) }), _jsx(TableBody, { children: rows.map(function (e) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: e.name }), _jsx(TableCell, { children: e.role }), _jsx(TableCell, { children: e.department }), _jsx(TableCell, { children: e.status })] }, e.name)); }) })] }));
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
// -----------------------------------------------------------------------
|
|
153
|
+
// Sticky Header
|
|
154
|
+
// -----------------------------------------------------------------------
|
|
155
|
+
/**
|
|
156
|
+
* Sticky header — the thead stays fixed at the top of the scroll container as
|
|
157
|
+
* the user scrolls through a long table. Use `style={{ maxHeight: '...' }}` to
|
|
158
|
+
* constrain the table height so the header can stick.
|
|
159
|
+
*/
|
|
160
|
+
export var StickyHeader = {
|
|
161
|
+
args: {
|
|
162
|
+
stickyHeader: true,
|
|
163
|
+
},
|
|
164
|
+
parameters: {
|
|
165
|
+
docs: {
|
|
166
|
+
source: {
|
|
167
|
+
code: "<Table stickyHeader style={{ maxHeight: '300px' }}>\n <TableHead>\n <TableRow>\n <TableHeaderCell>#</TableHeaderCell>\n <TableHeaderCell>Name</TableHeaderCell>\n <TableHeaderCell>Role</TableHeaderCell>\n <TableHeaderCell>Department</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {/* many rows */}\n </TableBody>\n</Table>",
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
render: function (args) {
|
|
172
|
+
var manyRows = Array.from({ length: 20 }, function (_, i) { return (__assign(__assign({}, employees[i % employees.length]), { name: "".concat(employees[i % employees.length].name, " ").concat(i + 1) })); });
|
|
173
|
+
return (_jsxs(Table, __assign({}, args, { style: { maxHeight: "300px" }, children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { children: "#" }), _jsx(TableHeaderCell, { children: "Name" }), _jsx(TableHeaderCell, { children: "Role" }), _jsx(TableHeaderCell, { children: "Department" })] }) }), _jsx(TableBody, { children: manyRows.map(function (e, i) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: i + 1 }), _jsx(TableCell, { children: e.name }), _jsx(TableCell, { children: e.role }), _jsx(TableCell, { children: e.department })] }, i)); }) })] })));
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
// -----------------------------------------------------------------------
|
|
177
|
+
// Custom Header Background
|
|
178
|
+
// -----------------------------------------------------------------------
|
|
179
|
+
/**
|
|
180
|
+
* A custom header background color applied via the `headerBg` prop.
|
|
181
|
+
*/
|
|
182
|
+
export var CustomHeaderBg = {
|
|
183
|
+
args: {
|
|
184
|
+
headerBg: "#dbeafe",
|
|
185
|
+
},
|
|
186
|
+
parameters: {
|
|
187
|
+
docs: {
|
|
188
|
+
source: {
|
|
189
|
+
code: "<Table headerBg=\"#dbeafe\">\n <TableHead>\n <TableRow>\n <TableHeaderCell>Name</TableHeaderCell>\n <TableHeaderCell>Role</TableHeaderCell>\n <TableHeaderCell>Department</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {/* rows */}\n </TableBody>\n</Table>",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
render: function (args) { return (_jsxs(Table, __assign({}, args, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { children: "Name" }), _jsx(TableHeaderCell, { children: "Role" }), _jsx(TableHeaderCell, { children: "Department" }), _jsx(TableHeaderCell, { children: "Status" })] }) }), _jsx(TableBody, { children: employees.map(function (e) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: e.name }), _jsx(TableCell, { children: e.role }), _jsx(TableCell, { children: e.department }), _jsx(TableCell, { children: e.status })] }, e.name)); }) })] }))); },
|
|
194
|
+
};
|
|
195
|
+
// -----------------------------------------------------------------------
|
|
196
|
+
// Column Alignment
|
|
197
|
+
// -----------------------------------------------------------------------
|
|
198
|
+
/**
|
|
199
|
+
* Column cells can be aligned left (default), center, or right using the
|
|
200
|
+
* `align` prop on `TableHeaderCell` and `TableCell`.
|
|
201
|
+
*/
|
|
202
|
+
export var ColumnAlignment = {
|
|
203
|
+
parameters: {
|
|
204
|
+
docs: {
|
|
205
|
+
source: {
|
|
206
|
+
code: "<Table>\n <TableHead>\n <TableRow>\n <TableHeaderCell align=\"left\">Name</TableHeaderCell>\n <TableHeaderCell align=\"center\">Version</TableHeaderCell>\n <TableHeaderCell align=\"right\">Downloads</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n <TableRow>\n <TableCell align=\"left\">react</TableCell>\n <TableCell align=\"center\">18.3.0</TableCell>\n <TableCell align=\"right\">24,000,000</TableCell>\n </TableRow>\n </TableBody>\n</Table>",
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
render: function () { return (_jsxs(Table, { children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { align: "left", children: "Package" }), _jsx(TableHeaderCell, { align: "center", children: "Version" }), _jsx(TableHeaderCell, { align: "right", children: "Weekly Downloads" })] }) }), _jsx(TableBody, { children: [
|
|
211
|
+
{ name: "react", version: "18.3.0", downloads: "24,000,000" },
|
|
212
|
+
{ name: "typescript", version: "5.4.5", downloads: "58,000,000" },
|
|
213
|
+
{ name: "vite", version: "5.2.11", downloads: "9,800,000" },
|
|
214
|
+
{ name: "tailwindcss", version: "3.4.4", downloads: "11,200,000" },
|
|
215
|
+
].map(function (pkg) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { align: "left", children: pkg.name }), _jsx(TableCell, { align: "center", children: pkg.version }), _jsx(TableCell, { align: "right", children: pkg.downloads })] }, pkg.name)); }) })] })); },
|
|
216
|
+
};
|
|
217
|
+
// -----------------------------------------------------------------------
|
|
218
|
+
// API Reference (documentation use-case)
|
|
219
|
+
// -----------------------------------------------------------------------
|
|
220
|
+
/**
|
|
221
|
+
* A typical API-reference table for documenting component props or
|
|
222
|
+
* configuration options.
|
|
223
|
+
*/
|
|
224
|
+
export var ApiReference = {
|
|
225
|
+
parameters: {
|
|
226
|
+
docs: {
|
|
227
|
+
source: {
|
|
228
|
+
code: "<Table variant=\"borderless\">\n <TableHead>\n <TableRow>\n <TableHeaderCell>Prop</TableHeaderCell>\n <TableHeaderCell>Type</TableHeaderCell>\n <TableHeaderCell>Default</TableHeaderCell>\n <TableHeaderCell>Description</TableHeaderCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {/* prop rows */}\n </TableBody>\n</Table>",
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
render: function () { return (_jsxs(Table, { variant: "borderless", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableHeaderCell, { children: "Prop" }), _jsx(TableHeaderCell, { children: "Type" }), _jsx(TableHeaderCell, { children: "Default" }), _jsx(TableHeaderCell, { children: "Description" })] }) }), _jsx(TableBody, { children: [
|
|
233
|
+
{
|
|
234
|
+
prop: "variant",
|
|
235
|
+
type: '"default" | "borderless"',
|
|
236
|
+
defaultVal: '"default"',
|
|
237
|
+
desc: "Visual style of the table.",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
prop: "stickyHeader",
|
|
241
|
+
type: "boolean",
|
|
242
|
+
defaultVal: "false",
|
|
243
|
+
desc: "Pins the header row to the top of the viewport while scrolling.",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
prop: "headerBg",
|
|
247
|
+
type: "string",
|
|
248
|
+
defaultVal: "—",
|
|
249
|
+
desc: "CSS color applied to the header background.",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
prop: "onSort",
|
|
253
|
+
type: "(key, direction) => void",
|
|
254
|
+
defaultVal: "—",
|
|
255
|
+
desc: "Callback for server-side sorting.",
|
|
256
|
+
},
|
|
257
|
+
].map(function (row) { return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx("code", { children: row.prop }) }), _jsx(TableCell, { children: _jsx("code", { children: row.type }) }), _jsx(TableCell, { children: _jsx("code", { children: row.defaultVal }) }), _jsx(TableCell, { children: row.desc })] }, row.prop)); }) })] })); },
|
|
258
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,6 @@ export * from './components/Typography';
|
|
|
11
11
|
export * from './components/Heading';
|
|
12
12
|
export * from './components/Link';
|
|
13
13
|
export * from './components/List';
|
|
14
|
+
export * from './components/Table';
|
|
14
15
|
export * from './components/Grid';
|
|
15
16
|
export * from './hooks/useKeyPress';
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export * from './components/Typography';
|
|
|
12
12
|
export * from './components/Heading';
|
|
13
13
|
export * from './components/Link';
|
|
14
14
|
export * from './components/List';
|
|
15
|
+
export * from './components/Table';
|
|
15
16
|
export * from './components/Grid';
|
|
16
17
|
// Export hooks
|
|
17
18
|
export * from './hooks/useKeyPress';
|
package/dist/styles.css
CHANGED
|
@@ -259,6 +259,27 @@
|
|
|
259
259
|
--dds-list-connector-line: #eceef2; /* gray-200 */
|
|
260
260
|
--dds-list-text: #374151; /* gray-700 */
|
|
261
261
|
|
|
262
|
+
/* Table */
|
|
263
|
+
--dds-table-margin: 1rem 0;
|
|
264
|
+
--dds-table-radius: 0.5rem; /* rounded-lg */
|
|
265
|
+
--dds-table-font-size: 0.875rem; /* text-sm */
|
|
266
|
+
--dds-table-bg: transparent;
|
|
267
|
+
--dds-table-text: #374151; /* gray-700 */
|
|
268
|
+
--dds-table-border: #e5e7eb; /* gray-200 */
|
|
269
|
+
--dds-table-row-border: #e5e7eb; /* gray-200 */
|
|
270
|
+
--dds-table-row-hover-bg: #f9fafb; /* gray-50 */
|
|
271
|
+
--dds-table-header-bg: #f3f4f6; /* gray-100 */
|
|
272
|
+
--dds-table-sticky-bg: var(--dds-table-header-bg); /* used as sticky header background; should be opaque */
|
|
273
|
+
--dds-table-sticky-hover-bg: var(--dds-table-header-hover-bg); /* used as sticky sortable header hover; should be opaque */
|
|
274
|
+
--dds-table-header-text: #111827; /* gray-900 */
|
|
275
|
+
--dds-table-header-font-size: 0.8125rem; /* ~13px */
|
|
276
|
+
--dds-table-header-border: #d1d5db; /* gray-300 */
|
|
277
|
+
--dds-table-header-hover-bg: #e5e7eb; /* gray-200 */
|
|
278
|
+
--dds-table-header-hover-text: #111827; /* gray-900 */
|
|
279
|
+
--dds-table-header-active-text: #1d4ed8; /* blue-700 */
|
|
280
|
+
--dds-table-cell-padding: 0.75rem 1rem;
|
|
281
|
+
--dds-table-focus-ring: #3b82f6; /* blue-500 */
|
|
282
|
+
|
|
262
283
|
/* Grid */
|
|
263
284
|
--dds-grid-gap-sm: 1rem; /* gap-4 */
|
|
264
285
|
--dds-grid-gap-md: 1.5rem; /* gap-6 */
|
|
@@ -427,6 +448,22 @@
|
|
|
427
448
|
--dds-list-connector-line: #353a42; /* gray-600 */
|
|
428
449
|
--dds-list-text: #e5e7eb; /* gray-200 */
|
|
429
450
|
|
|
451
|
+
/* Table */
|
|
452
|
+
--dds-table-bg: transparent;
|
|
453
|
+
--dds-table-text: #d1d5db; /* gray-300 */
|
|
454
|
+
--dds-table-border: #4b5563; /* gray-600 */
|
|
455
|
+
--dds-table-row-border: #374151; /* gray-700 */
|
|
456
|
+
--dds-table-row-hover-bg: rgba(255, 255, 255, 0.04);
|
|
457
|
+
--dds-table-header-bg: rgba(255, 255, 255, 0.06);
|
|
458
|
+
--dds-table-sticky-bg: #1f2937; /* gray-800 — opaque fallback for sticky header */
|
|
459
|
+
--dds-table-sticky-hover-bg: #263347; /* slightly lighter opaque hover for sticky header */
|
|
460
|
+
--dds-table-header-text: #f9fafb; /* gray-50 */
|
|
461
|
+
--dds-table-header-border: #4b5563; /* gray-600 */
|
|
462
|
+
--dds-table-header-hover-bg: rgba(255, 255, 255, 0.1);
|
|
463
|
+
--dds-table-header-hover-text: #f9fafb; /* gray-50 */
|
|
464
|
+
--dds-table-header-active-text: #93c5fd; /* blue-300 */
|
|
465
|
+
--dds-table-focus-ring: #60a5fa; /* blue-400 */
|
|
466
|
+
|
|
430
467
|
/* Grid */
|
|
431
468
|
--dds-grid-divider-color: #4b5563; /* gray-600 */
|
|
432
469
|
}
|
|
@@ -586,6 +623,22 @@
|
|
|
586
623
|
--dds-list-connector-line: #353a42; /* gray-600 */
|
|
587
624
|
--dds-list-text: #e5e7eb; /* gray-200 */
|
|
588
625
|
|
|
626
|
+
/* Table */
|
|
627
|
+
--dds-table-bg: transparent;
|
|
628
|
+
--dds-table-text: #d1d5db;
|
|
629
|
+
--dds-table-border: #4b5563;
|
|
630
|
+
--dds-table-row-border: #374151;
|
|
631
|
+
--dds-table-row-hover-bg: rgba(255, 255, 255, 0.04);
|
|
632
|
+
--dds-table-header-bg: rgba(255, 255, 255, 0.06);
|
|
633
|
+
--dds-table-sticky-bg: #1f2937;
|
|
634
|
+
--dds-table-sticky-hover-bg: #263347;
|
|
635
|
+
--dds-table-header-text: #f9fafb;
|
|
636
|
+
--dds-table-header-border: #4b5563;
|
|
637
|
+
--dds-table-header-hover-bg: rgba(255, 255, 255, 0.1);
|
|
638
|
+
--dds-table-header-hover-text: #f9fafb;
|
|
639
|
+
--dds-table-header-active-text: #93c5fd;
|
|
640
|
+
--dds-table-focus-ring: #60a5fa;
|
|
641
|
+
|
|
589
642
|
/* Grid */
|
|
590
643
|
--dds-grid-divider-color: #4b5563; /* gray-600 */
|
|
591
644
|
}
|
|
@@ -726,6 +779,22 @@
|
|
|
726
779
|
--dds-popover-eyebrow-color: #9ca3af;
|
|
727
780
|
--dds-popover-link-color: #60a5fa;
|
|
728
781
|
--dds-popover-link-color-hover: #93c5fd;
|
|
782
|
+
|
|
783
|
+
/* Table */
|
|
784
|
+
--dds-table-bg: transparent;
|
|
785
|
+
--dds-table-text: #d1d5db;
|
|
786
|
+
--dds-table-border: #4b5563;
|
|
787
|
+
--dds-table-row-border: #374151;
|
|
788
|
+
--dds-table-row-hover-bg: rgba(255, 255, 255, 0.04);
|
|
789
|
+
--dds-table-header-bg: rgba(255, 255, 255, 0.06);
|
|
790
|
+
--dds-table-sticky-bg: #1f2937;
|
|
791
|
+
--dds-table-sticky-hover-bg: #263347;
|
|
792
|
+
--dds-table-header-text: #f9fafb;
|
|
793
|
+
--dds-table-header-border: #4b5563;
|
|
794
|
+
--dds-table-header-hover-bg: rgba(255, 255, 255, 0.1);
|
|
795
|
+
--dds-table-header-hover-text: #f9fafb;
|
|
796
|
+
--dds-table-header-active-text: #93c5fd;
|
|
797
|
+
--dds-table-focus-ring: #60a5fa;
|
|
729
798
|
}
|
|
730
799
|
/* Import PrismJS theme */
|
|
731
800
|
/**
|
|
@@ -1845,6 +1914,125 @@ a.no-text-decoration {
|
|
|
1845
1914
|
}
|
|
1846
1915
|
}
|
|
1847
1916
|
}
|
|
1917
|
+
/* Table wrapper — enables responsive horizontal scroll */
|
|
1918
|
+
.dds-table-wrapper {
|
|
1919
|
+
width: 100%;
|
|
1920
|
+
overflow-x: auto;
|
|
1921
|
+
-webkit-overflow-scrolling: touch;
|
|
1922
|
+
border: 1px solid var(--dds-table-border);
|
|
1923
|
+
border-radius: var(--dds-table-radius);
|
|
1924
|
+
margin: var(--dds-table-margin);
|
|
1925
|
+
}
|
|
1926
|
+
/* When stickyHeader is true the wrapper also scrolls vertically so that
|
|
1927
|
+
position:sticky on th elements activates within the same scroll container. */
|
|
1928
|
+
.dds-table-scrollable {
|
|
1929
|
+
overflow-y: auto;
|
|
1930
|
+
}
|
|
1931
|
+
/* Remove outer border for borderless variant — only row borders remain */
|
|
1932
|
+
.dds-table-borderless {
|
|
1933
|
+
border: none;
|
|
1934
|
+
border-radius: 0;
|
|
1935
|
+
}
|
|
1936
|
+
.dds-table {
|
|
1937
|
+
width: 100%;
|
|
1938
|
+
border-collapse: collapse;
|
|
1939
|
+
font-size: var(--dds-table-font-size);
|
|
1940
|
+
color: var(--dds-table-text);
|
|
1941
|
+
background-color: var(--dds-table-bg);
|
|
1942
|
+
}
|
|
1943
|
+
/* -----------------------------------------------------------------------
|
|
1944
|
+
Header
|
|
1945
|
+
----------------------------------------------------------------------- */
|
|
1946
|
+
.dds-table-head {
|
|
1947
|
+
background-color: var(--dds-table-header-bg);
|
|
1948
|
+
}
|
|
1949
|
+
.dds-table-head-sticky th {
|
|
1950
|
+
position: sticky;
|
|
1951
|
+
top: 0;
|
|
1952
|
+
z-index: 2;
|
|
1953
|
+
background-color: var(--dds-table-sticky-bg, var(--dds-table-header-bg));
|
|
1954
|
+
}
|
|
1955
|
+
/* When headerBg is set via inline style, the sticky cells must inherit it */
|
|
1956
|
+
.dds-table-head-sticky[style] th {
|
|
1957
|
+
background-color: inherit;
|
|
1958
|
+
}
|
|
1959
|
+
/* Sticky sortable header hover: keep background opaque to avoid bleed-through
|
|
1960
|
+
when the global .dds-table-th-sortable:hover uses a semi-transparent color. */
|
|
1961
|
+
.dds-table-head-sticky th.dds-table-th-sortable:hover {
|
|
1962
|
+
background-color: var(
|
|
1963
|
+
--dds-table-sticky-hover-bg,
|
|
1964
|
+
var(--dds-table-sticky-bg, var(--dds-table-header-bg))
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
/* -----------------------------------------------------------------------
|
|
1968
|
+
Cells — shared
|
|
1969
|
+
----------------------------------------------------------------------- */
|
|
1970
|
+
.dds-table-th,
|
|
1971
|
+
.dds-table-td {
|
|
1972
|
+
padding: var(--dds-table-cell-padding);
|
|
1973
|
+
text-align: left;
|
|
1974
|
+
vertical-align: top;
|
|
1975
|
+
}
|
|
1976
|
+
/* Alignment helpers */
|
|
1977
|
+
.dds-table-align-left { text-align: left; }
|
|
1978
|
+
.dds-table-align-center { text-align: center; }
|
|
1979
|
+
.dds-table-align-right { text-align: right; }
|
|
1980
|
+
/* -----------------------------------------------------------------------
|
|
1981
|
+
Header cell
|
|
1982
|
+
----------------------------------------------------------------------- */
|
|
1983
|
+
.dds-table-th {
|
|
1984
|
+
font-weight: var(--dds-font-semibold);
|
|
1985
|
+
font-size: var(--dds-table-header-font-size);
|
|
1986
|
+
color: var(--dds-table-header-text);
|
|
1987
|
+
border-bottom: 2px solid var(--dds-table-header-border);
|
|
1988
|
+
white-space: nowrap;
|
|
1989
|
+
}
|
|
1990
|
+
/* Default variant: left/right column borders */
|
|
1991
|
+
.dds-table-wrapper:not(.dds-table-borderless) .dds-table-th + .dds-table-th,
|
|
1992
|
+
.dds-table-wrapper:not(.dds-table-borderless) .dds-table-td + .dds-table-td {
|
|
1993
|
+
border-left: 1px solid var(--dds-table-border);
|
|
1994
|
+
}
|
|
1995
|
+
/* -----------------------------------------------------------------------
|
|
1996
|
+
Sortable column header
|
|
1997
|
+
----------------------------------------------------------------------- */
|
|
1998
|
+
.dds-table-th-sortable {
|
|
1999
|
+
cursor: pointer;
|
|
2000
|
+
user-select: none;
|
|
2001
|
+
}
|
|
2002
|
+
.dds-table-th-sortable:hover {
|
|
2003
|
+
background-color: var(--dds-table-header-hover-bg);
|
|
2004
|
+
color: var(--dds-table-header-hover-text);
|
|
2005
|
+
}
|
|
2006
|
+
.dds-table-th-sortable:focus-visible {
|
|
2007
|
+
outline: 2px solid var(--dds-table-focus-ring);
|
|
2008
|
+
outline-offset: -2px;
|
|
2009
|
+
}
|
|
2010
|
+
.dds-table-th-active {
|
|
2011
|
+
color: var(--dds-table-header-active-text);
|
|
2012
|
+
}
|
|
2013
|
+
.dds-table-th-content {
|
|
2014
|
+
display: inline-flex;
|
|
2015
|
+
align-items: center;
|
|
2016
|
+
gap: 0.375rem;
|
|
2017
|
+
}
|
|
2018
|
+
.dds-table-sort-icon {
|
|
2019
|
+
font-size: 0.75em;
|
|
2020
|
+
opacity: 0.7;
|
|
2021
|
+
flex-shrink: 0;
|
|
2022
|
+
}
|
|
2023
|
+
.dds-table-th-active .dds-table-sort-icon {
|
|
2024
|
+
opacity: 1;
|
|
2025
|
+
}
|
|
2026
|
+
/* -----------------------------------------------------------------------
|
|
2027
|
+
Body rows
|
|
2028
|
+
----------------------------------------------------------------------- */
|
|
2029
|
+
.dds-table-body .dds-table-row {
|
|
2030
|
+
border-top: 1px solid var(--dds-table-row-border);
|
|
2031
|
+
transition: background-color 150ms ease-in-out;
|
|
2032
|
+
}
|
|
2033
|
+
.dds-table-body .dds-table-row:hover {
|
|
2034
|
+
background-color: var(--dds-table-row-hover-bg);
|
|
2035
|
+
}
|
|
1848
2036
|
/* =============================================================================
|
|
1849
2037
|
Grid — multi-column layout component
|
|
1850
2038
|
============================================================================= */
|