@ssa-ui-kit/core 3.22.1 → 3.23.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.
Files changed (42) hide show
  1. package/dist/ai/source-map.md +97 -27
  2. package/dist/components/Carousel/Carousel.d.ts +62 -0
  3. package/dist/components/Carousel/index.d.ts +1 -0
  4. package/dist/components/Carousel/styles.d.ts +27 -0
  5. package/dist/components/Carousel/types.d.ts +142 -0
  6. package/dist/components/Charts/FunnelChart/FunnelChart.d.ts +24 -0
  7. package/dist/components/Charts/FunnelChart/index.d.ts +2 -0
  8. package/dist/components/Charts/FunnelChart/styles.d.ts +10 -0
  9. package/dist/components/Charts/FunnelChart/types.d.ts +62 -0
  10. package/dist/components/Charts/FunnelChart/utils.d.ts +25 -0
  11. package/dist/components/Charts/index.d.ts +1 -0
  12. package/dist/components/Drawer/DrawerActions.d.ts +44 -0
  13. package/dist/components/Drawer/DrawerFooter.d.ts +33 -0
  14. package/dist/components/Drawer/DrawerRoot.d.ts +10 -4
  15. package/dist/components/Drawer/constants.d.ts +17 -0
  16. package/dist/components/Drawer/index.parts.d.ts +2 -0
  17. package/dist/components/Drawer/useDrawer.d.ts +23 -0
  18. package/dist/components/NavBar/NavBarList.d.ts +5 -0
  19. package/dist/components/Table/ColumnResizeContext.d.ts +30 -0
  20. package/dist/components/Table/ColumnResizeHandle.d.ts +47 -0
  21. package/dist/components/Table/ColumnResizeHandle.types.d.ts +29 -0
  22. package/dist/components/Table/Table.d.ts +67 -5
  23. package/dist/components/Table/TableBase.d.ts +36 -0
  24. package/dist/components/Table/consts.d.ts +8 -0
  25. package/dist/components/Table/hooks/useColumnResize.d.ts +76 -0
  26. package/dist/components/Table/index.d.ts +5 -0
  27. package/dist/components/Table/types.d.ts +149 -0
  28. package/dist/components/TableCellHeader/TableCellHeader.d.ts +2 -1
  29. package/dist/components/TableCellHeader/types.d.ts +18 -1
  30. package/dist/components/Tooltip/types.d.ts +2 -2
  31. package/dist/components/Typeahead/Typeahead.context.d.ts +1 -0
  32. package/dist/components/Typeahead/Typeahead.d.ts +1 -1
  33. package/dist/components/Typeahead/singleLine.d.ts +52 -0
  34. package/dist/components/Typeahead/styles.d.ts +19 -0
  35. package/dist/components/Typeahead/types.d.ts +10 -1
  36. package/dist/components/Typeahead/useTypeahead.d.ts +2 -1
  37. package/dist/components/index.d.ts +4 -0
  38. package/dist/index.js +2368 -325
  39. package/dist/index.mjs +2364 -326
  40. package/dist/tsbuildcache +1 -1
  41. package/dist/types/emotion.d.ts +9 -0
  42. package/package.json +3 -3
@@ -0,0 +1,33 @@
1
+ export interface DrawerFooterProps extends React.HTMLAttributes<HTMLElement> {
2
+ children?: React.ReactNode;
3
+ }
4
+ /**
5
+ * Drawer.Footer - A sticky action bar across the bottom of the panel.
6
+ *
7
+ * Holds the drawer's closing actions — cancel and confirm, clear and apply —
8
+ * above a full-width divider. It stays at the bottom whether the body is short
9
+ * or scrolling, and it only handles layout: the buttons are ordinary `Button`s,
10
+ * so their labels, variants and disabled states are yours to set.
11
+ *
12
+ * Place it as the last child of `Drawer.Content`. Children are laid out in a
13
+ * row, 20px apart, aligned to the trailing edge.
14
+ *
15
+ * @category Components
16
+ * @subcategory Overlay
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <Drawer.Content>
21
+ * <Drawer.Header>
22
+ * <Drawer.Title>Filters</Drawer.Title>
23
+ * <Drawer.CloseButton />
24
+ * </Drawer.Header>
25
+ * {fields}
26
+ * <Drawer.Footer>
27
+ * <Button variant="custom" text="Clear" onClick={handleClear} />
28
+ * <Button variant="primary" text="View leads" onClick={handleSubmit} />
29
+ * </Drawer.Footer>
30
+ * </Drawer.Content>
31
+ * ```
32
+ */
33
+ export declare const DrawerFooter: import("react").ForwardRefExoticComponent<DrawerFooterProps & import("react").RefAttributes<HTMLElement>>;
@@ -18,7 +18,7 @@ export interface DrawerProps extends UseDrawerOptions {
18
18
  * └── Drawer.Content — the panel itself
19
19
  * ├── Drawer.Header
20
20
  * │ ├── Drawer.Title
21
- * │ └── Drawer.CloseButton
21
+ * │ └── Drawer.Actions — save/search + Drawer.CloseButton
22
22
  * └── …your content
23
23
  * ```
24
24
  * Each layer reads context from the one above, so skipping a level (Content
@@ -37,7 +37,9 @@ export interface DrawerProps extends UseDrawerOptions {
37
37
  * across open/close belongs above the drawer, not inside it.
38
38
  *
39
39
  * Note `opened`/`defaultOpened` are the legacy spelling of `open`/`defaultOpen`;
40
- * prefer the latter.
40
+ * prefer the latter. `title`/`withCloseButton` are likewise deprecated — they
41
+ * build a header that cannot hold anything else; compose `Drawer.Header`
42
+ * yourself instead.
41
43
  *
42
44
  * @category Components
43
45
  * @subcategory Overlay
@@ -45,14 +47,18 @@ export interface DrawerProps extends UseDrawerOptions {
45
47
  * @example
46
48
  * ```tsx
47
49
  * // Controlled: the trigger lives outside the drawer
48
- * const drawer = useDrawer({ title: 'Settings', withCloseButton: true });
50
+ * const drawer = useDrawer();
49
51
  *
50
52
  * <>
51
53
  * <Button {...drawer.interactions.getReferenceProps()} text="Settings" />
52
54
  * <Drawer.Root store={drawer}>
53
55
  * <Drawer.Portal>
54
56
  * <Drawer.Overlay>
55
- * <Drawer.Content css={{ maxWidth: 400, padding: 24 }}>
57
+ * <Drawer.Content>
58
+ * <Drawer.Header>
59
+ * <Drawer.Title>Settings</Drawer.Title>
60
+ * <Drawer.CloseButton />
61
+ * </Drawer.Header>
56
62
  * {form}
57
63
  * </Drawer.Content>
58
64
  * </Drawer.Overlay>
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Panel padding, per the design: 24px above the header, 32px gutters.
3
+ *
4
+ * `DrawerHeader` and `DrawerFooter` are sticky bars that have to cover the full
5
+ * width of the panel as content scrolls under them, so both cancel these
6
+ * gutters with a negative margin and re-apply them as their own padding.
7
+ * Keeping the numbers here means the bleed cannot drift from the padding it is
8
+ * cancelling.
9
+ */
10
+ export declare const PANEL_PADDING_X = 32;
11
+ export declare const PANEL_PADDING_TOP = 24;
12
+ /**
13
+ * Gap between the header and the body, per the design. Applied as the header's
14
+ * bottom padding rather than a margin so it stays opaque while the header is
15
+ * stuck and the body scrolls beneath it.
16
+ */
17
+ export declare const HEADER_GAP = 24;
@@ -3,5 +3,7 @@ export { DrawerOverlay as Overlay } from './DrawerOverlay';
3
3
  export { DrawerPortal as Portal } from './DrawerPortal';
4
4
  export { DrawerContent as Content } from './DrawerContent';
5
5
  export { DrawerHeader as Header } from './DrawerHeader';
6
+ export { DrawerActions as Actions } from './DrawerActions';
7
+ export { DrawerFooter as Footer } from './DrawerFooter';
6
8
  export { DrawerTitle as Title } from './DrawerTitle';
7
9
  export { DrawerCloseButton as CloseButton } from './DrawerCloseButton';
@@ -25,8 +25,30 @@ export type UseDrawerOptions = {
25
25
  duration?: number;
26
26
  dismissable?: boolean;
27
27
  position?: Position;
28
+ /**
29
+ * Title for the header that `Drawer.Content` builds for you.
30
+ *
31
+ * @deprecated Compose the header instead — `Drawer.Header` with a
32
+ * `Drawer.Title` inside. The store-built header cannot hold anything else,
33
+ * so a drawer that needs a save button or a search field has to abandon it
34
+ * entirely. Removed in the next major release.
35
+ */
28
36
  title?: string;
37
+ /**
38
+ * Adds a close button to the header that `Drawer.Content` builds for you.
39
+ *
40
+ * @deprecated Render `Drawer.CloseButton` yourself, inside a `Drawer.Header`
41
+ * — usually within a `Drawer.Actions` group. Removed in the next major
42
+ * release.
43
+ */
29
44
  withCloseButton?: boolean;
45
+ /**
46
+ * Width of the panel for `left`/`right` drawers — a number of px, or any CSS
47
+ * length. `top`/`bottom` drawers span the full width and ignore it.
48
+ *
49
+ * @default 400
50
+ */
51
+ width?: number | string;
30
52
  onOpenChange?: (open: boolean, event?: Event, reason?: OpenChangeReason) => void;
31
53
  };
32
54
  export declare const useDrawer: (options?: UseDrawerOptions) => {
@@ -64,6 +86,7 @@ export declare const useDrawer: (options?: UseDrawerOptions) => {
64
86
  };
65
87
  title: string | undefined;
66
88
  withCloseButton: boolean;
89
+ width: string | number;
67
90
  portalNode: HTMLElement | null;
68
91
  setFloating: ((node: HTMLElement | null) => void) & ((node: HTMLElement | null) => void);
69
92
  setPortalNode: import("react").Dispatch<import("react").SetStateAction<HTMLElement | null>>;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Also used as the styling base for `CollapsibleNavBarList`, which resets the
3
+ * column layout below — keep the two in sync when changing direction, gap or
4
+ * wrapping here.
5
+ */
1
6
  declare const NavBarList: import("@emotion/styled").StyledComponent<{
2
7
  theme?: import("@emotion/react").Theme;
3
8
  as?: React.ElementType;
@@ -0,0 +1,30 @@
1
+ import { ColumnResizeApi } from './types';
2
+ /**
3
+ * Null outside a resizable `Table` — deliberately not a "safe" context.
4
+ * `TableCellHeader` reads it on every render to decide whether it owes the
5
+ * table a drag handle, and the answer is usually no.
6
+ */
7
+ export declare const ColumnResizeContext: import("react").Context<ColumnResizeApi | null>;
8
+ /**
9
+ * The enclosing table's resize API, or `null` when there isn't one.
10
+ *
11
+ * Lets a custom header cell decide whether it owes the table a drag handle,
12
+ * without knowing how its table was configured.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const MyHeaderCell = ({ children }) => {
17
+ * const columnResize = useColumnResizeContext();
18
+ *
19
+ * return (
20
+ * <TableCell as="th">
21
+ * {children}
22
+ * {columnResize && <ColumnResizeHandle />}
23
+ * </TableCell>
24
+ * );
25
+ * };
26
+ * ```
27
+ *
28
+ * @see {@link useColumnResize} - creates the API this reads
29
+ */
30
+ export declare const useColumnResizeContext: () => ColumnResizeApi | null;
@@ -0,0 +1,47 @@
1
+ import { ColumnResizeHandleProps } from './ColumnResizeHandle.types';
2
+ /**
3
+ * ColumnResizeHandle - the grab area on a column's right edge
4
+ *
5
+ * Rendered automatically by `TableCellHeader` inside a `Table` with
6
+ * `resizableColumns`, so most tables never name it. Render it by hand when the
7
+ * header cells are something other than `TableCellHeader` but still sit inside
8
+ * a resizable `Table`.
9
+ *
10
+ * Outside a resizable table it renders nothing, which keeps it safe to drop
11
+ * into a shared header cell that is used in both kinds of table.
12
+ *
13
+ * ### Which column it resizes
14
+ *
15
+ * With no `columnIndex` it takes the `cellIndex` of the cell it is rendered in.
16
+ * That is the right answer for every table whose header is one cell per column,
17
+ * and the wrong one as soon as a header cell spans several columns — pass
18
+ * `columnIndex` explicitly there.
19
+ *
20
+ * @category Components
21
+ * @subcategory Data Display
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <Table resizableColumns>
26
+ * <TableHead>
27
+ * <TableRow>
28
+ * <th>
29
+ * Name
30
+ * <ColumnResizeHandle />
31
+ * </th>
32
+ * </TableRow>
33
+ * </TableHead>
34
+ * </Table>
35
+ * ```
36
+ *
37
+ * @see {@link Table} - the resizableColumns prop that turns this on
38
+ * @see {@link useColumnResize} - the state and maths behind the handle
39
+ *
40
+ * @accessibility
41
+ * - Focusable `role="separator"` with `aria-orientation="vertical"`
42
+ * - Left/Right arrows resize in 8px steps, Shift + arrow in 40px steps
43
+ * - Enter, or a double click, restores the column's starting width
44
+ * - Reports the live width through `aria-valuenow`
45
+ */
46
+ export declare const ColumnResizeHandle: ({ columnIndex, label, ...rest }: ColumnResizeHandleProps) => import("@emotion/react/jsx-runtime").JSX.Element | null;
47
+ export default ColumnResizeHandle;
@@ -0,0 +1,29 @@
1
+ import { HTMLAttributes } from 'react';
2
+ /**
3
+ * Props for the ColumnResizeHandle component
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * // Inside a TableCellHeader, index taken from the cell
8
+ * <ColumnResizeHandle />
9
+ * ```
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * // Explicit column, for a header that does not map one cell per column
14
+ * <ColumnResizeHandle columnIndex={2} label="Created at" />
15
+ * ```
16
+ */
17
+ export interface ColumnResizeHandleProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'role' | 'tabIndex' | 'onPointerDown' | 'onPointerMove' | 'onPointerUp' | 'onPointerCancel' | 'onDoubleClick' | 'onKeyDown'> {
18
+ /**
19
+ * Which column this handle resizes. Defaults to the `cellIndex` of the cell
20
+ * the handle is rendered in, which is only wrong when a header cell spans
21
+ * more than one column.
22
+ */
23
+ columnIndex?: number;
24
+ /**
25
+ * Column name used in the handle's accessible label. Defaults to the text of
26
+ * the cell the handle sits in.
27
+ */
28
+ label?: string;
29
+ }
@@ -1,4 +1,4 @@
1
- import { CommonProps } from '../../types/emotion';
1
+ import { TableProps } from './types';
2
2
  /**
3
3
  * Table - Base table component for displaying tabular data
4
4
  *
@@ -16,6 +16,26 @@ import { CommonProps } from '../../types/emotion';
16
16
  * - TableRow (data rows)
17
17
  * - TableCell (data cells)
18
18
  *
19
+ * ### Resizable columns
20
+ *
21
+ * `resizableColumns` gives every header cell a drag handle on its right edge.
22
+ * The table measures its own columns on first layout, so it opens at the widths
23
+ * it would have had anyway, then switches to `table-layout: fixed` and
24
+ * truncates overflowing cell content with an ellipsis.
25
+ *
26
+ * By default a resize is a trade between two columns: the one to the right
27
+ * gives up exactly what the dragged column gains, so the table stays the width
28
+ * it was and nothing around it reflows. The last column has nothing to its
29
+ * right to trade with, so it has no handle.
30
+ *
31
+ * `columnResizeMode="expand"` opts into the other model — the table grows
32
+ * with the dragged column and the others keep their widths — for tables that
33
+ * have a horizontally scrollable parent to grow into.
34
+ *
35
+ * Widths are not persisted: read them from `onColumnWidthsChange`, store them
36
+ * wherever the app keeps user preferences, and feed them back through
37
+ * `defaultColumnWidths`.
38
+ *
19
39
  * @category Components
20
40
  * @subcategory Data Display
21
41
  *
@@ -44,6 +64,48 @@ import { CommonProps } from '../../types/emotion';
44
64
  *
45
65
  * @example
46
66
  * ```tsx
67
+ * // Resizable columns, widths measured from the content
68
+ * <Table resizableColumns>
69
+ * <TableHead>
70
+ * <TableRow>
71
+ * <TableCellHeader>Name</TableCellHeader>
72
+ * <TableCellHeader>Email</TableCellHeader>
73
+ * </TableRow>
74
+ * </TableHead>
75
+ * <TableBody>{rows}</TableBody>
76
+ * </Table>
77
+ * ```
78
+ *
79
+ * @example
80
+ * ```tsx
81
+ * // Columns keep their widths and the table grows, so it needs to be able to
82
+ * // scroll sideways
83
+ * <Wrapper css={{ display: 'block', overflowX: 'auto' }}>
84
+ * <Table resizableColumns columnResizeMode="expand">
85
+ * {children}
86
+ * </Table>
87
+ * </Wrapper>
88
+ * ```
89
+ *
90
+ * @example
91
+ * ```tsx
92
+ * // Resizable columns, widths owned and persisted by the caller
93
+ * const [widths, setWidths] = useState(loadWidths);
94
+ *
95
+ * <Table
96
+ * resizableColumns
97
+ * columnWidths={widths}
98
+ * minColumnWidth={96}
99
+ * onColumnWidthsChange={(next) => {
100
+ * setWidths(next);
101
+ * saveWidths(next);
102
+ * }}>
103
+ * {children}
104
+ * </Table>
105
+ * ```
106
+ *
107
+ * @example
108
+ * ```tsx
47
109
  * // Table with custom styling
48
110
  * <Table css={{ border: '1px solid #ccc' }}>
49
111
  * <TableHead>
@@ -66,15 +128,15 @@ import { CommonProps } from '../../types/emotion';
66
128
  * @see {@link TableRow} - Row component
67
129
  * @see {@link TableCell} - Data cell component
68
130
  * @see {@link TableCellHeader} - Header cell component
131
+ * @see {@link useColumnResize} - the resizing state, for custom header layouts
132
+ * @see {@link ColumnResizeHandle} - the drag handle header cells render
69
133
  *
70
134
  * @accessibility
71
135
  * - Semantic HTML table element
72
136
  * - Proper table structure for screen readers
73
137
  * - Keyboard navigation support
74
138
  * - ARIA attributes when needed
139
+ * - Resize handles are keyboard operable; see {@link ColumnResizeHandle}
75
140
  */
76
- declare const Table: import("@emotion/styled").StyledComponent<{
77
- theme?: import("@emotion/react").Theme;
78
- as?: React.ElementType;
79
- } & CommonProps, import("react").DetailedHTMLProps<import("react").TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, {}>;
141
+ declare const Table: import("react").ForwardRefExoticComponent<TableProps & import("react").RefAttributes<HTMLTableElement>>;
80
142
  export default Table;
@@ -0,0 +1,36 @@
1
+ import { CommonProps } from '../../types/emotion';
2
+ import { ColumnResizeMode } from './types';
3
+ export interface TableBaseProps extends CommonProps {
4
+ /** Applies the truncation rules resizing depends on. */
5
+ isResizable?: boolean;
6
+ /**
7
+ * Whether the columns have been measured yet. Fixed layout is what makes a
8
+ * dragged width stick, but it can only be switched on once there are widths
9
+ * to switch to.
10
+ */
11
+ hasColumnWidths?: boolean;
12
+ /** How a resize distributes width. See TableProps.columnResizeMode. */
13
+ columnResizeMode?: ColumnResizeMode;
14
+ }
15
+ /**
16
+ * The styled element behind `Table`.
17
+ *
18
+ * Kept separate so `Table` can stay a component with state and a colgroup while
19
+ * everything that composes it — `NestedTable`, consumer `styled(Table)` calls —
20
+ * keeps getting a plain table element underneath.
21
+ *
22
+ * ### Nothing per-pixel belongs in here
23
+ *
24
+ * Every distinct value interpolated into this template mints another emotion
25
+ * class and injects another stylesheet rule, permanently. A width that changes
26
+ * with the pointer would add one rule per frame of every drag — a few hundred
27
+ * within seconds — and each insertion invalidates the document's style cache,
28
+ * so resizing gets progressively slower until the page is reloaded. The table's
29
+ * width in `expand` mode is therefore an inline style, set by `Table`, and the
30
+ * props here only ever take a handful of values.
31
+ */
32
+ declare const TableBase: import("@emotion/styled").StyledComponent<{
33
+ theme?: import("@emotion/react").Theme;
34
+ as?: React.ElementType;
35
+ } & TableBaseProps, import("react").DetailedHTMLProps<import("react").TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, {}>;
36
+ export default TableBase;
@@ -0,0 +1,8 @@
1
+ /** Smallest width a column can be dragged to, in pixels. */
2
+ export declare const DEFAULT_MIN_COLUMN_WIDTH = 64;
3
+ /** Width change per arrow-key press on a resize handle, in pixels. */
4
+ export declare const KEYBOARD_RESIZE_STEP = 8;
5
+ /** Width change per Shift + arrow-key press on a resize handle, in pixels. */
6
+ export declare const KEYBOARD_RESIZE_STEP_LARGE = 40;
7
+ /** Hit area of the drag handle, inset into the right edge of the cell. */
8
+ export declare const RESIZE_HANDLE_WIDTH = 8;
@@ -0,0 +1,76 @@
1
+ import { ColumnResizeApi, UseColumnResizeOptions } from '../types';
2
+ /**
3
+ * Column resizing for a `Table`, without any of the rendering.
4
+ *
5
+ * Owns the width of every column and the pointer/keyboard maths that moves it.
6
+ * `Table`'s `resizableColumns` prop is a thin wrapper over this hook — reach for
7
+ * the hook directly when the header is built from something other than
8
+ * `TableCellHeader`, or when the handles need to live somewhere unusual.
9
+ *
10
+ * ## Widths are measured, not invented
11
+ *
12
+ * With no `defaultColumnWidths`, the first layout pass reads the columns' real
13
+ * rendered widths off the DOM while the table is still in `table-layout: auto`,
14
+ * and seeds state from those. The table only switches to `fixed` once it has
15
+ * numbers to switch to, so an uncontrolled table starts out looking exactly as
16
+ * it did before resizing was turned on. Under jsdom every measurement comes back
17
+ * `0`; the hook then stays unseeded, so tests that care about widths should pass
18
+ * `defaultColumnWidths` explicitly.
19
+ *
20
+ * ## Two ways to spend the width
21
+ *
22
+ * In the default `fit` mode a resize is a trade: the column to the right gives
23
+ * up exactly what the dragged column gains, so the table's own width never
24
+ * changes and no surrounding layout moves. The last column has nothing to its
25
+ * right and so cannot be dragged.
26
+ *
27
+ * In `expand` mode the table grows instead, and the columns beside the dragged
28
+ * one keep their widths. That needs a horizontally scrollable container, or the
29
+ * table will overflow whatever is holding it.
30
+ *
31
+ * A column marked `data-column-pinned="true"` on its header cell never pays for
32
+ * the column before it in `fit` mode, so that handle is inert — pinning a
33
+ * column pins it against every route to changing its width, not just its own
34
+ * handle.
35
+ *
36
+ * ## Stored widths are not always rendered widths
37
+ *
38
+ * A table in `fit` mode is still `width: 100%`, and fixed layout spreads any
39
+ * difference between the widths it was given and the width it actually has
40
+ * across the columns in proportion. Widths of `[220, 140, 140, 96]` in a
41
+ * 1248px table therefore render at a little over twice their stated size.
42
+ *
43
+ * That makes two coordinate spaces: the caller's units, which the widths and
44
+ * the min/max bounds are in, and rendered pixels, which is what a pointer
45
+ * moves through. Every gesture is converted between them, so a column tracks
46
+ * the pointer exactly no matter how far apart the two spaces are — without
47
+ * quietly rewriting the numbers the caller chose.
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * const { columnWidths, tableRef, getResizeHandleProps } = useColumnResize({
52
+ * defaultColumnWidths: [240, 160, 160],
53
+ * onColumnWidthsChange: (widths) => localStorage.setItem('cols', JSON.stringify(widths)),
54
+ * });
55
+ *
56
+ * <table ref={tableRef} style={{ tableLayout: 'fixed' }}>
57
+ * <colgroup>
58
+ * {columnWidths.map((width, index) => <col key={index} style={{ width }} />)}
59
+ * </colgroup>
60
+ * <thead>
61
+ * <tr>
62
+ * {headers.map((header, index) => (
63
+ * <th key={header}>
64
+ * {header}
65
+ * <span {...getResizeHandleProps(index)} />
66
+ * </th>
67
+ * ))}
68
+ * </tr>
69
+ * </thead>
70
+ * </table>
71
+ * ```
72
+ *
73
+ * @see {@link Table} - pass `resizableColumns` to get all of this wired up
74
+ * @see {@link ColumnResizeHandle} - the handle `TableCellHeader` renders for you
75
+ */
76
+ export declare const useColumnResize: (options?: UseColumnResizeOptions) => ColumnResizeApi;
@@ -1 +1,6 @@
1
1
  export { default } from './Table';
2
+ export { default as ColumnResizeHandle } from './ColumnResizeHandle';
3
+ export { useColumnResize } from './hooks/useColumnResize';
4
+ export { useColumnResizeContext } from './ColumnResizeContext';
5
+ export * from './types';
6
+ export * from './ColumnResizeHandle.types';
@@ -0,0 +1,149 @@
1
+ import { AriaAttributes, KeyboardEvent, PointerEvent, RefObject, TableHTMLAttributes } from 'react';
2
+ import { CommonProps } from '../../types/emotion';
3
+ /**
4
+ * How a resize distributes width.
5
+ *
6
+ * - `fit` — the column to the right gives up what the dragged column gains, so
7
+ * the table's own width never changes. The last column cannot be dragged,
8
+ * having nothing to its right to trade with.
9
+ * - `expand` — the table grows and the other columns keep their widths, so the
10
+ * table needs a horizontally scrollable parent.
11
+ */
12
+ export type ColumnResizeMode = 'fit' | 'expand';
13
+ /** Options shared by `useColumnResize` and `Table`'s resizable mode. */
14
+ export interface ColumnResizeOptions {
15
+ /**
16
+ * Column widths in pixels, one per column. Passing this prop puts the table
17
+ * into controlled mode for the life of the component — hold the value in
18
+ * state and update it from `onColumnWidthsChange`, or the columns will not
19
+ * move when dragged.
20
+ */
21
+ columnWidths?: number[];
22
+ /**
23
+ * Starting column widths in pixels, for the uncontrolled case. Omit it and
24
+ * the table measures its own columns on first layout, so it opens at whatever
25
+ * widths it would have had without resizing.
26
+ */
27
+ defaultColumnWidths?: number[];
28
+ /**
29
+ * Called on every width change, including each frame of a drag. Persisting
30
+ * widths is the caller's job — write them to storage or user preferences here
31
+ * and feed them back through `defaultColumnWidths`.
32
+ */
33
+ onColumnWidthsChange?: (columnWidths: number[]) => void;
34
+ /**
35
+ * Narrowest a column can be dragged, in pixels.
36
+ * @default 64
37
+ */
38
+ minColumnWidth?: number;
39
+ /**
40
+ * Widest a column can be dragged, in pixels. Unbounded when omitted.
41
+ */
42
+ maxColumnWidth?: number;
43
+ /**
44
+ * Whether a resize is paid for by the next column or by the table's own
45
+ * width. Defaults to `fit`, which keeps the table exactly as wide as it was
46
+ * — surrounding layout never moves because a user dragged a column.
47
+ *
48
+ * Switch to `expand` when the table lives in its own scroll container and
49
+ * columns should keep the widths the user gave them.
50
+ *
51
+ * @default 'fit'
52
+ */
53
+ columnResizeMode?: ColumnResizeMode;
54
+ }
55
+ /** Props for the element that starts a drag. Spread onto any element. */
56
+ export interface ResizeHandleProps extends Pick<AriaAttributes, 'aria-orientation' | 'aria-valuenow' | 'aria-valuemin' | 'aria-valuemax'> {
57
+ role: 'separator';
58
+ tabIndex: number;
59
+ 'data-resizing'?: 'true';
60
+ onPointerDown: (event: PointerEvent<HTMLElement>) => void;
61
+ onPointerMove: (event: PointerEvent<HTMLElement>) => void;
62
+ onPointerUp: (event: PointerEvent<HTMLElement>) => void;
63
+ onPointerCancel: (event: PointerEvent<HTMLElement>) => void;
64
+ onDoubleClick: () => void;
65
+ onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
66
+ }
67
+ /**
68
+ * Options for {@link useColumnResize}.
69
+ *
70
+ * Everything `Table` accepts for resizing, plus the two escape hatches `Table`
71
+ * itself needs — `enabled` and `controlled`.
72
+ *
73
+ * @example
74
+ * ```tsx
75
+ * useColumnResize({
76
+ * defaultColumnWidths: [240, 160, 160],
77
+ * minColumnWidth: 96,
78
+ * onColumnWidthsChange: saveWidths,
79
+ * });
80
+ * ```
81
+ */
82
+ export interface UseColumnResizeOptions extends ColumnResizeOptions {
83
+ /**
84
+ * Whether to measure and track widths at all. `Table` passes its
85
+ * `resizableColumns` prop through so the hook can be called unconditionally.
86
+ * @default true
87
+ */
88
+ enabled?: boolean;
89
+ /**
90
+ * Overrides the controlled/uncontrolled decision, which is otherwise taken
91
+ * from whether `columnWidths` was passed. `Table` sets it explicitly because
92
+ * it rebuilds the options object rather than forwarding its own props.
93
+ */
94
+ controlled?: boolean;
95
+ }
96
+ /** What `useColumnResize` hands back. */
97
+ export interface ColumnResizeApi {
98
+ /** Current width of each column, in pixels. Empty until measured. */
99
+ columnWidths: number[];
100
+ /** Attach to the `table` element so the hook can measure its columns. */
101
+ tableRef: RefObject<HTMLTableElement | null>;
102
+ /** Whether a drag is in progress. */
103
+ isResizing: boolean;
104
+ /** The column being dragged, or `null`. */
105
+ resizingColumnIndex: number | null;
106
+ minColumnWidth: number;
107
+ maxColumnWidth?: number;
108
+ columnResizeMode: ColumnResizeMode;
109
+ /**
110
+ * Sets one column's width, clamped to the min/max. In `fit` mode the width is
111
+ * taken from, or given back to, the column on the right, and the request is
112
+ * clamped by that column's limits as well as this one's.
113
+ */
114
+ setColumnWidth: (index: number, width: number) => void;
115
+ /** Adds to one column's width, clamped to the min/max. */
116
+ resizeColumnBy: (index: number, delta: number) => void;
117
+ /** Restores a column to the width it started at. */
118
+ resetColumn: (index: number) => void;
119
+ /** Builds the props for the drag handle of a given column. */
120
+ getResizeHandleProps: (index: number) => ResizeHandleProps;
121
+ }
122
+ /**
123
+ * Props for the {@link Table} component.
124
+ *
125
+ * Every attribute of a `table` element, plus the column-resizing options that
126
+ * `resizableColumns` turns on.
127
+ *
128
+ * @example
129
+ * ```tsx
130
+ * <Table resizableColumns minColumnWidth={96}>
131
+ * {children}
132
+ * </Table>
133
+ * ```
134
+ */
135
+ export interface TableProps extends CommonProps, ColumnResizeOptions, TableHTMLAttributes<HTMLTableElement> {
136
+ /**
137
+ * Lets columns be resized by dragging the right edge of each header cell.
138
+ *
139
+ * Turning this on switches the table to `table-layout: fixed` once it has
140
+ * measured its columns, truncates overflowing cell content with an ellipsis,
141
+ * and makes every `TableCellHeader` render its own drag handle.
142
+ *
143
+ * By default the table's own width does not change — see
144
+ * `columnResizeMode`.
145
+ *
146
+ * @default false
147
+ */
148
+ resizableColumns?: boolean;
149
+ }
@@ -53,6 +53,7 @@ import { TableCellHeaderProps } from './types';
53
53
  * @see {@link TableRow} - Row component (use in TableHead)
54
54
  * @see {@link TableCell} - Data cell component (use in TableBody)
55
55
  * @see {@link TableBody} - Body section component
56
+ * @see {@link ColumnResizeHandle} - the handle rendered inside resizable headers
56
57
  *
57
58
  * @accessibility
58
59
  * - Semantic HTML th element (renders as th)
@@ -60,5 +61,5 @@ import { TableCellHeaderProps } from './types';
60
61
  * - Supports ARIA attributes via TableCellProps
61
62
  * - Better accessibility than using TableCell in headers
62
63
  */
63
- declare const TableCellHeader: ({ children, ...props }: React.PropsWithChildren<TableCellHeaderProps>) => import("@emotion/react/jsx-runtime").JSX.Element;
64
+ declare const TableCellHeader: ({ children, resizable, ...props }: React.PropsWithChildren<TableCellHeaderProps>) => import("@emotion/react/jsx-runtime").JSX.Element;
64
65
  export default TableCellHeader;