neba 1.2.0 → 1.4.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.
- package/README.md +8 -8
- package/dist/components/alert/Alert.d.ts +7 -1
- package/dist/components/alert/Alert.js +1 -1
- package/dist/components/animate-appear/AnimateAppear.d.ts +55 -0
- package/dist/components/animate-appear/AnimateAppear.js +1 -0
- package/dist/components/animate-appear/index.d.ts +2 -0
- package/dist/components/animate-appear/index.js +1 -0
- package/dist/components/animate-blink/AnimateBlink.d.ts +31 -0
- package/dist/components/animate-blink/AnimateBlink.js +1 -0
- package/dist/components/animate-blink/index.d.ts +2 -0
- package/dist/components/animate-blink/index.js +1 -0
- package/dist/components/animate-fade/AnimateFade.d.ts +31 -0
- package/dist/components/animate-fade/AnimateFade.js +1 -0
- package/dist/components/animate-fade/index.d.ts +2 -0
- package/dist/components/animate-fade/index.js +1 -0
- package/dist/components/animate-grow/AnimateGrow.d.ts +41 -0
- package/dist/components/animate-grow/AnimateGrow.js +1 -0
- package/dist/components/animate-grow/index.d.ts +2 -0
- package/dist/components/animate-grow/index.js +1 -0
- package/dist/components/animate-headline/AnimateHeadline.d.ts +55 -0
- package/dist/components/animate-headline/AnimateHeadline.js +1 -0
- package/dist/components/animate-headline/index.d.ts +2 -0
- package/dist/components/animate-headline/index.js +1 -0
- package/dist/components/animate-lighting/AnimateLighting.d.ts +62 -0
- package/dist/components/animate-lighting/AnimateLighting.js +1 -0
- package/dist/components/animate-lighting/index.d.ts +2 -0
- package/dist/components/animate-lighting/index.js +1 -0
- package/dist/components/animate-marquee/AnimateMarquee.d.ts +65 -0
- package/dist/components/animate-marquee/AnimateMarquee.js +1 -0
- package/dist/components/animate-marquee/index.d.ts +2 -0
- package/dist/components/animate-marquee/index.js +1 -0
- package/dist/components/animate-rotate/AnimateRotate.d.ts +48 -0
- package/dist/components/animate-rotate/AnimateRotate.js +1 -0
- package/dist/components/animate-rotate/index.d.ts +2 -0
- package/dist/components/animate-rotate/index.js +1 -0
- package/dist/components/animate-slide/AnimateSlide.d.ts +46 -0
- package/dist/components/animate-slide/AnimateSlide.js +1 -0
- package/dist/components/animate-slide/index.d.ts +2 -0
- package/dist/components/animate-slide/index.js +1 -0
- package/dist/components/animate-typing/AnimateTyping.d.ts +58 -0
- package/dist/components/animate-typing/AnimateTyping.js +1 -0
- package/dist/components/animate-typing/index.d.ts +2 -0
- package/dist/components/animate-typing/index.js +1 -0
- package/dist/components/animate-zoom/AnimateZoom.d.ts +37 -0
- package/dist/components/animate-zoom/AnimateZoom.js +1 -0
- package/dist/components/animate-zoom/index.d.ts +2 -0
- package/dist/components/animate-zoom/index.js +1 -0
- package/dist/components/aspect-ratio/AspectRatio.d.ts +63 -0
- package/dist/components/aspect-ratio/AspectRatio.js +1 -0
- package/dist/components/aspect-ratio/index.d.ts +2 -0
- package/dist/components/aspect-ratio/index.js +1 -0
- package/dist/components/avatar/Avatar.d.ts +7 -1
- package/dist/components/avatar/Avatar.js +1 -1
- package/dist/components/blockquote/Blockquote.d.ts +7 -1
- package/dist/components/blockquote/Blockquote.js +1 -1
- package/dist/components/box/Box.d.ts +7 -1
- package/dist/components/box/Box.js +1 -1
- package/dist/components/chip/Chip.d.ts +7 -1
- package/dist/components/chip/Chip.js +1 -1
- package/dist/components/color-picker/ColorPicker.d.ts +102 -0
- package/dist/components/color-picker/ColorPicker.js +1 -0
- package/dist/components/color-picker/index.d.ts +2 -0
- package/dist/components/color-picker/index.js +1 -0
- package/dist/components/data-table/DataTable.d.ts +323 -0
- package/dist/components/data-table/DataTable.js +1 -0
- package/dist/components/data-table/index.d.ts +2 -0
- package/dist/components/data-table/index.js +1 -0
- package/dist/components/drawer/Drawer.d.ts +145 -0
- package/dist/components/drawer/Drawer.js +1 -0
- package/dist/components/drawer/index.d.ts +2 -0
- package/dist/components/drawer/index.js +1 -0
- package/dist/components/empty/Empty.d.ts +69 -0
- package/dist/components/empty/Empty.js +1 -0
- package/dist/components/empty/index.d.ts +2 -0
- package/dist/components/empty/index.js +1 -0
- package/dist/components/icon/Icon.d.ts +8 -1
- package/dist/components/icon/Icon.js +1 -1
- package/dist/components/mockup/Mockup.d.ts +151 -0
- package/dist/components/mockup/Mockup.js +1 -0
- package/dist/components/mockup/index.d.ts +2 -0
- package/dist/components/mockup/index.js +1 -0
- package/dist/components/popover/Popover.d.ts +109 -0
- package/dist/components/popover/Popover.js +1 -0
- package/dist/components/popover/index.d.ts +2 -0
- package/dist/components/popover/index.js +1 -0
- package/dist/components/skeleton/Skeleton.d.ts +76 -0
- package/dist/components/skeleton/Skeleton.js +1 -0
- package/dist/components/skeleton/index.d.ts +2 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/typography/Typography.d.ts +7 -1
- package/dist/components/typography/Typography.js +1 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1 -1
- package/dist/internal/animate.d.ts +175 -0
- package/dist/internal/animate.js +1 -0
- package/dist/internal/color.d.ts +108 -0
- package/dist/internal/color.js +1 -0
- package/dist/internal/data-table.d.ts +170 -0
- package/dist/internal/data-table.js +1 -0
- package/dist/internal/i18n.d.ts +76 -0
- package/dist/internal/i18n.js +1 -1
- package/dist/internal/mockup.d.ts +193 -0
- package/dist/internal/mockup.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind.css +405 -11
- package/dist/types.d.ts +112 -0
- package/package.json +12 -12
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NebaAlign, NebaElevation, NebaStyleProps } from '../../types';
|
|
3
|
+
/** Which way a column runs when it is sorted. */
|
|
4
|
+
export type DataTableSortDirection = 'asc' | 'desc';
|
|
5
|
+
/** One key of the sort, and its direction. A sort is a list of these. */
|
|
6
|
+
export interface DataTableSort {
|
|
7
|
+
/** The column's `key`. */
|
|
8
|
+
key: string;
|
|
9
|
+
direction: DataTableSortDirection;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* How many rows may be chosen at once.
|
|
13
|
+
*
|
|
14
|
+
* `none` is the default: a table that highlights a row under the pointer but
|
|
15
|
+
* cannot be selected is a table that has promised something it does not do.
|
|
16
|
+
*/
|
|
17
|
+
export type DataTableSelectionMode = 'none' | 'single' | 'multiple';
|
|
18
|
+
/**
|
|
19
|
+
* Which rows carry the tint, counted the way a reader counts them — `odd` is
|
|
20
|
+
* the first, the third and the fifth.
|
|
21
|
+
*/
|
|
22
|
+
export type DataTableStripe = 'odd' | 'even';
|
|
23
|
+
/**
|
|
24
|
+
* How the rows are handed out.
|
|
25
|
+
*
|
|
26
|
+
* - `scroll` — all of them, in one scrolling body. With a `height` set this is
|
|
27
|
+
* the virtualized mode, and the one to reach for at any size.
|
|
28
|
+
* - `pages` — a slice at a time, with a footer to step through them. Right when
|
|
29
|
+
* the row's position in the whole set is information (a ledger, a log), and
|
|
30
|
+
* the only option when the rows are being fetched a page at a time.
|
|
31
|
+
*/
|
|
32
|
+
export type DataTablePaging = 'scroll' | 'pages';
|
|
33
|
+
/** The three things the table does to the rows before drawing them. */
|
|
34
|
+
export type DataTableStage = 'sort' | 'filter' | 'pages';
|
|
35
|
+
/**
|
|
36
|
+
* A column: its heading, how wide it is, how to get a value out of a row and
|
|
37
|
+
* how to draw one.
|
|
38
|
+
*
|
|
39
|
+
* The split between `value` and `render` is the whole shape of this type. A
|
|
40
|
+
* `render` decides what a reader sees; a `value` decides what the sort and the
|
|
41
|
+
* search see. Most columns need neither — the cell is `row[key]` and that is
|
|
42
|
+
* what is compared and matched. A column that draws a Chip needs `render`, and
|
|
43
|
+
* it needs `value` as well the moment it is sortable, because a React element
|
|
44
|
+
* has no order.
|
|
45
|
+
*/
|
|
46
|
+
export interface DataTableColumn<Row> {
|
|
47
|
+
/**
|
|
48
|
+
* Identifies the column — to `sort`, to `columnWidths`, and unless `value` or
|
|
49
|
+
* `render` says otherwise, it names the property to read off each row.
|
|
50
|
+
*/
|
|
51
|
+
key: string;
|
|
52
|
+
/** The heading. Defaults to the `key`, which is usually not what you want. */
|
|
53
|
+
label?: React.ReactNode;
|
|
54
|
+
/**
|
|
55
|
+
* The heading above this column and its neighbours.
|
|
56
|
+
*
|
|
57
|
+
* Adjacent columns carrying the same string are drawn under one merged cell
|
|
58
|
+
* in a second header row; a column with no `group` spans both rows. Merging
|
|
59
|
+
* by adjacency rather than by a separate model is deliberate — a group is a
|
|
60
|
+
* run of columns, and a table where "Address" covers columns 2, 5 and 9 is a
|
|
61
|
+
* table whose columns are in the wrong order.
|
|
62
|
+
*/
|
|
63
|
+
group?: string;
|
|
64
|
+
/**
|
|
65
|
+
* How wide, in pixels. Columns that do not say share whatever is left.
|
|
66
|
+
*
|
|
67
|
+
* Pixels rather than any CSS length, because the width is a number the resize
|
|
68
|
+
* drag does arithmetic on. A column that has been dragged keeps the dragged
|
|
69
|
+
* width until it is double-clicked.
|
|
70
|
+
*/
|
|
71
|
+
width?: number;
|
|
72
|
+
/** How narrow a drag may make it. @default 48 */
|
|
73
|
+
minWidth?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Which edge the cells line up against. Numbers want `end` so their digits
|
|
76
|
+
* line up in a column.
|
|
77
|
+
* @default 'start'
|
|
78
|
+
*/
|
|
79
|
+
align?: NebaAlign;
|
|
80
|
+
/** The heading's own alignment, when it should differ from the cells'. */
|
|
81
|
+
headerAlign?: NebaAlign;
|
|
82
|
+
/** Whether this column can be sorted. Defaults to the table's `sortable`. */
|
|
83
|
+
sortable?: boolean;
|
|
84
|
+
/** Whether this column can be dragged wider. Defaults to `resizable`. */
|
|
85
|
+
resizable?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Whether the search looks in this column.
|
|
88
|
+
* @default true
|
|
89
|
+
*/
|
|
90
|
+
searchable?: boolean;
|
|
91
|
+
/** Leaves the column out without removing it from the list. */
|
|
92
|
+
hidden?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* The value behind the cell: what is sorted, and what the search is matched
|
|
95
|
+
* against. Defaults to `row[key]`.
|
|
96
|
+
*/
|
|
97
|
+
value?: (row: Row) => unknown;
|
|
98
|
+
/**
|
|
99
|
+
* Orders two rows by this column, for a value the default comparison cannot
|
|
100
|
+
* rank — a status that goes `draft`, `review`, `live` rather than
|
|
101
|
+
* alphabetically. Always written ascending; the table reverses it.
|
|
102
|
+
*/
|
|
103
|
+
compare?: (a: Row, b: Row) => number;
|
|
104
|
+
/**
|
|
105
|
+
* Draws the cell. `index` is the row's place in the sorted, filtered order,
|
|
106
|
+
* counted from `0` across every page — so `(row, index) => index + 1` is a
|
|
107
|
+
* running row number.
|
|
108
|
+
*/
|
|
109
|
+
render?: (row: Row, index: number) => React.ReactNode;
|
|
110
|
+
}
|
|
111
|
+
export interface DataTableProps<Row> extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'children' | 'onSelect' | 'defaultValue'> {
|
|
112
|
+
/** The columns, in the order they appear. */
|
|
113
|
+
headers: readonly DataTableColumn<Row>[];
|
|
114
|
+
/** The rows. */
|
|
115
|
+
items: readonly Row[];
|
|
116
|
+
/**
|
|
117
|
+
* A stable identity per row, and the value `selected` is a list of.
|
|
118
|
+
*
|
|
119
|
+
* Defaults to the row's index in `items`, which is enough for a table that
|
|
120
|
+
* only ever displays. The moment rows can be chosen, sorted or filtered it is
|
|
121
|
+
* required in practice: an index identifies a position, and every one of
|
|
122
|
+
* those three changes which row is in it.
|
|
123
|
+
*/
|
|
124
|
+
getRowKey?: (row: Row, index: number) => React.Key;
|
|
125
|
+
/**
|
|
126
|
+
* Drop shadow depth. `0` (the default) is flat.
|
|
127
|
+
* @default 0
|
|
128
|
+
*/
|
|
129
|
+
elevation?: NebaElevation;
|
|
130
|
+
/**
|
|
131
|
+
* How tall the scrolling body is — a number is pixels, a string any CSS
|
|
132
|
+
* length. **This is what turns virtual scrolling on**: rows can only be left
|
|
133
|
+
* out of the DOM if something bounds the height they would have taken.
|
|
134
|
+
*/
|
|
135
|
+
height?: number | string;
|
|
136
|
+
/** The same, as a ceiling: the table is as tall as its rows, up to this. */
|
|
137
|
+
maxHeight?: number | string;
|
|
138
|
+
/**
|
|
139
|
+
* How tall one row is, in pixels. Defaults to the `size`/`density` ladder.
|
|
140
|
+
*
|
|
141
|
+
* Every row is this tall and cells never wrap — which is what makes the
|
|
142
|
+
* scroll position arithmetic rather than a measurement. Raise it for a table
|
|
143
|
+
* whose cells hold an Avatar or two lines of text.
|
|
144
|
+
*/
|
|
145
|
+
rowHeight?: number;
|
|
146
|
+
/**
|
|
147
|
+
* Tints every other row. `true` means `even` — the second, the fourth, the
|
|
148
|
+
* sixth — and the parity is counted over the whole set, so it does not change
|
|
149
|
+
* when the rows are scrolled or sorted.
|
|
150
|
+
* @default false
|
|
151
|
+
*/
|
|
152
|
+
striped?: boolean | DataTableStripe;
|
|
153
|
+
/**
|
|
154
|
+
* Lights the row under the pointer.
|
|
155
|
+
* @default true
|
|
156
|
+
*/
|
|
157
|
+
hoverable?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Pins the header while the body scrolls.
|
|
160
|
+
* @default true
|
|
161
|
+
*/
|
|
162
|
+
stickyHeader?: boolean;
|
|
163
|
+
/** Shown above the table, and read out as its accessible name. */
|
|
164
|
+
caption?: React.ReactNode;
|
|
165
|
+
/** The name the grid is announced by, when there is no `caption`. */
|
|
166
|
+
label?: string;
|
|
167
|
+
/** What to show instead of rows when there are none. */
|
|
168
|
+
empty?: React.ReactNode;
|
|
169
|
+
/**
|
|
170
|
+
* Leaves the rows that are off screen out of the DOM. Needs a `height` or a
|
|
171
|
+
* `maxHeight` to have anything to measure against; without one every row is
|
|
172
|
+
* rendered whatever this says.
|
|
173
|
+
* @default true
|
|
174
|
+
*/
|
|
175
|
+
virtual?: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* How many rows are kept rendered past each edge of the viewport, so a fast
|
|
178
|
+
* scroll does not show a band of nothing.
|
|
179
|
+
* @default 8
|
|
180
|
+
*/
|
|
181
|
+
overscan?: number;
|
|
182
|
+
/**
|
|
183
|
+
* Makes every column sortable. A column overrides it either way with its own
|
|
184
|
+
* `sortable`.
|
|
185
|
+
* @default false
|
|
186
|
+
*/
|
|
187
|
+
sortable?: boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Whether more than one column can be sorted at a time. With `multiple`, a
|
|
190
|
+
* Shift-click adds a column to the sort instead of replacing it.
|
|
191
|
+
* @default 'single'
|
|
192
|
+
*/
|
|
193
|
+
sortMode?: 'single' | 'multiple';
|
|
194
|
+
/** The sort. Use with `onSortChange` for a controlled one. */
|
|
195
|
+
sort?: readonly DataTableSort[];
|
|
196
|
+
/** What it starts as, for an uncontrolled one. */
|
|
197
|
+
defaultSort?: readonly DataTableSort[];
|
|
198
|
+
onSortChange?: (sort: DataTableSort[]) => void;
|
|
199
|
+
/**
|
|
200
|
+
* Lets the headers be dragged wider or narrower. A double-click on the handle
|
|
201
|
+
* gives the column its original width back.
|
|
202
|
+
* @default false
|
|
203
|
+
*/
|
|
204
|
+
resizable?: boolean;
|
|
205
|
+
/** The widths, keyed by column. Use with `onColumnWidthsChange`. */
|
|
206
|
+
columnWidths?: Readonly<Record<string, number>>;
|
|
207
|
+
/** What they start as, for an uncontrolled table. */
|
|
208
|
+
defaultColumnWidths?: Readonly<Record<string, number>>;
|
|
209
|
+
onColumnWidthsChange?: (widths: Record<string, number>) => void;
|
|
210
|
+
/**
|
|
211
|
+
* How many rows may be chosen.
|
|
212
|
+
* @default 'none'
|
|
213
|
+
*/
|
|
214
|
+
selectionMode?: DataTableSelectionMode;
|
|
215
|
+
/** The chosen rows, as their keys. Use with `onSelectedChange`. */
|
|
216
|
+
selected?: readonly React.Key[];
|
|
217
|
+
/** Which start chosen, for an uncontrolled table. */
|
|
218
|
+
defaultSelected?: readonly React.Key[];
|
|
219
|
+
/** The keys, and the rows behind them — including rows on other pages. */
|
|
220
|
+
onSelectedChange?: (selected: React.Key[], rows: Row[]) => void;
|
|
221
|
+
/**
|
|
222
|
+
* Adds a column of ticks, and one in the header that chooses every displayed
|
|
223
|
+
* row at once. The rows stay clickable either way; this is for a table where
|
|
224
|
+
* choosing is the task rather than something done on the way past.
|
|
225
|
+
* @default false
|
|
226
|
+
*/
|
|
227
|
+
checkboxes?: boolean;
|
|
228
|
+
/** Fires on every press of a row, before the selection changes. */
|
|
229
|
+
onRowClick?: (row: Row, index: number, event: React.MouseEvent<HTMLTableRowElement>) => void;
|
|
230
|
+
/** Fires on a double-click, and on Enter. Opening the row is what this is. */
|
|
231
|
+
onRowActivate?: (row: Row, index: number) => void;
|
|
232
|
+
/**
|
|
233
|
+
* Whether the rows arrive all at once or a page at a time.
|
|
234
|
+
* @default 'scroll'
|
|
235
|
+
*/
|
|
236
|
+
paging?: DataTablePaging;
|
|
237
|
+
/** The current page, 1-based. Use with `onPageChange`. */
|
|
238
|
+
page?: number;
|
|
239
|
+
/** @default 1 */
|
|
240
|
+
defaultPage?: number;
|
|
241
|
+
onPageChange?: (page: number) => void;
|
|
242
|
+
/** How many rows a page holds. Use with `onPageSizeChange`. */
|
|
243
|
+
pageSize?: number;
|
|
244
|
+
/** @default 25 */
|
|
245
|
+
defaultPageSize?: number;
|
|
246
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
247
|
+
/**
|
|
248
|
+
* What the footer's page-size Select offers. An empty list drops the control.
|
|
249
|
+
* @default [10, 25, 50, 100]
|
|
250
|
+
*/
|
|
251
|
+
pageSizeOptions?: readonly number[];
|
|
252
|
+
/**
|
|
253
|
+
* The bar under the table: how many rows there are, how many are chosen, and
|
|
254
|
+
* the pages. On by default whenever `paging` is `pages`.
|
|
255
|
+
*/
|
|
256
|
+
footer?: boolean;
|
|
257
|
+
/**
|
|
258
|
+
* The query every searchable column is matched against. Use with
|
|
259
|
+
* `onSearchChange` for a controlled field.
|
|
260
|
+
*/
|
|
261
|
+
search?: string;
|
|
262
|
+
/** What it starts as, for an uncontrolled one. */
|
|
263
|
+
defaultSearch?: string;
|
|
264
|
+
onSearchChange?: (search: string) => void;
|
|
265
|
+
/** Draws the search field above the table. @default false */
|
|
266
|
+
searchable?: boolean;
|
|
267
|
+
/** Overrides the field's placeholder and its accessible name. */
|
|
268
|
+
searchPlaceholder?: string;
|
|
269
|
+
/**
|
|
270
|
+
* A filter of your own, applied after the search. Return `false` to drop a
|
|
271
|
+
* row.
|
|
272
|
+
*/
|
|
273
|
+
filter?: (row: Row, index: number) => boolean;
|
|
274
|
+
/** Content at the end of the bar the search field sits in. */
|
|
275
|
+
toolbar?: React.ReactNode;
|
|
276
|
+
/**
|
|
277
|
+
* Which stages the caller has already done — for a table whose rows come from
|
|
278
|
+
* a server a page at a time. `true` is all three.
|
|
279
|
+
*
|
|
280
|
+
* With `pages` in the list, `items` is taken to be one page and `rowCount`
|
|
281
|
+
* says how many rows there are in total.
|
|
282
|
+
* @default false
|
|
283
|
+
*/
|
|
284
|
+
manual?: boolean | readonly DataTableStage[];
|
|
285
|
+
/** How many rows there are in total, when the table is not doing the paging. */
|
|
286
|
+
rowCount?: number;
|
|
287
|
+
/**
|
|
288
|
+
* The language the table's own words are in — the search field's placeholder,
|
|
289
|
+
* the ticks' labels, the footer's count.
|
|
290
|
+
*
|
|
291
|
+
* It is also what the default sort compares strings with. Pass it whenever
|
|
292
|
+
* the markup is rendered on a server: without it the comparison follows the
|
|
293
|
+
* runtime's own locale, and a server that disagrees with the browser about
|
|
294
|
+
* that produces two different row orders for the same table.
|
|
295
|
+
*/
|
|
296
|
+
locale?: string;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* A table for a lot of rows.
|
|
300
|
+
*
|
|
301
|
+
* [Table](../display/table) draws a grid; this one is a place to work. The
|
|
302
|
+
* difference shows up in three decisions and everything else follows from them.
|
|
303
|
+
*
|
|
304
|
+
* **The rows are all the same height, and it is a number.** That is what lets
|
|
305
|
+
* the body render thirty rows out of two hundred thousand and still put the
|
|
306
|
+
* scrollbar in the right place — the offset of a row is its index times a
|
|
307
|
+
* constant, so nothing has to be measured on a scroll frame. It is also why
|
|
308
|
+
* cells truncate instead of wrapping: a cell that decides its own height would
|
|
309
|
+
* make every arithmetic answer above a guess.
|
|
310
|
+
*
|
|
311
|
+
* **Selecting is the file manager's, not the form's.** A click chooses a row
|
|
312
|
+
* and drops the rest, Ctrl adds one, Shift takes the run between, a drag takes
|
|
313
|
+
* the run under the pointer, and the arrow keys do all three with the same
|
|
314
|
+
* modifiers. Ticks are available and are not the default: a column of
|
|
315
|
+
* checkboxes says the task is choosing, and on most tables it is not.
|
|
316
|
+
*
|
|
317
|
+
* **The three stages are one pipeline, and the caller can take over any of
|
|
318
|
+
* them.** Search, then sort, then cut a page out — done here over `items` by
|
|
319
|
+
* default, and skipped stage by stage through `manual` for a table whose server
|
|
320
|
+
* is doing it. Both paths render the same, which is what stops a table that
|
|
321
|
+
* starts local and grows remote from becoming a second component.
|
|
322
|
+
*/
|
|
323
|
+
export declare function DataTable<Row>({ headers, items, getRowKey, variant, size, color, density, elevation, height, maxHeight, rowHeight: rowHeightProp, striped, hoverable, stickyHeader, caption, label, empty, virtual, overscan, sortable, sortMode, sort: sortProp, defaultSort, onSortChange, resizable, columnWidths, defaultColumnWidths, onColumnWidthsChange, selectionMode, selected, defaultSelected, onSelectedChange, checkboxes, onRowClick, onRowActivate, paging, page: pageProp, defaultPage, onPageChange, pageSize: pageSizeProp, defaultPageSize, onPageSizeChange, pageSizeOptions, footer, search: searchProp, defaultSearch, onSearchChange, searchable, searchPlaceholder, filter, toolbar, manual, rowCount, locale, className, style, ...boxProps }: DataTableProps<Row>): React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import*as r from"react";import{Box as a}from"../box/Box";import{Checkbox as l}from"../checkbox/Checkbox";import{Pagination as o}from"../pagination/Pagination";import{Select as s}from"../select/Select";import{TextField as i}from"../text-field/TextField";import{compareValues as c,dataHeaderHeights as u,dataRowHeights as d,dataTickWidths as p,defaultColumnWidth as m,keysBetween as h,minColumnWidth as f,nextSort as g,pageBounds as v,searchText as y,sortRows as b,virtualWindow as k}from"../../internal/data-table";import{fillMessage as w,useMessages as x}from"../../internal/i18n";import{ChevronIcon as C}from"../../internal/icons";import{controlTextLeadingClasses as S,cx as M,hasContent as N,metaTextClasses as K,paddingXValues as z,srOnlyClasses as $}from"../../internal/styles";const E=["[--n-row:transparent]","[transition:background-color_var(--neba-duration)_var(--neba-ease)]"].join(" "),_={"--n-stripe":"color-mix(in oklab, var(--neba-fg) 4%, transparent)"},R=["group/sort flex w-full min-w-0 cursor-pointer items-center gap-1","text-inherit [outline:none]","[transition:color_var(--neba-duration)_var(--neba-ease)]","hover:text-(--n-accent)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1","[&_svg]:pointer-events-none [&_svg]:size-[1.15em] [&_svg]:shrink-0"].join(" "),D=["absolute inset-y-0 z-10 w-2 cursor-col-resize select-none","end-0 translate-x-1/2 rtl:-translate-x-1/2","after:absolute after:inset-y-1 after:start-1/2 after:w-px","after:[background:transparent]","after:[transition:background_var(--neba-duration)_var(--neba-ease)]","hover:after:[background:var(--n-accent)]"].join(" ");function L(){return t("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[e("circle",{cx:"7.25",cy:"7.25",r:"4.75",stroke:"currentColor",strokeWidth:"1.5"}),e("path",{d:"m10.75 10.75 2.75 2.75",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]})}function P(e){return"number"==typeof e?`${e}px`:e}export function DataTable({headers:A,items:T,getRowKey:j,variant:H="outline",size:B="sm",color:I="primary",density:W="compact",elevation:F=0,height:O,maxHeight:q,rowHeight:U,striped:X=!1,hoverable:Y=!0,stickyHeader:V=!0,caption:G,label:J,empty:Q,virtual:Z=!0,overscan:ee=8,sortable:te=!1,sortMode:ne="single",sort:re,defaultSort:ae,onSortChange:le,resizable:oe=!1,columnWidths:se,defaultColumnWidths:ie,onColumnWidthsChange:ce,selectionMode:ue="none",selected:de,defaultSelected:pe,onSelectedChange:me,checkboxes:he=!1,onRowClick:fe,onRowActivate:ge,paging:ve="scroll",page:ye,defaultPage:be=1,onPageChange:ke,pageSize:we,defaultPageSize:xe=25,onPageSizeChange:Ce,pageSizeOptions:Se=[10,25,50,100],footer:Me,search:Ne,defaultSearch:Ke,onSearchChange:ze,searchable:$e=!1,searchPlaceholder:Ee,filter:_e,toolbar:Re,manual:De=!1,rowCount:Le,locale:Pe,className:Ae,style:Te,...je}){const He=x(Pe),Be=r.useId(),Ie=U??d[W][B],We=u[W][B],Fe=z[W][B],Oe=r.useMemo(()=>new Set(!0===De?["sort","filter","pages"]:De||[]),[De]),qe=r.useMemo(()=>A.filter(e=>!e.hidden),[A]),Ue=qe.some(e=>void 0!==e.group),Xe="none"!==ue,Ye="multiple"===ue,Ve=Xe&&he,Ge=r.useMemo(()=>T.map((e,t)=>{const n=j?j(e,t):t;return{row:e,identity:n,key:String(n),origin:t}}),[T,j]),[Je,Qe]=r.useState(Ke??""),Ze=(Ne??Je).trim(),et=r.useMemo(()=>{if(Oe.has("filter"))return Ge;const e=y(Ze),t=qe.filter(e=>!1!==e.searchable);let n=Ge;return""!==e&&t.length>0&&(n=n.filter(n=>t.some(t=>{const r=t.value?t.value(n.row):n.row[t.key];return y(r).includes(e)}))),_e?n.filter(e=>_e(e.row,e.origin)):n},[Ge,qe,Ze,_e,Oe]),tt=r.useMemo(()=>new Intl.Collator(Pe,{numeric:!0,sensitivity:"base"}),[Pe]),[nt,rt]=r.useState(ae??[]),at=re??nt,lt=r.useMemo(()=>Oe.has("sort")?et:b(et,at,e=>{const t=qe.find(t=>t.key===e);if(!t)return null;if(t.compare)return(e,n)=>t.compare(e.row,n.row);const n=t.value?t.value:e=>e[t.key];return(e,t)=>c(n(e.row),n(t.row),tt)}),[et,at,qe,tt,Oe]),[ot,st]=r.useState(be),[it,ct]=r.useState(xe),ut=we??it,dt=Oe.has("pages")?Le??lt.length:lt.length,pt=v(dt,ye??ot,ut),mt=r.useMemo(()=>"pages"!==ve||Oe.has("pages")?lt:lt.slice(pt.start,pt.end),[lt,ve,Oe,pt.start,pt.end]),ht="pages"===ve?pt.start:0,ft=r.useMemo(()=>mt.map(e=>e.key),[mt]),gt=r.useMemo(()=>new Map(Ge.map(e=>[e.key,e])),[Ge]),[vt,yt]=r.useState(pe??[]),bt=de??vt,kt=r.useMemo(()=>new Set(bt.map(String)),[bt]),[wt,xt]=r.useState(null),Ct=r.useRef(null),St=r.useRef({paged:mt,pagedKeys:ft,byKey:gt,selectedKeys:kt,multiple:Ye});St.current={paged:mt,pagedKeys:ft,byKey:gt,selectedKeys:kt,multiple:Ye};const Mt=r.useCallback(e=>{const t=[],n=[];for(const r of e){const e=St.current.byKey.get(r);e&&(t.push(e.identity),n.push(e.row))}void 0===de&&yt(t),me?.(t,n)},[de,me]),Nt=r.useCallback(e=>{Ct.current=e,Mt([e])},[Mt]),Kt=r.useCallback(e=>{const t=St.current.selectedKeys,n=new Set(t);n.has(e)?n.delete(e):n.add(e),Ct.current=e,Mt([...n])},[Mt]),zt=r.useCallback((e,t)=>{const n=St.current.pagedKeys,r=Ct.current??n[0];if(void 0===r)return;const a=h(n,r,e);0!==a.length&&Mt(t?[...new Set([...St.current.selectedKeys,...a])]:a)},[Mt]),$t=r.useRef(null),Et=r.useRef(null),_t=r.useRef(null),[Rt,Dt]=r.useState(0),[Lt,Pt]=r.useState(0),At=void 0!==O||void 0!==q,Tt=Z&&At&&mt.length>0;r.useLayoutEffect(()=>{const e=$t.current;if(!e||!Tt)return;const t=new ResizeObserver(([e])=>{Dt(e.contentRect.height)});return t.observe(e),Dt(e.clientHeight),()=>t.disconnect()},[Tt]);const jt=r.useCallback(e=>{if(!Tt)return;const t=Math.floor(e.currentTarget.scrollTop/Ie)*Ie;Pt(e=>e===t?e:t)},[Tt,Ie]),Ht=Tt?k(Lt,Rt,Ie,mt.length,ee):{start:0,end:mt.length,before:0,after:0},Bt=mt.slice(Ht.start,Ht.end),It=Xe&&null!==wt&&Bt.some(e=>e.key===wt),[Wt,Ft]=r.useState(ie??{}),Ot=se??Wt,qt=r.useCallback(e=>{void 0===se&&Ft(e),ce?.(e)},[se,ce]),Ut=r.useRef(new Map),Xt=r.useCallback(e=>{const t=$t.current;if(!t||!At)return;const n=V?We*(Ue?2:1):0,r=e*Ie;r<t.scrollTop+n?t.scrollTop=Math.max(0,r-n):r+Ie>t.scrollTop+t.clientHeight&&(t.scrollTop=r+Ie-t.clientHeight)},[At,V,We,Ue,Ie]),Yt=(e,t)=>{const n=St.current.paged,r=Math.min(Math.max(e,0),n.length-1),a=n[r];a&&(t.preventDefault(),xt(a.key),Xt(r),t.shiftKey&&St.current.multiple?zt(a.key,!1):t.ctrlKey||t.metaKey||Nt(a.key))};const Vt=r.useCallback(e=>{const t=Et.current,n=St.current.paged;if(!t||0===n.length)return null;const r=t.getBoundingClientRect().top,a=Math.floor((e-r)/Ie);return Math.min(Math.max(a,0),n.length-1)},[Ie]),Gt=r.useRef(null),Jt=r.useCallback(e=>{const t=Vt(e),n=null===t?void 0:St.current.paged[t];n&&(xt(n.key),zt(n.key,!1))},[Vt,zt]),Qt=r.useRef(Jt);Qt.current=Jt;function Zt(e,t){if(Xe&&!t.target.closest('button, a, input, select, textarea, [role="button"]'))if(_t.current?.focus({preventScroll:!0}),xt(e.key),2!==t.button){if(0===t.button)return t.shiftKey&&Ye?(t.preventDefault(),void zt(e.key,t.ctrlKey||t.metaKey)):void((t.ctrlKey||t.metaKey)&&Ye?Kt(e.key):(Nt(e.key),Ye&&(e=>{if(Gt.current)return;const t=e=>{const t=Gt.current,r=$t.current;if(!t)return;if(t.y=e.clientY,Qt.current(t.y),!r||!At)return;const a=r.getBoundingClientRect(),l=a.top+Ie-t.y,o=t.y-(a.bottom-Ie);t.speed=l>0?-Math.min(l,40):o>0?Math.min(o,40):0,0!==t.speed&&null===t.frame&&(t.frame=requestAnimationFrame(n))},n=()=>{const e=Gt.current,t=$t.current;e&&t&&0!==e.speed?(t.scrollTop+=e.speed,Qt.current(e.y),e.frame=requestAnimationFrame(n)):e&&(e.frame=null)},r=()=>{const e=Gt.current;null!=e?.frame&&cancelAnimationFrame(e.frame),Gt.current=null,window.removeEventListener("pointermove",t),window.removeEventListener("pointerup",r),window.removeEventListener("pointercancel",r)};Gt.current={y:e,speed:0,frame:null,stop:r},window.addEventListener("pointermove",t),window.addEventListener("pointerup",r),window.addEventListener("pointercancel",r)})(t.clientY)))}else St.current.selectedKeys.has(e.key)||Nt(e.key)}r.useEffect(()=>()=>Gt.current?.stop(),[]);const en=r.useMemo(()=>ft.reduce((e,t)=>kt.has(t)?e+1:e,0),[ft,kt]),tn=ft.length>0&&en===ft.length,nn=p[B],rn=e=>Ot[e.key]??e.width,an=(Ve?nn:0)+qe.reduce((e,t)=>e+(rn(t)??f),0),ln=qe.length>0&&qe.every(e=>void 0!==rn(e)),on=qe.length+(Ve?1:0)+(ln?1:0),sn=r.useMemo(()=>{const e=[];return qe.forEach((t,n)=>{const r=e[e.length-1];r&&void 0!==r.label&&r.label===t.group?r.span+=1:e.push({label:t.group,span:1,from:n})}),e},[qe]),cn={padding:`0 ${Fe}`,borderBottom:"1px solid var(--n-line)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},un={...cn,height:`${We}px`,backgroundColor:"var(--n-panel-press)"},dn="odd"===X?0:1,pn=r.useMemo(()=>new Intl.NumberFormat(Pe),[Pe]),mn=Me??"pages"===ve,hn=w(He.table.range,{start:pn.format(0===dt?0:("pages"===ve?pt.start:0)+1),end:pn.format("pages"===ve?pt.end:dt),total:pn.format(dt)}),fn=e=>{void 0===ye&&st(e),ke?.(e)},gn=(n,r,a)=>{const l=n.sortable??te,o=n.resizable??oe,s=(i=n.key,at.find(e=>e.key===i));var i;const c=s?at.findIndex(e=>e.key===n.key)+1:0,u=n.headerAlign??n.align??"start";return t("th",{ref:e=>{e?Ut.current.set(n.key,e):Ut.current.delete(n.key)},scope:"col",rowSpan:a,"aria-sort":s?"asc"===s.direction?"ascending":"descending":void 0,className:M("relative font-semibold select-none",s?"text-(--n-accent)":"text-(--neba-muted-fg)",V?"sticky z-20 [backdrop-filter:var(--neba-blur)]":""),style:{...un,top:V?2!==a&&Ue?We:0:void 0,textAlign:u},children:[l?t("button",{type:"button",className:M(R,"end"===u?"justify-end":"center"===u?"justify-center":"justify-start"),onClick:e=>((e,t)=>{const n=g(at,e,t&&"multiple"===ne);void 0===re&&rt(n),le?.(n)})(n.key,e.shiftKey),children:[e("span",{className:"min-w-0 truncate",children:n.label??n.key}),e("span",{"aria-hidden":"true",className:M("flex items-center","desc"===s?.direction?"rotate-0":"rotate-180",s?"":"text-transparent group-hover/sort:text-inherit group-focus-visible/sort:text-inherit"),children:e(C,{})}),c>1?e("span",{"aria-hidden":"true",className:"text-[0.85em] tabular-nums",children:c}):null]}):e("span",{className:"block truncate",children:n.label??n.key}),o&&r<qe.length-1?e("span",{"aria-hidden":"true",className:D,onPointerDown:e=>((e,t)=>{t.preventDefault(),t.stopPropagation();const n=t.currentTarget,r={...Ot};for(const e of qe){const t=Ut.current.get(e.key);t&&void 0===r[e.key]&&(r[e.key]=Math.round(t.getBoundingClientRect().width))}const a="rtl"===getComputedStyle(n).direction,l=t.clientX,o=r[e]??m,s=qe.find(t=>t.key===e)?.minWidth??f;n.setPointerCapture(t.pointerId);const i=t=>{const n=(t.clientX-l)*(a?-1:1);qt({...r,[e]:Math.max(s,Math.round(o+n))})},c=()=>{n.removeEventListener("pointermove",i),n.removeEventListener("pointerup",c),n.removeEventListener("pointercancel",c)};n.addEventListener("pointermove",i),n.addEventListener("pointerup",c),n.addEventListener("pointercancel",c)})(n.key,e),onDoubleClick:()=>(e=>{const t={...Ot};delete t[e],qt(t)})(n.key)}):null]},n.key)},vn=t=>e("span",{className:"flex items-center justify-center",children:t}),yn=t=>e("td",{role:Xe?"gridcell":void 0,style:{...cn,padding:0,overflow:"visible"},children:vn(e(l,{size:B,color:I,checked:kt.has(t.key),"aria-label":He.table.selectRow,onCheckedChange:()=>{Ye?Kt(t.key):Nt(t.key)}}))}),bn=Ye?vn(e(l,{size:B,color:I,checked:tn,indeterminate:en>0&&!tn,"aria-label":He.table.selectAll,onCheckedChange:()=>{if(tn){const e=new Set(ft);Mt([...kt].filter(t=>!e.has(t)))}else Mt([...new Set([...kt,...ft])])}})):null,kn=ln?e("th",{"aria-hidden":"true",className:M(V?"sticky top-0 z-20 [backdrop-filter:var(--neba-blur)]":""),style:{...un,padding:0}}):null,wn=(t,n)=>n>0?e("tr",{"aria-hidden":"true",style:{height:`${n}px`},children:e("td",{colSpan:on,style:{padding:0,border:0}})},t):null;return t(a,{variant:H,size:B,color:I,density:W,elevation:F,padded:!1,className:M("flex flex-col overflow-hidden",Xe?"has-[:focus-visible]:[outline:2px_solid_var(--n-ring)] has-[:focus-visible]:outline-offset-2":"",Ae),style:{..._,...Te},...je,children:[$e||N(Re)?t("div",{className:"flex items-center gap-2",style:{padding:`${Fe} ${Fe}`,borderBottom:"1px solid var(--n-line)"},children:[$e?e(i,{size:B,color:I,density:W,variant:"outline",type:"search",className:"w-full max-w-64",startIcon:e(L,{}),placeholder:Ee??He.table.search,"aria-label":Ee??He.table.search,value:Ne??Je,onChange:e=>{const t=e.target.value;void 0===Ne&&Qe(t),fn(1),ze?.(t)}}):null,N(Re)?e("div",{className:"ms-auto flex items-center gap-2",children:Re}):null]}):null,e("div",{ref:$t,className:"min-h-0 flex-auto overflow-auto overscroll-contain",style:{height:P(O),maxHeight:P(q)},onScroll:jt,children:t("table",{ref:_t,role:Xe?"grid":void 0,"aria-label":J,"aria-multiselectable":Ye||void 0,"aria-rowcount":Tt?mt.length+1:void 0,"aria-activedescendant":It?`${Be}-${wt}`:void 0,tabIndex:Xe?0:void 0,className:M("w-full text-start [outline:none]",S[B],"text-(--neba-fg)",Xe?"select-none":""),style:{tableLayout:"fixed",borderCollapse:"separate",borderSpacing:0,minWidth:`${an}px`},onKeyDown:function(e){if(!Xe||e.target!==e.currentTarget)return;const t=St.current.paged;if(0===t.length)return;const n=null===wt?-1:St.current.pagedKeys.indexOf(wt),r=Math.max(1,Math.floor((Rt||10*Ie)/Ie)-1);switch(e.key){case"ArrowDown":Yt(n+1,e);break;case"ArrowUp":Yt(-1===n?0:n-1,e);break;case"Home":Yt(0,e);break;case"End":Yt(t.length-1,e);break;case"PageDown":Yt(-1===n?0:n+r,e);break;case"PageUp":Yt(-1===n?0:n-r,e);break;case" ":-1!==n&&(e.preventDefault(),(e.ctrlKey||e.metaKey)&&Ye?Kt(t[n].key):Nt(t[n].key));break;case"a":case"A":(e.ctrlKey||e.metaKey)&&Ye&&(e.preventDefault(),Mt(St.current.pagedKeys));break;case"Escape":e.preventDefault(),Mt([]);break;case"Enter":-1!==n&&ge&&(e.preventDefault(),ge(t[n].row,ht+n))}},children:[G?e("caption",{className:M(K[B],"text-(--neba-muted-fg)"),style:{padding:`0.5rem ${Fe}`,textAlign:"start"},children:G}):null,t("colgroup",{children:[Ve?e("col",{style:{width:`${nn}px`}}):null,qe.map(t=>{const n=rn(t);return e("col",{style:void 0===n?void 0:{width:`${n}px`}},t.key)}),ln?e("col",{}):null]}),t("thead",{children:[Ue?t("tr",{style:{height:`${We}px`},children:[Ve?e("th",{scope:"col",rowSpan:2,className:M(V?"sticky top-0 z-20 [backdrop-filter:var(--neba-blur)]":""),style:{...un,padding:0,overflow:"visible"},children:bn}):null,sn.map(t=>void 0===t.label?gn(qe[t.from],t.from,2):e("th",{scope:"colgroup",colSpan:t.span,className:M("font-semibold text-(--neba-muted-fg) select-none",V?"sticky top-0 z-20 [backdrop-filter:var(--neba-blur)]":""),style:{...un,textAlign:"center"},children:t.label},`group-${t.from}`)),ln?r.cloneElement(kn,{rowSpan:2}):null]}):null,t("tr",{style:{height:`${We}px`},children:[Ve&&!Ue?e("th",{scope:"col",className:M(V?"sticky top-0 z-20 [backdrop-filter:var(--neba-blur)]":""),style:{...un,padding:0,overflow:"visible"},children:bn}):null,qe.map((e,t)=>Ue&&void 0===e.group?null:gn(e,t)),ln&&!Ue?kn:null]})]}),e("tbody",{ref:Et,children:0===mt.length?e("tr",{children:e("td",{colSpan:on,className:"text-(--neba-muted-fg)",style:{padding:`2rem ${Fe}`,textAlign:"center"},children:Q??He.empty.title})}):t(n,{children:[wn("before",Ht.before),Bt.map((n,r)=>{const a=Ht.start+r,l=kt.has(n.key),o=wt===n.key;return t("tr",{id:`${Be}-${n.key}`,"aria-selected":Xe?l:void 0,"aria-rowindex":Tt?a+2:void 0,"data-neba-row":n.key,className:M(E,l?"[--n-row:var(--n-soft-press)]":!1!==X&&a%2===dn?"[--n-row:var(--n-stripe)]":"",!l&&Y?"hover:[--n-row:var(--n-soft)]":"",o&&Xe?"[box-shadow:inset_0_0_0_1px_var(--n-ring)]":"",Xe||fe?"cursor-default":""),style:{height:`${Ie}px`,backgroundColor:"var(--n-row)"},onPointerDown:e=>Zt(n,e),onClick:e=>fe?.(n.row,ht+a,e),onDoubleClick:()=>ge?.(n.row,ht+a),children:[Ve?yn(n):null,qe.map(t=>e("td",{role:Xe?"gridcell":void 0,style:{...cn,textAlign:t.align??"start"},children:t.render?t.render(n.row,ht+a):n.row[t.key]},t.key)),ln?e("td",{"aria-hidden":"true",style:{...cn,padding:0}}):null]},n.key)}),wn("after",Ht.after)]})})]})}),mn?t("div",{className:M("flex flex-wrap items-center gap-3",K[B]),style:{padding:`0.375rem ${Fe}`,borderTop:"1px solid var(--n-line)"},children:[e("span",{className:"text-(--neba-muted-fg) tabular-nums",children:hn}),Xe&&kt.size>0?e("span",{className:"text-(--n-accent) tabular-nums",children:w(He.table.selected,{count:pn.format(kt.size)})}):null,t("div",{className:"ms-auto flex items-center gap-2",children:["pages"===ve&&Se.length>0?e(n,{children:e(s,{size:B,color:I,density:W,variant:"outline",label:He.table.rowsPerPage,items:Se.map(e=>({value:e})),value:ut,onValueChange:e=>{const t=Number(e);void 0===we&&ct(t),fn(Math.floor(pt.start/t)+1),Ce?.(t)}})}):null,"pages"===ve?e(o,{size:B,color:I,count:pt.pages,page:pt.page,siblingCount:0,onPageChange:fn}):null]})]}):null,!mn&&Tt?e("span",{className:$,"aria-live":"polite",children:hn}):null]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{DataTable}from"./DataTable";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Dialog as BaseUIDialog } from '@base-ui/react/dialog';
|
|
3
|
+
import type { NebaSide, NebaStyleProps } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* How the panel relates to the page.
|
|
6
|
+
*
|
|
7
|
+
* - `overlay` — it is opened, it floats over the page on a scrim, it holds the
|
|
8
|
+
* focus, and it is dismissed. The navigation drawer behind a hamburger, the
|
|
9
|
+
* filter panel beside a table.
|
|
10
|
+
* - `inline` — it is part of the layout and the page is laid out around it. No
|
|
11
|
+
* scrim, no portal, no focus trap, nothing to dismiss. The sidebar that is
|
|
12
|
+
* simply there.
|
|
13
|
+
*
|
|
14
|
+
* A separate axis from `variant`, which already means the weight of a surface
|
|
15
|
+
* across the whole library and would be a second spelling of nothing.
|
|
16
|
+
*/
|
|
17
|
+
export type NebaDrawerMode = 'overlay' | 'inline';
|
|
18
|
+
/**
|
|
19
|
+
* A drawer takes `size`, `color` and `density` and stops there.
|
|
20
|
+
*
|
|
21
|
+
* There is no `variant`, for Dialog's reason: the three weights answer "how
|
|
22
|
+
* much does this surface assert itself against the page", and a panel that has
|
|
23
|
+
* taken an edge of the window has answered it. There is no `elevation` either —
|
|
24
|
+
* an `overlay` drawer floats and carries a shadow at level 3, an `inline` one is
|
|
25
|
+
* part of the layout and carries none, and neither is a decision worth offering.
|
|
26
|
+
*/
|
|
27
|
+
export interface DrawerProps extends Pick<NebaStyleProps, 'size' | 'color' | 'density'> {
|
|
28
|
+
/**
|
|
29
|
+
* Which edge the panel is attached to. Physical rather than logical, the way
|
|
30
|
+
* `NebaSide` is everywhere: a drawer along the top of the window is along the
|
|
31
|
+
* top in every writing direction.
|
|
32
|
+
* @default 'left'
|
|
33
|
+
*/
|
|
34
|
+
side?: NebaSide;
|
|
35
|
+
/** @default 'overlay' */
|
|
36
|
+
mode?: NebaDrawerMode;
|
|
37
|
+
/** The drawer is shown. Use with `onOpenChange` for a controlled drawer. */
|
|
38
|
+
open?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the drawer starts open, for an uncontrolled one.
|
|
41
|
+
*
|
|
42
|
+
* Defaults to `false` in `overlay` mode and `true` in `inline` mode, because
|
|
43
|
+
* a fixed sidebar that had to be opened before it appeared would not be a
|
|
44
|
+
* fixed sidebar.
|
|
45
|
+
*/
|
|
46
|
+
defaultOpen?: boolean;
|
|
47
|
+
onOpenChange?: (open: boolean) => void;
|
|
48
|
+
/**
|
|
49
|
+
* The element that opens the drawer, wired up by Base UI.
|
|
50
|
+
*
|
|
51
|
+
* `overlay` only. An `inline` drawer is not opened — it is in the layout —
|
|
52
|
+
* so a trigger there would have nothing to do and is not rendered.
|
|
53
|
+
*/
|
|
54
|
+
trigger?: React.ReactElement;
|
|
55
|
+
/** The heading. Rendered as the element that names the drawer. */
|
|
56
|
+
title?: React.ReactNode;
|
|
57
|
+
/** A line under the title, and the drawer's accessible description. */
|
|
58
|
+
description?: React.ReactNode;
|
|
59
|
+
/**
|
|
60
|
+
* The bottom row, held against the foot of the panel while the body scrolls.
|
|
61
|
+
* Laid out end-aligned, so a pair of buttons needs no wrapper of its own —
|
|
62
|
+
* and `DrawerClose` is what makes one of them dismiss.
|
|
63
|
+
*/
|
|
64
|
+
actions?: React.ReactNode;
|
|
65
|
+
/**
|
|
66
|
+
* Draws a hairline between the header, the body and the actions instead of
|
|
67
|
+
* separating them with space. Worth turning on the moment the body scrolls:
|
|
68
|
+
* the lines are what say the header stayed put.
|
|
69
|
+
* @default false
|
|
70
|
+
*/
|
|
71
|
+
dividers?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Shows the × in the corner. On in `overlay` mode, where the panel has taken
|
|
74
|
+
* the page and the way out should not have to be remembered; off in `inline`
|
|
75
|
+
* mode, where a × that closes a fixed sidebar with nothing to reopen it is a
|
|
76
|
+
* one-way door.
|
|
77
|
+
*/
|
|
78
|
+
showClose?: boolean;
|
|
79
|
+
/** Accessible name of the × button. */
|
|
80
|
+
closeLabel?: string;
|
|
81
|
+
/**
|
|
82
|
+
* How far the panel reaches in from its edge: a **width** for `left` and
|
|
83
|
+
* `right`, a **height** for `top` and `bottom`. Numbers are pixels.
|
|
84
|
+
*
|
|
85
|
+
* Left alone, a side panel takes the width its `size` implies and a top or
|
|
86
|
+
* bottom panel is as tall as what is in it, up to 85% of the window.
|
|
87
|
+
*/
|
|
88
|
+
extent?: number | string;
|
|
89
|
+
/**
|
|
90
|
+
* Rounds the two corners on the edge that faces the page — the top and bottom
|
|
91
|
+
* of a side panel, the inner pair of a top or bottom one. The corners against
|
|
92
|
+
* the window edge are always square, because a corner cut off something that
|
|
93
|
+
* has no visible end is a corner cut off nothing.
|
|
94
|
+
* @default true
|
|
95
|
+
*/
|
|
96
|
+
rounded?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Whether the page behind is taken away. `'trap-focus'` keeps the page
|
|
99
|
+
* scrollable and clickable while still holding focus inside. `overlay` only.
|
|
100
|
+
* @default true
|
|
101
|
+
*/
|
|
102
|
+
modal?: boolean | 'trap-focus';
|
|
103
|
+
/**
|
|
104
|
+
* Whether pressing Escape or clicking the scrim closes the drawer. Turn it off
|
|
105
|
+
* for the drawer that has to be answered — and then give it actions that
|
|
106
|
+
* answer it, because there will be no other way out. `overlay` only.
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
109
|
+
dismissible?: boolean;
|
|
110
|
+
/** The body. */
|
|
111
|
+
children?: React.ReactNode;
|
|
112
|
+
className?: string;
|
|
113
|
+
style?: React.CSSProperties;
|
|
114
|
+
}
|
|
115
|
+
export type DrawerCloseProps = React.ComponentPropsWithoutRef<typeof BaseUIDialog.Close>;
|
|
116
|
+
/**
|
|
117
|
+
* Closes the drawer it is inside.
|
|
118
|
+
*
|
|
119
|
+
* Exported for `DialogClose`'s reason: an uncontrolled drawer has no `setOpen`
|
|
120
|
+
* for its Cancel button to call. It is an `overlay` drawer's button — an
|
|
121
|
+
* `inline` drawer is not a Base UI dialog and has nothing for this to talk to.
|
|
122
|
+
*
|
|
123
|
+
* `render` is Base UI's own escape hatch, so a real Neba button dismisses:
|
|
124
|
+
* `<DrawerClose render={<Button variant="text">Cancel</Button>} />`.
|
|
125
|
+
*/
|
|
126
|
+
export declare const DrawerClose: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").AlertDialogCloseProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
127
|
+
/**
|
|
128
|
+
* A panel attached to one edge of the window.
|
|
129
|
+
*
|
|
130
|
+
* Two things in one component, because they are the same panel: `overlay` is the
|
|
131
|
+
* drawer you open — a scrim, a focus trap, Escape — and `inline` is the drawer
|
|
132
|
+
* that is simply part of the page. Everything else about them is identical,
|
|
133
|
+
* which is exactly why they should not be two components a caller has to switch
|
|
134
|
+
* between when a sidebar becomes a hamburger at a breakpoint.
|
|
135
|
+
*
|
|
136
|
+
* The sections are props rather than compound sub-components, as on Card and
|
|
137
|
+
* Dialog: the arrangement is fixed — heading, description, body, actions — and
|
|
138
|
+
* what a caller wants to decide is what goes in each slot. The body is the only
|
|
139
|
+
* part that scrolls, so the heading and the actions stay put.
|
|
140
|
+
*
|
|
141
|
+
* In `overlay` mode Base UI owns everything hard about it: the focus trap, the
|
|
142
|
+
* scroll lock, the `aria-labelledby` / `aria-describedby` wiring, restoring
|
|
143
|
+
* focus to the trigger, and the inert page behind.
|
|
144
|
+
*/
|
|
145
|
+
export declare function Drawer({ side, mode, size, color, density, open, defaultOpen, onOpenChange, trigger, title, description, actions, dividers, showClose, closeLabel, extent, rounded, modal, dismissible, className, style, children }: DrawerProps): React.JSX.Element | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r,Fragment as a}from"react/jsx-runtime";import{Dialog as l}from"@base-ui/react/dialog";import{boxPaddingXClasses as n,boxPaddingYClasses as o}from"../box/Box";import{CloseIcon as s}from"../../internal/icons";import{hasContent as i,metaTextClasses as d,sheetBodyClasses as t,sheetHeaderGapClasses as u,sheetSectionGapClasses as b,sheetTitleClasses as m,surfaceClasses as c,surfaceSlots as f}from"../../internal/styles";const x={xs:"w-56",sm:"w-64",md:"w-80",lg:"w-96",xl:"w-[28rem]"},p={left:{xs:"rounded-r-(--neba-radius-xs)",sm:"rounded-r-(--neba-radius-sm)",md:"rounded-r-(--neba-radius-md)",lg:"rounded-r-(--neba-radius-lg)",xl:"rounded-r-(--neba-radius-xl)"},right:{xs:"rounded-l-(--neba-radius-xs)",sm:"rounded-l-(--neba-radius-sm)",md:"rounded-l-(--neba-radius-md)",lg:"rounded-l-(--neba-radius-lg)",xl:"rounded-l-(--neba-radius-xl)"},top:{xs:"rounded-b-(--neba-radius-xs)",sm:"rounded-b-(--neba-radius-sm)",md:"rounded-b-(--neba-radius-md)",lg:"rounded-b-(--neba-radius-lg)",xl:"rounded-b-(--neba-radius-xl)"},bottom:{xs:"rounded-t-(--neba-radius-xs)",sm:"rounded-t-(--neba-radius-sm)",md:"rounded-t-(--neba-radius-md)",lg:"rounded-t-(--neba-radius-lg)",xl:"rounded-t-(--neba-radius-xl)"}},g={left:"border-r",right:"border-l",top:"border-b",bottom:"border-t"},h={left:"flex-row justify-start",right:"flex-row justify-end",top:"flex-col justify-start",bottom:"flex-col justify-end"},v=[c,"relative flex flex-col overflow-hidden","text-(--neba-fg) bg-(--n-panel-press)","[border-color:var(--n-line)]","[outline:none]"].join(" "),y=["[transition:opacity_var(--neba-duration)_var(--neba-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),w=["fixed inset-0 z-50 bg-(--neba-scrim)","[backdrop-filter:blur(2px)]",y].join(" "),j="border-t [border-color:var(--n-line)]",N=["flex size-[1.6em] shrink-0 cursor-pointer items-center justify-center","rounded-full text-(--neba-muted-fg)","[&_svg]:size-[1.1em] [&_svg]:shrink-0","[transition:background-color_var(--neba-duration)_var(--neba-ease),color_var(--neba-duration)_var(--neba-ease)]","hover:bg-(--n-soft) hover:text-(--neba-fg)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"].join(" ");export const DrawerClose=l.Close;export function Drawer({side:c="left",mode:$="overlay",size:_="md",color:k="primary",density:C="default",open:z,defaultOpen:B,onOpenChange:D,trigger:O,title:P,description:T,actions:F,dividers:L=!1,showClose:R,closeLabel:V="Close",extent:q,rounded:A=!0,modal:E=!0,dismissible:G=!0,className:H,style:I,children:J}){const K="overlay"===$,M="left"===c||"right"===c,Q=R??K,S=n[C][_],U=o[C][_],W=L?`${S} ${U}`:S,X=i(P)||i(T),Y=i(F),Z=void 0===q?null:{[M?"width":"height"]:"number"==typeof q?`${q}px`:q},ee=[v,t[_],g[c],A?p[c][_]:"",K?"[box-shadow:var(--neba-shadow-3),var(--neba-plate-glass)]":"[box-shadow:var(--neba-plate-glass)]",K?y:"",M?`h-full max-w-full ${void 0===q?x[_]:""}`:"w-full "+(void 0===q?"max-h-[85%]":""),L?"":`${U} ${b[_]}`,H??""].filter(Boolean).join(" "),re=K?l.Title:"h2",ae=K?l.Description:"p",le=r(a,{children:[X||Q?r("div",{className:`flex shrink-0 items-start gap-3 ${W}`,children:[r("div",{className:`flex min-w-0 flex-1 flex-col ${u[_]}`,children:[i(P)?e(re,{className:`m-0 font-semibold ${m[_]}`,children:P}):null,i(T)?e(ae,{className:`m-0 text-(--neba-muted-fg) ${d[_]}`,children:T}):null]}),Q?K?e(l.Close,{"aria-label":V,className:N,children:e(s,{})}):e("button",{type:"button","aria-label":V,className:N,onClick:()=>D?.(!1),children:e(s,{})}):null]}):null,i(J)?e("div",{className:["min-h-0 flex-1 overflow-y-auto overscroll-contain",W,L&&(X||Q)?j:"",L?"":"py-1 -my-1"].filter(Boolean).join(" "),children:J}):null,Y?e("div",{className:["flex shrink-0 flex-wrap items-center justify-end gap-2",W,L?j:""].filter(Boolean).join(" "),children:F}):null]});return K?r(l.Root,{open:z,defaultOpen:B,modal:E,disablePointerDismissal:!G,onOpenChange:(e,r)=>{G||e||"escape-key"!==r.reason?D?.(e):r.cancel()},children:[O?e(l.Trigger,{render:O}):null,r(l.Portal,{children:[e(l.Backdrop,{className:`neba-portal ${w}`}),e(l.Viewport,{className:`neba-portal fixed inset-0 z-50 flex ${h[c]}`,children:e(l.Popup,{className:ee,style:{...f(k,3),...Z,...I},children:le})})]})]}):z??B??1?e("div",{className:ee,style:{...f(k,0),...Z,...I},children:le}):null}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Drawer,DrawerClose}from"./Drawer";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
import type { NebaElevation, NebaStyleProps, NebaTransition } from '../../types';
|
|
4
|
+
export interface EmptyProps extends NebaStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title'> {
|
|
5
|
+
/**
|
|
6
|
+
* The headline. Defaults to the `locale`'s way of saying that there is
|
|
7
|
+
* nothing here; pass `false` for a state that is a glyph and a sentence with
|
|
8
|
+
* no heading over them.
|
|
9
|
+
*/
|
|
10
|
+
title?: React.ReactNode | false;
|
|
11
|
+
/**
|
|
12
|
+
* The glyph above the headline. Defaults to the empty tray; pass `false` to
|
|
13
|
+
* drop it, or a node — an illustration, a brand mark, an icon from any set —
|
|
14
|
+
* to replace it. An `svg` is sized off the `size` ladder; anything else is
|
|
15
|
+
* left at whatever size it came in at.
|
|
16
|
+
*/
|
|
17
|
+
icon?: React.ReactNode | false;
|
|
18
|
+
/**
|
|
19
|
+
* What to do about it, under the text: a "Create the first one" button, a
|
|
20
|
+
* "Clear filters" link. Several of them sit in a row and wrap together.
|
|
21
|
+
*/
|
|
22
|
+
action?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Which language the default headline is written in — a BCP 47 tag. Ignored
|
|
25
|
+
* once `title` is given, and unsupported tags fall back to English.
|
|
26
|
+
* @default 'en'
|
|
27
|
+
*/
|
|
28
|
+
locale?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Drop shadow depth. `0` (the default) is flat, and it is almost always
|
|
31
|
+
* right: an empty state is a hole in a surface that already exists rather
|
|
32
|
+
* than a sheet of its own.
|
|
33
|
+
* @default 0
|
|
34
|
+
*/
|
|
35
|
+
elevation?: NebaElevation;
|
|
36
|
+
/**
|
|
37
|
+
* An entrance animation, run once on mount: `transition="fade"` for a list
|
|
38
|
+
* that has just come back with nothing. For a trigger or a replay, wrap it in
|
|
39
|
+
* an `Animate*` component instead.
|
|
40
|
+
*/
|
|
41
|
+
transition?: NebaTransition;
|
|
42
|
+
/** Renders something other than a `<div>`: `render={<td colSpan={5} />}`. */
|
|
43
|
+
render?: useRender.RenderProp;
|
|
44
|
+
/** The sentence under the headline: why it is empty, or what to do next. */
|
|
45
|
+
children?: React.ReactNode;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* What stands where content would have been: a glyph, a headline, a sentence
|
|
49
|
+
* and a way out.
|
|
50
|
+
*
|
|
51
|
+
* It is the other half of [Skeleton](../feedback/skeleton). A skeleton is the
|
|
52
|
+
* shape of something on its way; this is the shape of something that is not
|
|
53
|
+
* coming — a search with no matches, an inbox nobody has written to, a folder
|
|
54
|
+
* before the first file. The two are never both right at once, and a list that
|
|
55
|
+
* shows neither has a blank rectangle where its answer should be.
|
|
56
|
+
*
|
|
57
|
+
* The headline is the only text in the library a component invents at full
|
|
58
|
+
* size, and it is defaulted rather than required for one reason: the version
|
|
59
|
+
* that says nothing useful is the version that gets shipped. `Nothing here` in
|
|
60
|
+
* the reader's language is a floor, and every slot above it — the glyph, the
|
|
61
|
+
* sentence, the action — is there to be filled with what is actually missing.
|
|
62
|
+
*
|
|
63
|
+
* `surfaceSlots` is the undyed slot set, so `color` reaches the hairline and
|
|
64
|
+
* the ring and stops there. An empty state that arrives in the accent colour is
|
|
65
|
+
* making a claim about content that does not exist; the family is worth
|
|
66
|
+
* changing only when the emptiness is itself a problem (`color="danger"` on a
|
|
67
|
+
* region that failed to load).
|
|
68
|
+
*/
|
|
69
|
+
export declare const Empty: React.ForwardRefExoticComponent<EmptyProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as r}from"react/jsx-runtime";import*as n from"react";import{useRender as l}from"@base-ui/react/use-render";import{boxPaddingXClasses as a}from"../box/Box";import{transitionProps as o}from"../../internal/animate";import{useMessages as s}from"../../internal/i18n";import{hasContent as i,iconClasses as m,radiusClasses as c,sheetBodyClasses as d,sheetHeaderGapClasses as x,sheetSectionGapClasses as p,sheetTitleClasses as f,surfaceClasses as u,surfaceSlots as h,transitionClasses as y}from"../../internal/styles";const v={default:{xs:"py-5",sm:"py-6",md:"py-8",lg:"py-10",xl:"py-12"},compact:{xs:"py-3",sm:"py-3.5",md:"py-4",lg:"py-5",xl:"py-6"}},b={xs:"text-[1.25rem]",sm:"text-[1.5rem]",md:"text-[1.75rem]",lg:"text-[2.125rem]",xl:"text-[2.5rem]"},g={solid:[u,"text-(--neba-fg) bg-(--n-panel-hover)","[box-shadow:var(--n-elev),var(--neba-plate-solid)]"].join(" "),outline:[u,"border text-(--neba-fg) bg-(--n-panel)","[border-color:var(--n-line)]","[box-shadow:var(--n-elev),var(--neba-plate-glass)]"].join(" "),text:"text-(--neba-fg) bg-transparent"};function j(){return t("svg",{viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:[e("path",{d:"M1.75 9.75h3l.9 1.6h4.7l.9-1.6h3",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"}),e("path",{d:"m1.75 9.75 2.1-6a1.5 1.5 0 0 1 1.42-1h5.46a1.5 1.5 0 0 1 1.42 1l2.1 6v2a1.5 1.5 0 0 1-1.5 1.5h-9.5a1.5 1.5 0 0 1-1.5-1.5Z",stroke:"currentColor",strokeWidth:"1.5",strokeLinejoin:"round"})]})}export const Empty=n.forwardRef(function({variant:n="text",size:u="md",color:N="secondary",density:k="default",elevation:w=0,title:$,icon:B,action:L,locale:C,transition:W,render:z,className:E,style:F,children:M,...R},Z){const q=s(C),A=void 0===$?q.empty.title:$,D=void 0===B?e(j,{}):B,G=o(W),H=i(A),I=["flex w-full flex-col items-center justify-center text-center",a[k][u],v[k][u],c[u],p[u],y,g[n],G.className,E??""].filter(Boolean).join(" ");return l({render:z,ref:Z,props:{role:"status",className:I,style:{...h(N,w),...G.style,...F},children:t(r,{children:[i(D)?e("span",{className:`flex items-center text-(--neba-muted-fg) ${b[u]} ${m}`,children:D}):null,H||i(M)?t("div",{className:`flex max-w-prose flex-col items-center ${x[u]}`,children:[H?e("div",{className:`neba-title font-semibold ${f[u]}`,children:A}):null,i(M)?e("div",{className:`${d[u]} ${H?"text-(--neba-muted-fg)":""}`,children:M}):null]}):null,i(L)?e("div",{className:"flex flex-wrap items-center justify-center gap-2",children:L}):null]}),...R}})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Empty}from"./Empty";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { NebaColor, NebaSize } from '../../types';
|
|
2
|
+
import type { NebaColor, NebaSize, NebaTransition } from '../../types';
|
|
3
3
|
export interface IconProps extends Omit<React.ComponentPropsWithoutRef<'span'>, 'color'> {
|
|
4
4
|
/**
|
|
5
5
|
* The glyph. An `<svg>` element, an `<img>`, a component from an icon set, or
|
|
@@ -13,6 +13,13 @@ export interface IconProps extends Omit<React.ComponentPropsWithoutRef<'span'>,
|
|
|
13
13
|
* *sizes*, not content the Icon merely wraps.
|
|
14
14
|
*/
|
|
15
15
|
icon: React.ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* An entrance animation, run once on mount: `transition="fade"`, or an object
|
|
18
|
+
* for the details. `transition="rotate"` with `repeat="infinite"` is the one
|
|
19
|
+
* spin the design language allows on a glyph. For a trigger or a replay, wrap
|
|
20
|
+
* it in an `Animate*` component instead.
|
|
21
|
+
*/
|
|
22
|
+
transition?: NebaTransition;
|
|
16
23
|
/**
|
|
17
24
|
* The box the glyph is drawn in: 14, 16, 20, 24 and 28px. Its own ladder
|
|
18
25
|
* rather than the control heights, because an icon is not a control.
|