@attrus-ds/core 0.1.0 → 0.2.0

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.
Files changed (58) hide show
  1. package/README.md +80 -8
  2. package/dist/css/components/buttons.css +1 -1
  3. package/dist/css/components/combobox.css +17 -1
  4. package/dist/css/components/inputs.css +3 -55
  5. package/dist/css/components/overlays.css +28 -59
  6. package/dist/css/components/primitives.css +10 -1
  7. package/dist/css/components/sidebar.css +3 -3
  8. package/dist/css/components/smart-search.css +91 -0
  9. package/dist/css/components/table.css +10 -8
  10. package/dist/css/components/tabs.css +2 -2
  11. package/dist/css/components/toast.css +4 -0
  12. package/dist/css/components/tooltip.css +5 -0
  13. package/dist/css/index.css +1 -0
  14. package/dist/css/tokens.css +100 -96
  15. package/dist/react/AppSidebar/AppSidebar.d.ts +50 -0
  16. package/dist/react/AppSidebar/AppSidebar.tsx +197 -0
  17. package/dist/react/AppTopbar/AppTopbar.d.ts +58 -0
  18. package/dist/react/AppTopbar/AppTopbar.tsx +203 -0
  19. package/dist/react/Atoms/Atoms.d.ts +149 -0
  20. package/dist/react/Atoms/Atoms.tsx +407 -0
  21. package/dist/react/Button/Button.d.ts +25 -0
  22. package/dist/react/Button/Button.tsx +83 -0
  23. package/dist/react/Callout/Callout.d.ts +29 -0
  24. package/dist/react/Callout/Callout.tsx +98 -0
  25. package/dist/react/Card/Card.d.ts +38 -0
  26. package/dist/react/Card/Card.tsx +93 -0
  27. package/dist/react/Combobox/Combobox.d.ts +52 -0
  28. package/dist/react/Combobox/Combobox.tsx +254 -0
  29. package/dist/react/DataTable/DataTable.d.ts +81 -0
  30. package/dist/react/DataTable/DataTable.tsx +308 -0
  31. package/dist/react/Drawer/Drawer.d.ts +35 -0
  32. package/dist/react/Drawer/Drawer.tsx +226 -0
  33. package/dist/react/Input/Input.d.ts +155 -0
  34. package/dist/react/Input/Input.tsx +478 -0
  35. package/dist/react/Modal/Modal.d.ts +27 -0
  36. package/dist/react/Modal/Modal.tsx +173 -0
  37. package/dist/react/NumberInput/NumberInput.d.ts +25 -0
  38. package/dist/react/NumberInput/NumberInput.tsx +117 -0
  39. package/dist/react/Pill/Pill.d.ts +31 -0
  40. package/dist/react/Pill/Pill.tsx +104 -0
  41. package/dist/react/SearchPill/SearchPill.d.ts +14 -0
  42. package/dist/react/SearchPill/SearchPill.tsx +40 -0
  43. package/dist/react/SmartSearch/SmartSearch.d.ts +65 -0
  44. package/dist/react/SmartSearch/SmartSearch.tsx +271 -0
  45. package/dist/react/Stepper/Stepper.d.ts +25 -0
  46. package/dist/react/Stepper/Stepper.tsx +94 -0
  47. package/dist/react/Tabs/Tabs.d.ts +32 -0
  48. package/dist/react/Tabs/Tabs.tsx +147 -0
  49. package/dist/react/Toast/Toast.d.ts +30 -0
  50. package/dist/react/Toast/Toast.tsx +94 -0
  51. package/dist/react/Tooltip/Tooltip.d.ts +23 -0
  52. package/dist/react/Tooltip/Tooltip.tsx +80 -0
  53. package/dist/react/ZeroState/ZeroState.d.ts +17 -0
  54. package/dist/react/ZeroState/ZeroState.tsx +45 -0
  55. package/dist/react/index.ts +35 -0
  56. package/dist/tokens/attrus-tokens.flat.json +1 -1
  57. package/dist/tokens/attrus-tokens.json +1 -1
  58. package/package.json +20 -2
@@ -0,0 +1,93 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * ATTRUS Card — typed wrapper over the canonical `.card` system
5
+ * (preview/components/cards.css). CSS stays the visual source of truth.
6
+ *
7
+ * Slots: compose with <CardHeader/>, <CardBody/>, <CardFooter/>,
8
+ * <CardCanvas/>, <CardDivider/> — the CSS `:has()` rules drop the base
9
+ * padding automatically when slots are present (each slot pads itself).
10
+ */
11
+
12
+ export type CardVariant = 'default' | 'flat' | 'subtle' | 'sunken' | 'raised' | 'floating' | 'hero' | 'inverse';
13
+ export type CardAccent = 'success' | 'warning' | 'danger' | 'info';
14
+ export type CardDensity = 'compact' | 'default' | 'spacious';
15
+
16
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
17
+ /** Surface role. Default: surface + hairline + xs shadow. */
18
+ variant?: CardVariant;
19
+ /** Semantic banner tint (success/warning/danger/info). */
20
+ accent?: CardAccent;
21
+ /** Padding density for the card and its slots. */
22
+ density?: CardDensity;
23
+ /** Clip children to the rounded corners (tables, images). */
24
+ clip?: boolean;
25
+ /** Hover/press affordance (`.card.interactive`) — wrap the card in an <a>/<button>, or pass onClick. */
26
+ interactive?: boolean;
27
+ }
28
+
29
+ export const Card: React.FC<CardProps> = ({
30
+ variant = 'default',
31
+ accent,
32
+ density = 'default',
33
+ clip = false,
34
+ interactive = false,
35
+ className,
36
+ style,
37
+ children,
38
+ ...rest
39
+ }) => {
40
+ const cls = [
41
+ 'card',
42
+ variant !== 'default' ? variant : '',
43
+ accent ? `accent-${accent}` : '',
44
+ density !== 'default' ? density : '',
45
+ interactive ? 'interactive' : '',
46
+ className || '',
47
+ ]
48
+ .filter(Boolean)
49
+ .join(' ');
50
+ return (
51
+ <div className={cls} style={clip ? { overflow: 'hidden', ...style } : style} {...rest}>
52
+ {children}
53
+ </div>
54
+ );
55
+ };
56
+
57
+ export interface CardSlotProps extends React.HTMLAttributes<HTMLDivElement> {}
58
+
59
+ export const CardHeader: React.FC<CardSlotProps> = ({ className, ...rest }) => (
60
+ <div className={['card-header', className || ''].filter(Boolean).join(' ')} {...rest} />
61
+ );
62
+ export const CardBody: React.FC<CardSlotProps> = ({ className, ...rest }) => (
63
+ <div className={['card-body', className || ''].filter(Boolean).join(' ')} {...rest} />
64
+ );
65
+ export const CardFooter: React.FC<CardSlotProps> = ({ className, ...rest }) => (
66
+ <div className={['card-footer', className || ''].filter(Boolean).join(' ')} {...rest} />
67
+ );
68
+ export const CardCanvas: React.FC<CardSlotProps> = ({ className, ...rest }) => (
69
+ <div className={['card-canvas', className || ''].filter(Boolean).join(' ')} {...rest} />
70
+ );
71
+ export const CardDivider: React.FC<CardSlotProps> = ({ className, ...rest }) => (
72
+ <div className={['card-divider', className || ''].filter(Boolean).join(' ')} {...rest} />
73
+ );
74
+
75
+ /** KPI/stat layout inside a card — `.card-stat` (mono label, bold value, tinted delta). */
76
+ export interface CardStatProps extends React.HTMLAttributes<HTMLDivElement> {
77
+ label: React.ReactNode;
78
+ value: React.ReactNode;
79
+ /** Delta text, e.g. "+8.2%". */
80
+ delta?: React.ReactNode;
81
+ /** Direction tints the delta: up=success, down=danger, flat=muted. Default: 'flat'. */
82
+ deltaDirection?: 'up' | 'down' | 'flat';
83
+ }
84
+ export const CardStat: React.FC<CardStatProps> = ({ label, value, delta, deltaDirection = 'flat', className, children, ...rest }) => (
85
+ <div className={['card-stat', className || ''].filter(Boolean).join(' ')} {...rest}>
86
+ <span className="stat-label">{label}</span>
87
+ <span className="stat-value">{value}</span>
88
+ {delta != null ? <span className={`stat-delta ${deltaDirection}`}>{delta}</span> : null}
89
+ {children}
90
+ </div>
91
+ );
92
+
93
+ export default Card;
@@ -0,0 +1,52 @@
1
+ import * as React from 'react';
2
+
3
+ export interface ComboOption {
4
+ value: string;
5
+ label: React.ReactNode;
6
+ /** Secondary line under the label. */
7
+ meta?: React.ReactNode;
8
+ /** Right-aligned mono hint (e.g. a code). */
9
+ trailing?: React.ReactNode;
10
+ /** Optional group header this option sits under. */
11
+ group?: string;
12
+ /** Non-selectable (`.is-disabled`). */
13
+ disabled?: boolean;
14
+ /** Text used by the search filter when label isn't a plain string. */
15
+ searchText?: string;
16
+ }
17
+
18
+ export type ComboboxStatus = 'default' | 'error';
19
+
20
+ export interface ComboboxProps {
21
+ options: ComboOption[];
22
+ value?: string | null;
23
+ onChange?: (value: string) => void;
24
+ placeholder?: string;
25
+ /** Shows the search header inside the popover. */
26
+ searchable?: boolean;
27
+ searchPlaceholder?: string;
28
+ /** Trigger leading icon (`.combobox-trigger-icon`). */
29
+ icon?: React.ReactNode;
30
+ /** Validation state — error ring on the trigger (`.combobox.is-invalid` on the wrapper). */
31
+ status?: ComboboxStatus;
32
+ /** Filter-chip row inside the popover (`.combobox-filters`). */
33
+ filters?: React.ReactNode;
34
+ /** Results meta line above the list (`.combobox-meta`). */
35
+ meta?: React.ReactNode;
36
+ /** Muted meta line below the list (`.combobox-foot-meta`). */
37
+ footMeta?: React.ReactNode;
38
+ /** Popover starts open (galleries/docs). */
39
+ defaultOpen?: boolean;
40
+ /** Footer action (e.g. "Create new counterparty"). */
41
+ footer?: React.ReactNode;
42
+ onFooterClick?: () => void;
43
+ emptyTitle?: React.ReactNode;
44
+ emptySub?: React.ReactNode;
45
+ disabled?: boolean;
46
+ className?: string;
47
+ style?: React.CSSProperties;
48
+ 'aria-label'?: string;
49
+ }
50
+
51
+ export declare const Combobox: React.FC<ComboboxProps>;
52
+ export default Combobox;
@@ -0,0 +1,254 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * ATTRUS Combobox — typed wrapper over the canonical `.combobox`
5
+ * (preview/components/combobox.css): trigger + popover listbox with
6
+ * filterable options, groups, metas, selected check and footer action.
7
+ */
8
+
9
+ export interface ComboOption {
10
+ value: string;
11
+ label: React.ReactNode;
12
+ /** Secondary line under the label. */
13
+ meta?: React.ReactNode;
14
+ /** Right-aligned mono hint (e.g. a code). */
15
+ trailing?: React.ReactNode;
16
+ /** Optional group header this option sits under. */
17
+ group?: string;
18
+ /** Non-selectable (`.is-disabled`). */
19
+ disabled?: boolean;
20
+ /** Text used by the search filter when label isn't a plain string. */
21
+ searchText?: string;
22
+ }
23
+
24
+ export type ComboboxStatus = 'default' | 'error';
25
+
26
+ export interface ComboboxProps {
27
+ options: ComboOption[];
28
+ value?: string | null;
29
+ onChange?: (value: string) => void;
30
+ placeholder?: string;
31
+ /** Shows the search header inside the popover. */
32
+ searchable?: boolean;
33
+ searchPlaceholder?: string;
34
+ /** Trigger leading icon (`.combobox-trigger-icon`). */
35
+ icon?: React.ReactNode;
36
+ /** Validation state — error ring on the trigger (`.is-invalid`). */
37
+ status?: ComboboxStatus;
38
+ /** Filter-chip row inside the popover (`.combobox-filters`) — use `.combobox-filter-chip` buttons. */
39
+ filters?: React.ReactNode;
40
+ /** Results meta line above the list (`.combobox-meta`), e.g. "Results (21)". */
41
+ meta?: React.ReactNode;
42
+ /** Muted meta line below the list (`.combobox-foot-meta`). */
43
+ footMeta?: React.ReactNode;
44
+ /** Popover starts open (galleries/docs). */
45
+ defaultOpen?: boolean;
46
+ /** Footer action (e.g. "Create new counterparty"). */
47
+ footer?: React.ReactNode;
48
+ onFooterClick?: () => void;
49
+ emptyTitle?: React.ReactNode;
50
+ emptySub?: React.ReactNode;
51
+ disabled?: boolean;
52
+ className?: string;
53
+ style?: React.CSSProperties;
54
+ 'aria-label'?: string;
55
+ }
56
+
57
+ const Chevron: React.FC = () => (
58
+ <svg className="combobox-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
59
+ <path d="m6 9 6 6 6-6" />
60
+ </svg>
61
+ );
62
+ const Check: React.FC = () => (
63
+ <svg className="combobox-option-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
64
+ <path d="M20 6 9 17l-5-5" />
65
+ </svg>
66
+ );
67
+
68
+ function optionText(o: ComboOption): string {
69
+ if (o.searchText) return o.searchText;
70
+ return typeof o.label === 'string' ? o.label : String(o.value);
71
+ }
72
+
73
+ export const Combobox: React.FC<ComboboxProps> = ({
74
+ options,
75
+ value = null,
76
+ onChange,
77
+ placeholder = 'Select…',
78
+ searchable = false,
79
+ searchPlaceholder = 'Search…',
80
+ icon,
81
+ status = 'default',
82
+ filters,
83
+ meta,
84
+ footMeta,
85
+ defaultOpen = false,
86
+ footer,
87
+ onFooterClick,
88
+ emptyTitle = 'No matches',
89
+ emptySub,
90
+ disabled = false,
91
+ className,
92
+ style,
93
+ ...rest
94
+ }) => {
95
+ const [open, setOpen] = React.useState(defaultOpen);
96
+ const [q, setQ] = React.useState('');
97
+ const [active, setActive] = React.useState<string | null>(null);
98
+ const wrapRef = React.useRef<HTMLDivElement>(null);
99
+
100
+ React.useEffect(() => {
101
+ if (!open) return;
102
+ const onDoc = (e: MouseEvent) => {
103
+ if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) setOpen(false);
104
+ };
105
+ const onKey = (e: KeyboardEvent) => {
106
+ if (e.key === 'Escape') setOpen(false);
107
+ };
108
+ document.addEventListener('mousedown', onDoc);
109
+ document.addEventListener('keydown', onKey);
110
+ return () => {
111
+ document.removeEventListener('mousedown', onDoc);
112
+ document.removeEventListener('keydown', onKey);
113
+ };
114
+ }, [open]);
115
+
116
+ const selected = options.find((o) => o.value === value) || null;
117
+ const filtered = q
118
+ ? options.filter((o) => optionText(o).toLowerCase().indexOf(q.toLowerCase()) !== -1)
119
+ : options;
120
+ const selectable = filtered.filter((o) => !o.disabled);
121
+
122
+ // Keyboard nav — wrapper-level so it works from the trigger AND the search
123
+ // input. Arrow keys move `.is-active`; Enter commits the active option.
124
+ const onWrapKeyDown = (e: React.KeyboardEvent) => {
125
+ if (!open || !selectable.length) return;
126
+ const idx = selectable.findIndex((o) => o.value === active);
127
+ if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
128
+ e.preventDefault();
129
+ const next = e.key === 'ArrowDown'
130
+ ? selectable[Math.min(idx + 1, selectable.length - 1)]
131
+ : selectable[Math.max(idx - 1, 0)];
132
+ setActive(next.value);
133
+ const list = wrapRef.current?.querySelector('.combobox-list');
134
+ const el = list?.querySelector(`[data-value="${next.value}"]`) as HTMLElement | null;
135
+ if (list && el) {
136
+ const lt = (list as HTMLElement).scrollTop;
137
+ const lb = lt + (list as HTMLElement).clientHeight;
138
+ if (el.offsetTop < lt) (list as HTMLElement).scrollTop = el.offsetTop;
139
+ else if (el.offsetTop + el.offsetHeight > lb) (list as HTMLElement).scrollTop = el.offsetTop + el.offsetHeight - (list as HTMLElement).clientHeight;
140
+ }
141
+ } else if (e.key === 'Enter') {
142
+ const hit = selectable.find((o) => o.value === active);
143
+ if (hit) {
144
+ e.preventDefault();
145
+ if (onChange) onChange(hit.value);
146
+ setOpen(false);
147
+ setQ('');
148
+ }
149
+ }
150
+ };
151
+
152
+ // group-preserving render order
153
+ const rendered: React.ReactNode[] = [];
154
+ let lastGroup: string | undefined;
155
+ filtered.forEach((o) => {
156
+ if (o.group && o.group !== lastGroup) {
157
+ rendered.push(
158
+ <li key={`g-${o.group}`} className="combobox-group-label">
159
+ {o.group}
160
+ </li>
161
+ );
162
+ lastGroup = o.group;
163
+ }
164
+ const isSel = o.value === value;
165
+ rendered.push(
166
+ <li
167
+ key={o.value}
168
+ data-value={o.value}
169
+ className={['combobox-option', isSel ? 'is-selected' : '', o.value === active ? 'is-active' : '', o.disabled ? 'is-disabled' : ''].filter(Boolean).join(' ')}
170
+ role="option"
171
+ aria-selected={isSel}
172
+ aria-disabled={o.disabled || undefined}
173
+ onMouseEnter={() => { if (!o.disabled) setActive(o.value); }}
174
+ onClick={() => {
175
+ if (o.disabled) return;
176
+ if (onChange) onChange(o.value);
177
+ setOpen(false);
178
+ setQ('');
179
+ }}
180
+ >
181
+ <span className="combobox-option-content">
182
+ <span className="combobox-option-label">{o.label}</span>
183
+ {o.meta != null ? <span className="combobox-option-meta">{o.meta}</span> : null}
184
+ </span>
185
+ {o.trailing != null ? <span className="combobox-option-trailing">{o.trailing}</span> : null}
186
+ <Check />
187
+ </li>
188
+ );
189
+ });
190
+
191
+ return (
192
+ <div
193
+ ref={wrapRef}
194
+ className={['combobox', open ? 'is-open' : '', status === 'error' ? 'is-invalid' : '', className || ''].filter(Boolean).join(' ')}
195
+ style={style}
196
+ onKeyDown={onWrapKeyDown}
197
+ >
198
+ <button
199
+ type="button"
200
+ className="combobox-trigger"
201
+ aria-haspopup="listbox"
202
+ aria-expanded={open}
203
+ disabled={disabled}
204
+ onClick={() => { setOpen((o) => !o); setActive(value); }}
205
+ {...rest}
206
+ >
207
+ {icon != null ? <span className="combobox-trigger-icon">{icon}</span> : null}
208
+ <span className="combobox-value">
209
+ {selected ? selected.label : <span className="combobox-placeholder">{placeholder}</span>}
210
+ </span>
211
+ <Chevron />
212
+ </button>
213
+ {open ? (
214
+ <div className="combobox-popover">
215
+ {searchable ? (
216
+ <div className="combobox-search">
217
+ <svg className="combobox-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
218
+ <circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" />
219
+ </svg>
220
+ <input
221
+ autoFocus
222
+ placeholder={searchPlaceholder}
223
+ value={q}
224
+ onChange={(e) => setQ(e.target.value)}
225
+ />
226
+ </div>
227
+ ) : null}
228
+ {filters != null ? <div className="combobox-filters">{filters}</div> : null}
229
+ {meta != null ? <div className="combobox-meta">{meta}</div> : null}
230
+ {filtered.length === 0 ? (
231
+ <div className="combobox-empty">
232
+ <strong>{emptyTitle}</strong>
233
+ {emptySub}
234
+ </div>
235
+ ) : (
236
+ <ul className="combobox-list" role="listbox">
237
+ {rendered}
238
+ </ul>
239
+ )}
240
+ {footMeta != null ? <div className="combobox-foot-meta">{footMeta}</div> : null}
241
+ {footer ? (
242
+ <div className="combobox-footer">
243
+ <button type="button" className="combobox-footer-action" onClick={onFooterClick}>
244
+ {footer}
245
+ </button>
246
+ </div>
247
+ ) : null}
248
+ </div>
249
+ ) : null}
250
+ </div>
251
+ );
252
+ };
253
+
254
+ export default Combobox;
@@ -0,0 +1,81 @@
1
+ import * as React from 'react';
2
+
3
+ export type SortDir = 'asc' | 'desc';
4
+ export type DataTableSize = 'sm' | 'md' | 'lg';
5
+ export type RowState = 'muted' | 'error' | undefined;
6
+
7
+ export interface DataTableColumn<T> {
8
+ /** Unique column id — also what onSort receives. */
9
+ key: string;
10
+ /** Column header. Strings also become the responsive data-label. */
11
+ header: React.ReactNode;
12
+ /** Right-aligned tabular numerals (.dt-num). */
13
+ numeric?: boolean;
14
+ /** Monospace identifier (.dt-id). */
15
+ id?: boolean;
16
+ /** Sortable header (.dt-th-sort with chevron). */
17
+ sortable?: boolean;
18
+ /** Cell renderer — defaults to String(row[key]). */
19
+ render?: (row: T) => React.ReactNode;
20
+ }
21
+
22
+ export interface DataTableProps<T> {
23
+ columns: Array<DataTableColumn<T>>;
24
+ rows: T[];
25
+ /** Stable row identity. */
26
+ rowKey: (row: T) => string;
27
+ /** Makes rows hoverable + clickable (tr.hov). */
28
+ onRowClick?: (row: T) => void;
29
+ /** Row tint: 'muted' (cancelled) or 'error' (danger). */
30
+ rowState?: (row: T) => RowState;
31
+ /** Keys of persistently selected rows (.is-selected). */
32
+ selectedKeys?: string[];
33
+ /** Renders the `.col-select` checkbox column; called with the row key. Pair with selectedKeys. */
34
+ onSelectToggle?: (key: string) => void;
35
+ /** Header checkbox — toggle all. */
36
+ onSelectAll?: () => void;
37
+ /** Loading state — `.dt-skeleton` shimmer rows instead of the body. */
38
+ loading?: boolean;
39
+ /** How many skeleton rows. Default 4. */
40
+ loadingRows?: number;
41
+ /** sm | md (default) | lg — .dt--sm / .dt--lg. */
42
+ size?: DataTableSize;
43
+ zebra?: boolean;
44
+ sticky?: boolean;
45
+ bordered?: boolean;
46
+ /** Dark-surface treatment (.dt.on-inverse). */
47
+ onInverse?: boolean;
48
+ /** Toolbar slot (.dt-toolbar) above the table. */
49
+ toolbar?: React.ReactNode;
50
+ /** Pagination slot (.dt-pagination) below the table. */
51
+ pagination?: React.ReactNode;
52
+ /** Surrounding card (.dt-wrap). Default true; disable inside a Card. */
53
+ wrap?: boolean;
54
+ /** Responsive card-collapse wrapper (.dt-responsive). Default true. */
55
+ responsive?: boolean;
56
+ /** Zero state when rows is empty. */
57
+ empty?: { icon?: React.ReactNode; title: React.ReactNode; sub?: React.ReactNode };
58
+ /** Controlled sorting (visual). */
59
+ sortKey?: string;
60
+ sortDir?: SortDir;
61
+ onSort?: (key: string) => void;
62
+ className?: string;
63
+ style?: React.CSSProperties;
64
+ }
65
+
66
+ export declare function DataTable<T>(props: DataTableProps<T>): React.ReactElement;
67
+ export declare const DTCellStack: React.FC<{ pri: React.ReactNode; sec?: React.ReactNode } & React.HTMLAttributes<HTMLDivElement>>;
68
+ export declare const DTCellLead: React.FC<{ lead: React.ReactNode; pri: React.ReactNode; sec?: React.ReactNode } & React.HTMLAttributes<HTMLDivElement>>;
69
+ export declare const DTActions: React.FC<React.HTMLAttributes<HTMLDivElement>>;
70
+
71
+ export interface DTPaginationProps extends React.HTMLAttributes<HTMLDivElement> {
72
+ /** Left-side mono range text (e.g. "1–10 of 42"). */
73
+ range?: React.ReactNode;
74
+ /** Current page (1-based). */
75
+ page: number;
76
+ pages: number;
77
+ onPage?: (page: number) => void;
78
+ }
79
+ export declare const DTPagination: React.FC<DTPaginationProps>;
80
+
81
+ export default DataTable;