@ssa-ui-kit/core 3.23.1 → 3.24.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 (52) hide show
  1. package/dist/ai/source-map.md +149 -43
  2. package/dist/components/Calendar/Calendar.d.ts +130 -0
  3. package/dist/components/Calendar/CalendarContext.d.ts +25 -0
  4. package/dist/components/Calendar/CalendarEventDetails.d.ts +80 -0
  5. package/dist/components/Calendar/components/CalendarToolbar.d.ts +20 -0
  6. package/dist/components/Calendar/components/DayView.d.ts +14 -0
  7. package/dist/components/Calendar/components/EventDetailsLayer.d.ts +17 -0
  8. package/dist/components/Calendar/components/EventSlot.d.ts +17 -0
  9. package/dist/components/Calendar/components/HighlightBadge.d.ts +5 -0
  10. package/dist/components/Calendar/components/MonthView.d.ts +19 -0
  11. package/dist/components/Calendar/components/MoreEventsPopover.d.ts +16 -0
  12. package/dist/components/Calendar/components/TaskCheckbox.d.ts +8 -0
  13. package/dist/components/Calendar/components/useEventClick.d.ts +10 -0
  14. package/dist/components/Calendar/consts.d.ts +49 -0
  15. package/dist/components/Calendar/index.d.ts +2 -0
  16. package/dist/components/Calendar/styles.d.ts +137 -0
  17. package/dist/components/Calendar/types.d.ts +383 -0
  18. package/dist/components/Calendar/utils.d.ts +116 -0
  19. package/dist/components/Carousel/Carousel.d.ts +8 -2
  20. package/dist/components/Carousel/FullImageModal.d.ts +12 -0
  21. package/dist/components/Carousel/styles.d.ts +5 -0
  22. package/dist/components/Carousel/types.d.ts +17 -4
  23. package/dist/components/Charts/FunnelChart/FunnelChart.d.ts +4 -3
  24. package/dist/components/Charts/FunnelChart/types.d.ts +11 -1
  25. package/dist/components/Charts/FunnelChart/utils.d.ts +12 -1
  26. package/dist/components/NestedTable/NestedTableContext.d.ts +3 -3
  27. package/dist/components/NestedTable/components/NestedTable.d.ts +37 -4
  28. package/dist/components/NestedTable/components/NestedTableCell.d.ts +2 -3
  29. package/dist/components/NestedTable/components/NestedTableCellBase.d.ts +16 -0
  30. package/dist/components/NestedTable/components/NestedTableCellHeader.d.ts +36 -0
  31. package/dist/components/NestedTable/components/index.d.ts +1 -0
  32. package/dist/components/NestedTable/consts.d.ts +5 -0
  33. package/dist/components/NestedTable/hooks/useNestedTableContext.d.ts +1 -1
  34. package/dist/components/NestedTable/types.d.ts +31 -0
  35. package/dist/components/Table/ColumnFreezeContext.d.ts +27 -0
  36. package/dist/components/Table/ColumnFreezeMenu.d.ts +33 -0
  37. package/dist/components/Table/TableBase.d.ts +8 -1
  38. package/dist/components/Table/hooks/useColumnFreeze.d.ts +44 -0
  39. package/dist/components/Table/index.d.ts +2 -0
  40. package/dist/components/Table/types.d.ts +97 -2
  41. package/dist/components/Table/utils.d.ts +21 -0
  42. package/dist/components/TableCellHeader/TableCellHeader.d.ts +2 -1
  43. package/dist/components/TableCellHeader/types.d.ts +17 -0
  44. package/dist/components/TableContainer/TableContainer.d.ts +50 -0
  45. package/dist/components/TableContainer/index.d.ts +2 -0
  46. package/dist/components/TableContainer/types.d.ts +21 -0
  47. package/dist/components/index.d.ts +6 -2
  48. package/dist/index.js +4158 -386
  49. package/dist/index.mjs +4154 -388
  50. package/dist/tsbuildcache +1 -1
  51. package/dist/types/emotion.d.ts +2 -0
  52. package/package.json +3 -3
@@ -0,0 +1,116 @@
1
+ import { ReactNode } from 'react';
2
+ import { DateTime } from 'luxon';
3
+ import { CalendarDateInput, CalendarEvent } from './types';
4
+ /** Length given to a timed event that has no `end`. */
5
+ export declare const DEFAULT_EVENT_MINUTES = 30;
6
+ /**
7
+ * Most days an entry is repeated on. A mistyped `end` years away would
8
+ * otherwise fill every cell up to it.
9
+ */
10
+ export declare const MAX_SPAN_DAYS = 366;
11
+ /** `Date` or ISO string → luxon, in local time. */
12
+ export declare const toDateTime: (value: CalendarDateInput) => DateTime;
13
+ /** `yyyy-MM-dd` of a date — the key events are grouped by. */
14
+ export declare const toDayKey: (value: DateTime) => string;
15
+ /**
16
+ * An event with its dates parsed once, so rendering never re-parses them.
17
+ */
18
+ export type NormalizedEvent<TData = unknown> = {
19
+ event: CalendarEvent<TData>;
20
+ start: DateTime;
21
+ /** For untimed events, the start of the last day (inclusive). */
22
+ end: DateTime;
23
+ allDay: boolean;
24
+ /** Days the entry is repeated on: 1 unless it spans several. */
25
+ spanDays: number;
26
+ /** Which of those days this copy is on, from 1. */
27
+ dayOfSpan: number;
28
+ };
29
+ export declare const normalizeEvent: <TData>(event: CalendarEvent<TData>) => NormalizedEvent<TData> | undefined;
30
+ /**
31
+ * Whether an entry fills a day: untimed, or timed and running from before
32
+ * the day starts to after it ends. Such entries are listed above the day
33
+ * view's timeline rather than placed on it.
34
+ */
35
+ export declare const isWholeDay: (item: NormalizedEvent, day: DateTime) => boolean;
36
+ /**
37
+ * Groups events by day (`yyyy-MM-dd`), each day sorted for display. An event
38
+ * spanning several days (see `NormalizedEvent.spanDays`) is repeated on
39
+ * each, with its `dayOfSpan`. Events with an unparsable `start` are dropped.
40
+ */
41
+ export declare const groupEventsByDay: <TData>(events: CalendarEvent<TData>[]) => Map<string, NormalizedEvent<TData>[]>;
42
+ /** A cell of the month grid. */
43
+ export type MonthDay = {
44
+ date: DateTime;
45
+ key: string;
46
+ isCurrentMonth: boolean;
47
+ isToday: boolean;
48
+ isWeekend: boolean;
49
+ };
50
+ /** A row of the month grid. */
51
+ export type MonthWeek = {
52
+ key: string;
53
+ days: MonthDay[];
54
+ };
55
+ /**
56
+ * The Monday-first week rows covering `month`, padded out with the
57
+ * neighbouring months' days. With five weekdays a row that holds only the
58
+ * neighbours' days is dropped — a month that ends on a Saturday would
59
+ * otherwise get a row of nothing but padding.
60
+ */
61
+ export declare const buildMonthWeeks: (month: DateTime, weekdays: 5 | 7, today?: DateTime) => MonthWeek[];
62
+ /** Monday-first weekday names, `long` (`Monday`) or `short` (`Mon`). */
63
+ export declare const getWeekdayNames: (format: "long" | "short", locale?: string) => string[];
64
+ /** `09:30` or `09:30 AM`. */
65
+ export declare const formatTime: (value: DateTime, timeFormat: "24h" | "12h") => string;
66
+ /**
67
+ * Hour label of the day view: `09:00` or `9 AM`. Formatted on a fixed date
68
+ * with no DST change, so every hour exists — on today's date an hour skipped
69
+ * by DST would be moved on, and labelled like the next one.
70
+ */
71
+ export declare const formatHourLabel: (hour: number, timeFormat: "24h" | "12h") => string;
72
+ /**
73
+ * Minutes from midnight as the clock shows them. The timeline draws 24
74
+ * labelled hours on every day, so positions follow the clock rather than
75
+ * elapsed time — on a DST day, elapsed time would put entries after the
76
+ * change an hour off their labels.
77
+ */
78
+ export declare const clockMinutes: (value: DateTime) => number;
79
+ /** A timed event placed on the day view's timeline. */
80
+ export type PositionedEvent<TData = unknown> = {
81
+ item: NormalizedEvent<TData>;
82
+ /** Minutes from midnight to the start. */
83
+ startMinutes: number;
84
+ /** Minutes the event lasts, clipped to the day. */
85
+ durationMinutes: number;
86
+ /** Column within its overlap group, from 0. */
87
+ column: number;
88
+ /** Columns in its overlap group. */
89
+ columns: number;
90
+ };
91
+ /**
92
+ * Places a day's timed events on the timeline. Events that overlap share the
93
+ * width side by side; each overlap group gets just as many columns as it
94
+ * needs at its busiest moment.
95
+ *
96
+ * Expects events sorted by start: the day's own (as `groupEventsByDay`
97
+ * returns them), after any carried over from earlier days. Events running
98
+ * past either midnight are clipped to the day; events not on it are skipped.
99
+ */
100
+ export declare const layoutDayEvents: <TData>(items: NormalizedEvent<TData>[], day: DateTime) => PositionedEvent<TData>[];
101
+ /** Applies `locale` when given; otherwise keeps luxon's default. */
102
+ export declare const withLocale: (value: DateTime, locale?: string) => DateTime<boolean>;
103
+ /**
104
+ * First and last day a view shows: the whole grid of the month view,
105
+ * neighbouring months' days included, or the single day.
106
+ */
107
+ export declare const getVisibleRange: (view: "month" | "day", date: DateTime, weekdays: 5 | 7) => {
108
+ start: DateTime;
109
+ end: DateTime;
110
+ };
111
+ /**
112
+ * Whether a slot has something to draw. Like React itself, keeps `0` and
113
+ * `''` but skips `false` — so `slot={cond && <Button />}` adds no empty
114
+ * wrapper when `cond` is false.
115
+ */
116
+ export declare const hasContent: (node: ReactNode) => node is string | number | bigint | true | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | import("react").ReactPortal | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined>;
@@ -7,8 +7,8 @@ import { CarouselProps } from './types';
7
7
  * The carousel always fills its container's width. The slide's height comes
8
8
  * from `aspectRatio` (square by default, as in the design) or from a fixed
9
9
  * `height`, never from the images — so the layout does not jump between
10
- * slides or while images load. Images are letterboxed inside the frame
11
- * (`fit="contain"`) or cropped to fill it (`fit="cover"`).
10
+ * slides or while images load. Images are cropped to fill the frame
11
+ * (`fit="cover"`, the default) or letterboxed inside it (`fit="contain"`).
12
12
  *
13
13
  * Thumbnails are a fixed 52px. A `left`/`right` strip is exactly as tall as
14
14
  * the slide and a `bottom` strip exactly as wide; extra thumbnails scroll and
@@ -49,6 +49,12 @@ import { CarouselProps } from './types';
49
49
  *
50
50
  * @example
51
51
  * ```tsx
52
+ * // Open full size in a modal on the same page
53
+ * <Carousel items={items} allowOpenFull openFullMode="modal" />
54
+ * ```
55
+ *
56
+ * @example
57
+ * ```tsx
52
58
  * // Autoplay: 3s per slide, 600ms slide animation
53
59
  * <Carousel items={items} autoPlay autoPlayInterval={3000} transitionDuration={600} />
54
60
  * ```
@@ -0,0 +1,12 @@
1
+ type FullImageModalProps = {
2
+ src: string;
3
+ alt?: string;
4
+ onClose: () => void;
5
+ };
6
+ /**
7
+ * The full-size image over a dimmed page, at its natural size but never more
8
+ * than 80% of the viewport. Escape, a click outside and the close button
9
+ * close it; focus moves in and returns to the open button.
10
+ */
11
+ export declare const FullImageModal: ({ src, alt, onClose }: FullImageModalProps) => import("@emotion/react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -17,6 +17,11 @@ export declare const dots: import("@emotion/react").SerializedStyles;
17
17
  export declare const dot: (theme: Theme, active: boolean) => import("@emotion/react").SerializedStyles;
18
18
  export declare const arrows: import("@emotion/react").SerializedStyles;
19
19
  export declare const squareButton: (theme: Theme) => import("@emotion/react").SerializedStyles;
20
+ export declare const fullOverlay: (theme: Theme) => import("@emotion/react").SerializedStyles;
21
+ /** Shrinks to the image, which stops at 80% of the viewport either way. */
22
+ export declare const fullDialog: import("@emotion/react").SerializedStyles;
23
+ export declare const fullImage: import("@emotion/react").SerializedStyles;
24
+ export declare const fullClose: import("@emotion/react").SerializedStyles;
20
25
  export declare const openFull: import("@emotion/react").SerializedStyles;
21
26
  /**
22
27
  * The vertical strip is taken out of flow so that it never stretches the
@@ -18,7 +18,7 @@ export type CarouselItem = {
18
18
  */
19
19
  thumbnailSrc?: string;
20
20
  /**
21
- * Full-size image opened in a new tab when `allowOpenFull` is set.
21
+ * Full-size image opened by the `allowOpenFull` button.
22
22
  * Falls back to `src`.
23
23
  */
24
24
  fullSrc?: string;
@@ -32,6 +32,11 @@ export type CarouselThumbnailsPosition = 'left' | 'right' | 'bottom' | false;
32
32
  * own row under it.
33
33
  */
34
34
  export type CarouselControlsPosition = 'overlay' | 'below';
35
+ /**
36
+ * Where the `allowOpenFull` button opens the image: a new browser tab, or a
37
+ * modal over the current page.
38
+ */
39
+ export type CarouselOpenFullMode = 'newTab' | 'modal';
35
40
  /**
36
41
  * How an image fills the slide frame. Mirrors CSS `object-fit`.
37
42
  */
@@ -71,11 +76,19 @@ export type CarouselProps = {
71
76
  */
72
77
  controlsPosition?: CarouselControlsPosition;
73
78
  /**
74
- * Show a button that opens the current image (`fullSrc ?? src`) in a new
75
- * tab. It appears when the slide is hovered or focused.
79
+ * Show a button that opens the current image (`fullSrc ?? src`), in a new
80
+ * tab or a modal (see `openFullMode`). It appears when the slide is hovered
81
+ * or focused.
76
82
  * @default false
77
83
  */
78
84
  allowOpenFull?: boolean;
85
+ /**
86
+ * Where the `allowOpenFull` button opens the image. `modal` shows it over a
87
+ * dimmed page at its natural size, capped at 80% of the viewport's width
88
+ * and height; autoplay pauses while it is open.
89
+ * @default 'newTab'
90
+ */
91
+ openFullMode?: CarouselOpenFullMode;
79
92
  /**
80
93
  * Width-to-height ratio of the slide. The slide always fills the
81
94
  * container's width; this sets its height. Ignored when `height` is set.
@@ -88,7 +101,7 @@ export type CarouselProps = {
88
101
  height?: CSSProperties['height'];
89
102
  /**
90
103
  * How images fill the slide frame.
91
- * @default 'contain'
104
+ * @default 'cover'
92
105
  */
93
106
  fit?: CarouselFit;
94
107
  /**
@@ -2,8 +2,9 @@ import { FunnelChartProps } from './types';
2
2
  /**
3
3
  * FunnelChart - Stage diagram drawn as a funnel or a triangle
4
4
  *
5
- * Every level has the same height regardless of its value, so zero or
6
- * non-decreasing values never collapse or distort the shape. The chart scales
5
+ * By default every level has the same height regardless of its value, so zero
6
+ * or non-decreasing values never collapse or distort the shape. Set
7
+ * `proportional` to size levels by value instead. The chart scales
7
8
  * to fit its container — give the container a height, or it falls back to the
8
9
  * shape's own aspect ratio.
9
10
  *
@@ -21,4 +22,4 @@ import { FunnelChartProps } from './types';
21
22
  * />
22
23
  * ```
23
24
  */
24
- export declare const FunnelChart: ({ data, type, withPointer, withTooltip, withLabels, renderLabel, renderPointerLabel, renderTooltip, tooltipProps, className, "aria-label": ariaLabel, }: FunnelChartProps) => import("@emotion/react/jsx-runtime").JSX.Element;
25
+ export declare const FunnelChart: ({ data, type, proportional, withPointer, withTooltip, withLabels, renderLabel, renderPointerLabel, renderTooltip, tooltipProps, className, "aria-label": ariaLabel, }: FunnelChartProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -16,13 +16,23 @@ export interface FunnelChartItem {
16
16
  export type FunnelChartRender = (item: FunnelChartItem, index: number) => ReactNode;
17
17
  /** Props for the FunnelChart component */
18
18
  export interface FunnelChartProps {
19
- /** Levels from top to bottom. Every level has the same height. */
19
+ /**
20
+ * Levels from top to bottom. Every level has the same height unless
21
+ * `proportional` is set.
22
+ */
20
23
  data: FunnelChartItem[];
21
24
  /**
22
25
  * Shape of the chart
23
26
  * @default 'funnel'
24
27
  */
25
28
  type?: FunnelChartType;
29
+ /**
30
+ * Size each level's height in proportion to its value, so bigger values
31
+ * get bigger levels. Zero and tiny values keep a minimum height (40% of
32
+ * an equal level) so their labels still fit; non-numeric values count as 0.
33
+ * @default false
34
+ */
35
+ proportional?: boolean;
26
36
  /**
27
37
  * Render a leader line and a label beside each level
28
38
  * @default false
@@ -8,6 +8,13 @@ type Point = {
8
8
  radius: number;
9
9
  };
10
10
  export declare const roundedPolygonPath: (points: Point[]) => string;
11
+ /**
12
+ * Splits `total` between levels in proportion to `values`. Levels that would
13
+ * fall below the minimum get the minimum, and the rest share what is left in
14
+ * proportion to their values. Non-numeric and negative values count as 0;
15
+ * when nothing is positive every level gets the same height.
16
+ */
17
+ export declare const getProportionalHeights: (values: (number | string)[], total: number) => number[];
11
18
  export interface FunnelBand {
12
19
  top: number;
13
20
  bottom: number;
@@ -21,5 +28,9 @@ export interface FunnelGeometry {
21
28
  /** Half-width of the shape at a given distance from the top */
22
29
  halfWidthAt: (y: number) => number;
23
30
  }
24
- export declare const getGeometry: (type: FunnelChartType, levels: number) => FunnelGeometry;
31
+ /**
32
+ * Shape and level bands. Pass `heights` (summing to `DESIGN_HEIGHT`) to size
33
+ * the levels; otherwise they are equal.
34
+ */
35
+ export declare const getGeometry: (type: FunnelChartType, levels: number, heights?: number[]) => FunnelGeometry;
25
36
  export {};
@@ -1,3 +1,3 @@
1
- import { NestedTableContextType } from './types';
2
- export declare const NestedTableContext: import("react").Context<NestedTableContextType>;
3
- export declare const NestedTableProvider: ({ children, collapsedIconName, expandedIconName, defaultCollapsed, }: React.PropsWithChildren<NestedTableContextType>) => import("@emotion/react/jsx-runtime").JSX.Element;
1
+ import { NestedTableContextValue } from './types';
2
+ export declare const NestedTableContext: import("react").Context<NestedTableContextValue>;
3
+ export declare const NestedTableProvider: ({ children, collapsedIconName, expandedIconName, defaultCollapsed, opaqueCells, isResizable, }: React.PropsWithChildren<NestedTableContextValue>) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,6 +1,4 @@
1
- import { PropsWithChildren, TableHTMLAttributes } from 'react';
2
- import { CommonProps } from '../../../types/emotion';
3
- import { NestedTableContextType } from '../types';
1
+ import { TableProps } from '../../Table/types';
4
2
  /**
5
3
  * NestedTable - Table whose rows collapse into expandable groups.
6
4
  *
@@ -26,6 +24,21 @@ import { NestedTableContextType } from '../types';
26
24
  * is what makes the transition animate. They remain findable by queries and by
27
25
  * `Ctrl+F`, so do not rely on collapse to hide sensitive content.
28
26
  *
27
+ * ### Resizing and freezing columns
28
+ * Takes every `Table` option — `resizableColumns`, `frozenColumns`,
29
+ * `freezeControls`, `stickyHeader` — and works inside `TableContainer`. Build
30
+ * the header from `NestedTableCellHeader` so the columns get their drag handles
31
+ * and freeze menus.
32
+ *
33
+ * Column positions skip the toggle column: `0` is your first column in
34
+ * `frozenColumns`, and width arrays hold one entry per column of yours. The
35
+ * toggle column freezes by itself only when your first column is frozen to the
36
+ * left; otherwise it scrolls like any other column.
37
+ *
38
+ * Frozen cells and a sticky header paint the row's background, so give rows an
39
+ * opaque one — a translucent row would let scrolled content show through.
40
+ * With resizing on, the table renders its own `colgroup`; drop any you had.
41
+ *
29
42
  * @category Components
30
43
  * @subcategory Data Display
31
44
  *
@@ -57,5 +70,25 @@ import { NestedTableContextType } from '../types';
57
70
  * {groups}
58
71
  * </NestedTable>
59
72
  * ```
73
+ *
74
+ * @example
75
+ * ```tsx
76
+ * // Resizable, with the first column frozen and a sticky header
77
+ * <TableContainer maxHeight={400}>
78
+ * <NestedTable
79
+ * resizableColumns
80
+ * freezeControls
81
+ * stickyHeader
82
+ * defaultFrozenColumns={{ start: ['team'] }}>
83
+ * <TableHead>
84
+ * <NestedTableRow isHeader>
85
+ * <NestedTableCellHeader columnId="team">Team</NestedTableCellHeader>
86
+ * <NestedTableCellHeader columnId="size">Headcount</NestedTableCellHeader>
87
+ * </NestedTableRow>
88
+ * </TableHead>
89
+ * <TableBody>{groups}</TableBody>
90
+ * </NestedTable>
91
+ * </TableContainer>
92
+ * ```
60
93
  */
61
- export declare const NestedTable: ({ children, collapsedIconName, expandedIconName, defaultCollapsed, ...rest }: PropsWithChildren & NestedTableContextType & CommonProps & TableHTMLAttributes<HTMLTableElement>) => import("@emotion/react/jsx-runtime").JSX.Element;
94
+ export declare const NestedTable: import("react").ForwardRefExoticComponent<TableProps & import("../types").NestedTableContextType & import("react").RefAttributes<HTMLTableElement>>;
@@ -1,5 +1,4 @@
1
- import { HTMLAttributes } from 'react';
2
- import { CommonProps } from '../../../types/emotion';
1
+ import { NestedTableCellBaseProps } from './NestedTableCellBase';
3
2
  /**
4
3
  * NestedTableCell - Cell for a `NestedTableRow`.
5
4
  *
@@ -33,4 +32,4 @@ import { CommonProps } from '../../../types/emotion';
33
32
  * <NestedTableCell as="th">Headcount</NestedTableCell>
34
33
  * ```
35
34
  */
36
- export declare const NestedTableCell: ({ children, ...props }: React.PropsWithChildren<HTMLAttributes<HTMLTableCellElement>> & CommonProps) => import("@emotion/react/jsx-runtime").JSX.Element;
35
+ export declare const NestedTableCell: (props: Omit<NestedTableCellBaseProps, "adornment" | "trailing">) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { ReactNode } from 'react';
2
+ import { TableCellProps } from '../../TableCell/types';
3
+ export type NestedTableCellBaseProps = React.PropsWithChildren<TableCellProps> & {
4
+ /** Rendered inside the content wrapper, after the content. */
5
+ adornment?: ReactNode;
6
+ /**
7
+ * Rendered after the content wrapper, straight inside the cell — where
8
+ * the table's stylesheet expects a column's resize handle.
9
+ */
10
+ trailing?: ReactNode;
11
+ };
12
+ /**
13
+ * The cell shared by `NestedTableCell` and `NestedTableCellHeader`. Not
14
+ * exported from the package.
15
+ */
16
+ export declare const NestedTableCellBase: ({ children, adornment, trailing, ...props }: NestedTableCellBaseProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { NestedTableCellHeaderProps } from '../types';
2
+ /**
3
+ * NestedTableCellHeader - Column header cell for a `NestedTable`.
4
+ *
5
+ * The nested counterpart of `TableCellHeader`: renders a `th` styled like a
6
+ * `NestedTableCell`, and carries the column's drag handle when the table has
7
+ * `resizableColumns` and its freeze menu when the table has `freezeControls`.
8
+ * Outside those modes it is just a header cell, so it is safe to use in every
9
+ * nested table.
10
+ *
11
+ * Use it in the header `NestedTableRow` (the one with `isHeader`). The
12
+ * toggle column the row adds in front gets no handle or menu, and does not
13
+ * count as a column — `0` is the first header cell you render.
14
+ *
15
+ * @category Components
16
+ * @subcategory Data Display
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <TableHead>
21
+ * <NestedTableRow isHeader>
22
+ * <NestedTableCellHeader columnId="team">Team</NestedTableCellHeader>
23
+ * <NestedTableCellHeader columnId="size">Headcount</NestedTableCellHeader>
24
+ * <NestedTableCellHeader columnId="actions" resizable={false} freezable={false} />
25
+ * </NestedTableRow>
26
+ * </TableHead>
27
+ * ```
28
+ *
29
+ * @see {@link NestedTable} - `resizableColumns`, `frozenColumns`, `freezeControls`
30
+ * @see {@link TableCellHeader} - the same cell for a plain `Table`
31
+ *
32
+ * @accessibility
33
+ * - Renders a semantic `th`
34
+ * - The resize handle and freeze menu are keyboard operable
35
+ */
36
+ export declare const NestedTableCellHeader: ({ children, resizable, freezable, columnId, ...props }: React.PropsWithChildren<NestedTableCellHeaderProps>) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -2,3 +2,4 @@ export * from './NestedTable';
2
2
  export * from './NestedTableCell';
3
3
  export * from './NestedTableCellSubHeader';
4
4
  export * from './NestedTableRow';
5
+ export * from './NestedTableCellHeader';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Width of the toggle column `NestedTableRow` puts in front of every row: the
3
+ * cell's 16px left padding plus the 20px icon box.
4
+ */
5
+ export declare const NESTED_EXPANDER_WIDTH = 36;
@@ -1 +1 @@
1
- export declare const useNestedTableContext: () => import("..").NestedTableContextType;
1
+ export declare const useNestedTableContext: () => import("..").NestedTableContextValue;
@@ -1,5 +1,7 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
2
  import { IconProps } from '../Icon/types';
3
+ import { TableProps } from '../Table/types';
4
+ import { TableCellHeaderProps } from '../TableCellHeader/types';
3
5
  export type NestedTableContextType = {
4
6
  /** Toggle icon shown while a group is collapsed. @default 'carrot-up' */
5
7
  collapsedIconName?: IconProps['name'];
@@ -14,6 +16,35 @@ export type NestedTableContextType = {
14
16
  */
15
17
  defaultCollapsed?: boolean;
16
18
  };
19
+ /** What `NestedTable` hands its rows and cells, beyond its own props. */
20
+ export type NestedTableContextValue = NestedTableContextType & {
21
+ /**
22
+ * Set while columns can freeze or the header sticks. Cells then paint the
23
+ * row's background themselves, and the row paints it opaque, so content
24
+ * scrolled under a stuck cell does not show through.
25
+ */
26
+ opaqueCells?: boolean;
27
+ /**
28
+ * Mirrors the table's `resizableColumns`. Cells read it here rather than
29
+ * from the resize context, whose value changes on every frame of a drag and
30
+ * would re-render every cell in the table with it.
31
+ */
32
+ isResizable?: boolean;
33
+ };
34
+ /**
35
+ * Props for {@link NestedTable}: everything `Table` accepts, plus the group
36
+ * toggle options.
37
+ *
38
+ * Column positions in `columnWidths`, `defaultColumnWidths`,
39
+ * `onColumnWidthsChange` and `frozenColumns` count only your own columns — the
40
+ * toggle column `NestedTableRow` adds in front is left out of all of them.
41
+ */
42
+ export type NestedTableProps = TableProps & NestedTableContextType;
43
+ /**
44
+ * Props for {@link NestedTableCellHeader}: the same column options as
45
+ * `TableCellHeader` — `columnId`, `resizable`, `freezable`.
46
+ */
47
+ export type NestedTableCellHeaderProps = TableCellHeaderProps;
17
48
  export type NestedTableRowContextType = {
18
49
  isCollapsed: boolean;
19
50
  isSubHeader: boolean;
@@ -0,0 +1,27 @@
1
+ import { ColumnFreezeApi } from './types';
2
+ /**
3
+ * Null outside a `Table` that freezes columns or offers freeze controls, so
4
+ * header cells in an ordinary table stay exactly as they were.
5
+ */
6
+ export declare const ColumnFreezeContext: import("react").Context<ColumnFreezeApi | null>;
7
+ /**
8
+ * The enclosing table's column-freezing state, or `null` when it has none.
9
+ *
10
+ * Lets a custom header cell render {@link ColumnFreezeMenu} only when the
11
+ * table asked for freeze controls.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * const MyHeaderCell = ({ children }) => {
16
+ * const columnFreeze = useColumnFreezeContext();
17
+ *
18
+ * return (
19
+ * <TableCell as="th">
20
+ * {children}
21
+ * {columnFreeze?.freezeControls && <ColumnFreezeMenu />}
22
+ * </TableCell>
23
+ * );
24
+ * };
25
+ * ```
26
+ */
27
+ export declare const useColumnFreezeContext: () => ColumnFreezeApi | null;
@@ -0,0 +1,33 @@
1
+ import { ColumnFreezeMenuProps } from './types';
2
+ /**
3
+ * ColumnFreezeMenu - The freeze/unfreeze menu in a table header cell
4
+ *
5
+ * `TableCellHeader` renders it for you when its `Table` has `freezeControls`.
6
+ * Render it yourself only in a custom header cell, passing the column's id;
7
+ * without one it falls back to the `columnId` or position of the `th` it
8
+ * sits in.
9
+ *
10
+ * Any column can be frozen to either edge. It stays where it is until
11
+ * scrolling would take it out of view, then sticks to that edge while the
12
+ * columns between slide underneath.
13
+ *
14
+ * @category Components
15
+ * @subcategory Data Display
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <TableCell as="th" data-column-id="email">
20
+ * Email
21
+ * <ColumnFreezeMenu columnId="email" />
22
+ * </TableCell>
23
+ * ```
24
+ *
25
+ * @see {@link Table} - `freezeControls` and `frozenColumns`
26
+ * @see {@link useColumnFreezeContext} - whether the table wants the menu
27
+ *
28
+ * @accessibility
29
+ * - The trigger is a labelled button, reachable by keyboard even while hidden
30
+ * - Clicks inside the menu do not reach the header cell, so they never sort
31
+ */
32
+ export declare const ColumnFreezeMenu: ({ columnId }: ColumnFreezeMenuProps) => import("@emotion/react/jsx-runtime").JSX.Element;
33
+ export default ColumnFreezeMenu;
@@ -1,5 +1,5 @@
1
1
  import { CommonProps } from '../../types/emotion';
2
- import { ColumnResizeMode } from './types';
2
+ import { ColumnResizeMode, FrozenColumnIndices } from './types';
3
3
  export interface TableBaseProps extends CommonProps {
4
4
  /** Applies the truncation rules resizing depends on. */
5
5
  isResizable?: boolean;
@@ -11,6 +11,13 @@ export interface TableBaseProps extends CommonProps {
11
11
  hasColumnWidths?: boolean;
12
12
  /** How a resize distributes width. See TableProps.columnResizeMode. */
13
13
  columnResizeMode?: ColumnResizeMode;
14
+ /**
15
+ * Positions of the frozen columns on each edge, resolved by `Table` from
16
+ * the ids in TableProps.frozenColumns.
17
+ */
18
+ frozenIndices?: FrozenColumnIndices;
19
+ /** Keeps the header row in view. See TableProps.stickyHeader. */
20
+ stickyHeader?: boolean;
14
21
  }
15
22
  /**
16
23
  * The styled element behind `Table`.
@@ -0,0 +1,44 @@
1
+ import { RefObject } from 'react';
2
+ import { ColumnFreezeApi, FrozenColumnIndices, FrozenColumns } from '../types';
3
+ /** Custom property holding the sticky offset of the column at `index`. */
4
+ export declare const frozenOffsetVar: (index: number) => string;
5
+ /** Attributes naming the frozen column that currently casts each shadow. */
6
+ export declare const SHADOW_START_ATTR = "data-frozen-shadow-start";
7
+ export declare const SHADOW_END_ATTR = "data-frozen-shadow-end";
8
+ interface UseColumnFreezeOptions {
9
+ tableRef: RefObject<HTMLTableElement | null>;
10
+ frozenColumns?: FrozenColumns;
11
+ defaultFrozenColumns?: FrozenColumns;
12
+ onFrozenColumnsChange?: (frozenColumns: Required<FrozenColumns>) => void;
13
+ freezeControls: boolean;
14
+ controlled: boolean;
15
+ }
16
+ /**
17
+ * Frozen-column state for `Table`, plus the DOM work that keeps frozen cells
18
+ * in place.
19
+ *
20
+ * ## Ids are resolved against the header
21
+ *
22
+ * The caller speaks in column ids; the stylesheet needs positions. After every
23
+ * render the header cells are read back, ids matched to positions, and the
24
+ * positions handed to `TableBase`. Only the set of frozen positions ever
25
+ * reaches emotion, so a column changing width mints no new rules.
26
+ *
27
+ * ## Offsets live in custom properties
28
+ *
29
+ * Each frozen cell is `position: sticky` with a `left`/`right` equal to the
30
+ * width of the frozen columns between it and its edge. Those widths change
31
+ * with every frame of a column resize, so they are written to custom
32
+ * properties on the table element directly.
33
+ *
34
+ * ## Shadows follow the scroll position
35
+ *
36
+ * `data-frozen-shadow-start` / `-end` on the table name the frozen column on
37
+ * each side that has content scrolled underneath it, so the divider only
38
+ * shows when there is something to divide.
39
+ */
40
+ export declare const useColumnFreeze: ({ tableRef, frozenColumns, defaultFrozenColumns, onFrozenColumnsChange, freezeControls, controlled, }: UseColumnFreezeOptions) => {
41
+ api: ColumnFreezeApi;
42
+ indices: FrozenColumnIndices;
43
+ };
44
+ export {};
@@ -2,5 +2,7 @@ export { default } from './Table';
2
2
  export { default as ColumnResizeHandle } from './ColumnResizeHandle';
3
3
  export { useColumnResize } from './hooks/useColumnResize';
4
4
  export { useColumnResizeContext } from './ColumnResizeContext';
5
+ export { default as ColumnFreezeMenu } from './ColumnFreezeMenu';
6
+ export { useColumnFreezeContext } from './ColumnFreezeContext';
5
7
  export * from './types';
6
8
  export * from './ColumnResizeHandle.types';