@versini/ui-datagrid 4.2.13 → 5.0.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 CHANGED
@@ -6,7 +6,7 @@ A data grid component library for React built with div-based ARIA grid layout fo
6
6
  - **Flexible Layout**: Div-based structure allows for complex styling
7
7
  - **CSS Grid Columns**: Define column widths with CSS Grid track sizes
8
8
  - **Row Virtualization**: Windowing for large datasets — only viewport rows stay in the DOM
9
- - **Animated Height**: Smooth height transitions when content changes
9
+ - **Animated Height**: Smooth height transitions when content changes (`animateHeight`)
10
10
  - **Sorting**: Built-in sorting utilities and sortable column headers
11
11
  - **Sticky Header/Footer**: With optional blur effects
12
12
  - **Loading States**: Built-in loading overlay with spinner
@@ -38,12 +38,6 @@ import { DataGridCellSort } from "@versini/ui-datagrid/cell-sort";
38
38
  // Virtualized body for large datasets
39
39
  import { DataGridInfiniteBody } from "@versini/ui-datagrid/infinite";
40
40
 
41
- // Animated height wrapper
42
- import {
43
- AnimatedWrapper,
44
- useAnimatedHeight
45
- } from "@versini/ui-datagrid/animated";
46
-
47
41
  // Sorting utilities
48
42
  import {
49
43
  sortByDate,
@@ -144,39 +138,42 @@ import { DataGridHeader } from "@versini/ui-datagrid/header";
144
138
  import { DataGridRow } from "@versini/ui-datagrid/row";
145
139
  import { DataGridCell } from "@versini/ui-datagrid/cell";
146
140
  import { DataGridInfiniteBody } from "@versini/ui-datagrid/infinite";
147
- import { AnimatedWrapper } from "@versini/ui-datagrid/animated";
148
141
 
149
142
  function MyInfiniteTable({ data }) {
150
143
  const [visibleCount, setVisibleCount] = useState(0);
151
144
 
152
145
  return (
153
- <AnimatedWrapper dependency={visibleCount}>
154
- <DataGrid maxHeight="500px" stickyHeader>
155
- <DataGridHeader caption={`Showing ${visibleCount} of ${data.length}`}>
156
- <DataGridRow>
157
- <DataGridCell>Name</DataGridCell>
158
- <DataGridCell>Date</DataGridCell>
159
- </DataGridRow>
160
- </DataGridHeader>
146
+ <DataGrid maxHeight="500px" stickyHeader animateHeight>
147
+ <DataGridHeader caption={`Showing ${visibleCount} of ${data.length}`}>
148
+ <DataGridRow>
149
+ <DataGridCell>Name</DataGridCell>
150
+ <DataGridCell>Date</DataGridCell>
151
+ </DataGridRow>
152
+ </DataGridHeader>
161
153
 
162
- <DataGridInfiniteBody
163
- data={data}
164
- estimatedRowHeight={48}
165
- onVisibleCountChange={(count) => setVisibleCount(count)}
166
- >
167
- {(item) => (
168
- <DataGridRow key={item.id}>
169
- <DataGridCell>{item.name}</DataGridCell>
170
- <DataGridCell>{item.date}</DataGridCell>
171
- </DataGridRow>
172
- )}
173
- </DataGridInfiniteBody>
174
- </DataGrid>
175
- </AnimatedWrapper>
154
+ <DataGridInfiniteBody
155
+ data={data}
156
+ estimatedRowHeight={48}
157
+ onVisibleCountChange={(count) => setVisibleCount(count)}
158
+ >
159
+ {(item) => (
160
+ <DataGridRow key={item.id}>
161
+ <DataGridCell>{item.name}</DataGridCell>
162
+ <DataGridCell>{item.date}</DataGridCell>
163
+ </DataGridRow>
164
+ )}
165
+ </DataGridInfiniteBody>
166
+ </DataGrid>
176
167
  );
177
168
  }
178
169
  ```
179
170
 
171
+ ### Animated height
172
+
173
+ `animateHeight` animates the grid's height over 300ms whenever its content grows or shrinks, and keeps its border, shadow and rounded corners intact while it does. It follows the grid's measured content height, so there is no dependency value to pass. A width change, such as a window resize, is not animated, and neither is the grid mounting: a loading line swapped for a freshly mounted grid appears without a transition. It is skipped when the user prefers reduced motion. It is meant for grids bounded by `maxHeight` or a sticky header/footer; a page-scroll `DataGridInfiniteBody` changes height as rows are measured while scrolling.
174
+
175
+ Migrating from `AnimatedWrapper` (removed in v5): replace `<AnimatedWrapper dependency={n}><DataGrid …></AnimatedWrapper>` with `<DataGrid animateHeight …>`. The duration is fixed at 300ms, and there is no replacement for `duration`, `enabled`, `className`, the standalone `useAnimatedHeight` hook or its `isAnimating` value.
176
+
180
177
  `DataGridInfiniteBody` keeps `columns` (including intrinsic `auto` tracks) working because it renders rows in normal grid flow between two full-span spacer elements (not absolutely positioned). It windows against the DataGrid's own scroll container — created when you set `maxHeight` or a sticky header/footer — and otherwise against the page (window scroll). To scroll inside your own bounded container, set `maxHeight` on the `DataGrid` rather than relying on an outer wrapper.
181
178
 
182
179
  Notes:
@@ -335,6 +332,7 @@ function MySortableTable({ data }) {
335
332
  | Prop | Type | Default | Description |
336
333
  | ------------------ | ----------------------------------------------- | ---------- | -------------------------------------- |
337
334
  | `mode` | `'dark' \| 'light' \| 'system' \| 'alt-system'` | `'system'` | Theme mode |
335
+ | `animateHeight` | `boolean` | `false` | Animate height when content changes |
338
336
  | `compact` | `boolean` | `false` | Reduced padding |
339
337
  | `stickyHeader` | `boolean` | `false` | Fixed header while scrolling |
340
338
  | `stickyFooter` | `boolean` | `false` | Fixed footer while scrolling |
package/dist/7.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
package/dist/8.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,2 +1,2 @@
1
1
  import type { DataGridProps } from "./DataGridTypes.js";
2
- export declare const DataGrid: ({ className, wrapperClassName, children, mode, compact, stickyHeader, stickyFooter, blurEffect, maxHeight, loading, columns, ...rest }: DataGridProps) => import("react").JSX.Element;
2
+ export declare const DataGrid: ({ animateHeight, className, wrapperClassName, children, mode, compact, stickyHeader, stickyFooter, blurEffect, maxHeight, loading, columns, ...rest }: DataGridProps) => import("react").JSX.Element;
@@ -16,6 +16,14 @@ export type DataGridProps = {
16
16
  * The content of the DataGrid (DataGridHeader, DataGridBody, DataGridFooter).
17
17
  */
18
18
  children: React.ReactNode;
19
+ /**
20
+ * If true, the data grid animates its height whenever its content grows or
21
+ * shrinks, e.g. when rows are filtered or swapped. The grid's own border,
22
+ * shadow and rounded corners stay intact throughout. A change in width, such
23
+ * as a window resize, is not animated.
24
+ * @default false
25
+ */
26
+ animateHeight?: boolean;
19
27
  /**
20
28
  * CSS class to apply to the data grid.
21
29
  */
@@ -1,14 +1,94 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- import { useCallback, useMemo, useRef, useState } from "react";
7
+ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
8
8
  import { BlurEffects } from "../7.js";
9
9
  import { getDataGridClasses } from "../y.js";
10
10
  import { DataGridContext } from "../8.js";
11
- const DataGrid = ({ className, wrapperClassName, children, mode = "system", compact = false, stickyHeader = false, stickyFooter = false, blurEffect = BlurEffects.NONE, maxHeight, loading = false, columns, ...rest })=>{
11
+ const HEIGHT_ANIMATION_DURATION = 300;
12
+ function prefersReducedMotion() {
13
+ return Boolean(window.matchMedia?.("(prefers-reduced-motion: reduce)").matches);
14
+ }
15
+ function useHeightAnimation(wrapper, grid, enabled) {
16
+ useLayoutEffect(()=>{
17
+ if (!enabled || !wrapper || !grid) return;
18
+ const scroller = grid.parentElement;
19
+ const clipped = scroller && scroller !== wrapper ? [
20
+ wrapper,
21
+ scroller
22
+ ] : [
23
+ wrapper
24
+ ];
25
+ let wrapperHeight = wrapper.offsetHeight;
26
+ let gridHeight = grid.offsetHeight;
27
+ let gridWidth = grid.offsetWidth;
28
+ let animation;
29
+ let frame = 0;
30
+ const unlock = ()=>{
31
+ for (const el of clipped)el.style.removeProperty("overflow-y");
32
+ };
33
+ const settle = ()=>{
34
+ unlock();
35
+ wrapperHeight = wrapper.offsetHeight;
36
+ if (animation) {
37
+ animation = void 0;
38
+ frame = requestAnimationFrame(()=>observer.observe(wrapper));
39
+ }
40
+ };
41
+ const observer = new ResizeObserver((entries)=>{
42
+ if (!entries.some((entry)=>entry.target === grid)) {
43
+ wrapperHeight = wrapper.offsetHeight;
44
+ return;
45
+ }
46
+ const nextGridHeight = grid.offsetHeight;
47
+ const nextGridWidth = grid.offsetWidth;
48
+ const resized = nextGridWidth !== gridWidth;
49
+ const heightChanged = nextGridHeight !== gridHeight;
50
+ gridHeight = nextGridHeight;
51
+ gridWidth = nextGridWidth;
52
+ if (!heightChanged || resized && !animation) {
53
+ wrapperHeight = wrapper.offsetHeight;
54
+ return;
55
+ }
56
+ const from = animation ? wrapper.offsetHeight : wrapperHeight;
57
+ animation?.cancel();
58
+ const to = wrapper.offsetHeight;
59
+ if (from === to || prefersReducedMotion()) return void settle();
60
+ if (!animation) observer.unobserve(wrapper);
61
+ for (const el of clipped)el.style.overflowY = "hidden";
62
+ const current = wrapper.animate({
63
+ height: [
64
+ `${from}px`,
65
+ `${to}px`
66
+ ]
67
+ }, {
68
+ duration: HEIGHT_ANIMATION_DURATION,
69
+ easing: "ease-out"
70
+ });
71
+ const settleIfCurrent = ()=>animation === current && settle();
72
+ current.onfinish = settleIfCurrent;
73
+ current.oncancel = settleIfCurrent;
74
+ animation = current;
75
+ });
76
+ observer.observe(grid);
77
+ observer.observe(wrapper);
78
+ return ()=>{
79
+ observer.disconnect();
80
+ cancelAnimationFrame(frame);
81
+ animation?.cancel();
82
+ animation = void 0;
83
+ unlock();
84
+ };
85
+ }, [
86
+ enabled,
87
+ wrapper,
88
+ grid
89
+ ]);
90
+ }
91
+ const DataGrid = ({ animateHeight = false, className, wrapperClassName, children, mode = "system", compact = false, stickyHeader = false, stickyFooter = false, blurEffect = BlurEffects.NONE, maxHeight, loading = false, columns, ...rest })=>{
12
92
  const [headerCount, setHeaderCount] = useState(0);
13
93
  const [footerCount, setFooterCount] = useState(0);
14
94
  const [headerHeight, setHeaderHeight] = useState(0);
@@ -40,6 +120,23 @@ const DataGrid = ({ className, wrapperClassName, children, mode = "system", comp
40
120
  const scrollContainerRef = useCallback((el)=>{
41
121
  setScrollContainer(el);
42
122
  }, []);
123
+ const [wrapperElement, setWrapperElement] = useState(null);
124
+ const [gridElement, setGridElement] = useState(null);
125
+ const wrapperIsScroller = hasInternalScroller && !hasSticky;
126
+ const setWrapper = useCallback((el)=>{
127
+ if (animateHeight) setWrapperElement(el);
128
+ if (wrapperIsScroller) setScrollContainer(el);
129
+ }, [
130
+ animateHeight,
131
+ wrapperIsScroller
132
+ ]);
133
+ const setGrid = useCallback((el)=>{
134
+ gridRef.current = el;
135
+ if (animateHeight) setGridElement(el);
136
+ }, [
137
+ animateHeight
138
+ ]);
139
+ useHeightAnimation(wrapperElement, gridElement, animateHeight);
43
140
  const classes = useMemo(()=>getDataGridClasses({
44
141
  mode,
45
142
  className,
@@ -110,7 +207,7 @@ const DataGrid = ({ className, wrapperClassName, children, mode = "system", comp
110
207
  gridTemplateColumns: columns.join(" ")
111
208
  } : void 0;
112
209
  const gridContent = jsx("div", {
113
- ref: gridRef,
210
+ ref: setGrid,
114
211
  role: "grid",
115
212
  "aria-labelledby": captionId,
116
213
  "aria-rowcount": rowCount,
@@ -143,7 +240,7 @@ const DataGrid = ({ className, wrapperClassName, children, mode = "system", comp
143
240
  ]
144
241
  }),
145
242
  jsx("div", {
146
- ref: hasInternalScroller && !hasSticky ? scrollContainerRef : void 0,
243
+ ref: setWrapper,
147
244
  className: classes.wrapper,
148
245
  style: wrapperStyle,
149
246
  children: hasSticky ? jsx("div", {
@@ -0,0 +1,24 @@
1
+ export declare const HEIGHT_ANIMATION_DURATION = 300;
2
+ /**
3
+ * Animates the wrapper's height whenever the grid inside it changes height.
4
+ *
5
+ * The wrapper is the element that carries the grid's rounded corners, shadow
6
+ * and any ring passed through `wrapperClassName`. Clipping it with its own
7
+ * `overflow` never clips its own wrapper-shadow, which is why the animation
8
+ * lives here and not on an element around the grid: an outer clip would cut the
9
+ * border off for the length of the animation.
10
+ *
11
+ * The grid's height drives the animation because it never depends on the
12
+ * wrapper's: animating the wrapper cannot feed back into the measurement. Both
13
+ * elements are passed in rather than read from refs, because the grid element
14
+ * is replaced when a sticky header or footer registers after the first render,
15
+ * and the observer has to follow it. The wrapper is observed too, only to keep
16
+ * its resting height current when it changes on its own, such as a new
17
+ * max-height, and it is unobserved while it animates: resizing an element from
18
+ * inside its own observer callback is what raises "ResizeObserver loop
19
+ * completed with undelivered notifications". A width change re-wraps text and
20
+ * changes the height too, but that is a resize, not new content, so it is not
21
+ * animated.
22
+ *
23
+ */
24
+ export declare function useHeightAnimation(wrapper: HTMLElement | null, grid: HTMLElement | null, enabled: boolean): void;
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
package/dist/u.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
package/dist/y.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- @versini/ui-datagrid v4.2.13
2
+ @versini/ui-datagrid v5.0.0
3
3
  © 2026 gizmette.com
4
4
  */
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/ui-datagrid",
3
- "version": "4.2.13",
3
+ "version": "5.0.0",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -13,10 +13,6 @@
13
13
  },
14
14
  "type": "module",
15
15
  "exports": {
16
- "./animated": {
17
- "types": "./dist/DataGridAnimated/index.d.ts",
18
- "import": "./dist/DataGridAnimated/index.js"
19
- },
20
16
  "./body": {
21
17
  "types": "./dist/DataGridBody/index.d.ts",
22
18
  "import": "./dist/DataGridBody/index.js"
@@ -64,12 +60,12 @@
64
60
  ],
65
61
  "devDependencies": {
66
62
  "@testing-library/jest-dom": "7.0.1",
67
- "@versini/ui-button": "15.3.9",
63
+ "@versini/ui-button": "15.3.10",
68
64
  "@versini/ui-styles": "9.7.9"
69
65
  },
70
66
  "dependencies": {
71
67
  "@tanstack/react-virtual": "3.14.13",
72
- "@versini/ui-icons": "4.29.3",
68
+ "@versini/ui-icons": "4.30.0",
73
69
  "clsx": "2.1.1",
74
70
  "tailwindcss": "4.3.3"
75
71
  },
@@ -1,50 +0,0 @@
1
- export type AnimatedWrapperProps = {
2
- /**
3
- * The content to wrap (typically a DataGrid).
4
- */
5
- children: React.ReactNode;
6
- /**
7
- * Value that triggers animation when changed. Typically the count of items or
8
- * a key that changes.
9
- */
10
- dependency: unknown;
11
- /**
12
- * Animation duration in milliseconds.
13
- * @default 300
14
- */
15
- duration?: number;
16
- /**
17
- * Whether animation is enabled.
18
- * @default true
19
- */
20
- enabled?: boolean;
21
- /**
22
- * Additional class name for the wrapper.
23
- */
24
- className?: string;
25
- };
26
- /**
27
- * Wrapper component that animates height changes when content changes.
28
- *
29
- * @example
30
- * ```tsx
31
- * const [visibleCount, setVisibleCount] = useState(0);
32
- *
33
- * return (
34
- * <AnimatedWrapper dependency={visibleCount}>
35
- * <DataGrid maxHeight="400px" stickyHeader>
36
- * <DataGridInfiniteBody
37
- * data={largeData}
38
- * onVisibleCountChange={(count) => setVisibleCount(count)}
39
- * >
40
- * {(row) => (
41
- * <DataGridRow key={row.id}>...</DataGridRow>
42
- * )}
43
- * </DataGridInfiniteBody>
44
- * </DataGrid>
45
- * </AnimatedWrapper>
46
- * );
47
- * ```
48
- *
49
- */
50
- export declare const AnimatedWrapper: ({ children, dependency, duration, enabled, className, }: AnimatedWrapperProps) => import("react").JSX.Element;
@@ -1,4 +0,0 @@
1
- export type { AnimatedWrapperProps } from "./AnimatedWrapper.js";
2
- export { AnimatedWrapper } from "./AnimatedWrapper.js";
3
- export type { UseAnimatedHeightOptions, UseAnimatedHeightReturn, } from "./useAnimatedHeight.js";
4
- export { useAnimatedHeight } from "./useAnimatedHeight.js";
@@ -1,92 +0,0 @@
1
- /*!
2
- @versini/ui-datagrid v4.2.13
3
- © 2026 gizmette.com
4
- */
5
-
6
- import { jsx } from "react/jsx-runtime";
7
- import { useLayoutEffect, useRef, useState } from "react";
8
- const DEFAULT_ANIMATION_DURATION = 300;
9
- function useAnimatedHeight(dependency, options) {
10
- const { duration = DEFAULT_ANIMATION_DURATION, enabled = true } = options ?? {};
11
- const ref = useRef(null);
12
- const [animationState, setAnimationState] = useState({
13
- height: "auto",
14
- isAnimating: false
15
- });
16
- const lastHeightRef = useRef(0);
17
- const prevDependencyRef = useRef(dependency);
18
- const animationFrameRef = useRef(0);
19
- const timeoutRef = useRef(null);
20
- useLayoutEffect(()=>{
21
- if (!ref.current || !enabled) return;
22
- if (0 === lastHeightRef.current) {
23
- lastHeightRef.current = ref.current.offsetHeight;
24
- prevDependencyRef.current = dependency;
25
- setAnimationState((state)=>state.isAnimating ? {
26
- height: "auto",
27
- isAnimating: false
28
- } : state);
29
- return;
30
- }
31
- if (prevDependencyRef.current === dependency) return;
32
- prevDependencyRef.current = dependency;
33
- const previousHeight = lastHeightRef.current;
34
- const newHeight = ref.current.scrollHeight;
35
- lastHeightRef.current = newHeight;
36
- if (previousHeight === newHeight || 0 === previousHeight) return void setAnimationState((state)=>state.isAnimating ? {
37
- height: "auto",
38
- isAnimating: false
39
- } : state);
40
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
41
- if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
42
- setAnimationState({
43
- height: previousHeight,
44
- isAnimating: true
45
- });
46
- animationFrameRef.current = requestAnimationFrame(()=>{
47
- animationFrameRef.current = requestAnimationFrame(()=>{
48
- setAnimationState({
49
- height: newHeight,
50
- isAnimating: true
51
- });
52
- timeoutRef.current = setTimeout(()=>{
53
- setAnimationState({
54
- height: "auto",
55
- isAnimating: false
56
- });
57
- }, duration);
58
- });
59
- });
60
- return ()=>{
61
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
62
- if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
63
- };
64
- }, [
65
- dependency,
66
- duration,
67
- enabled
68
- ]);
69
- const style = enabled ? {
70
- height: "auto" === animationState.height ? "auto" : `${animationState.height}px`,
71
- overflow: animationState.isAnimating ? "hidden" : void 0,
72
- transition: animationState.isAnimating ? `height ${duration}ms ease-out` : void 0
73
- } : {};
74
- return {
75
- ref,
76
- style,
77
- isAnimating: animationState.isAnimating
78
- };
79
- }
80
- const AnimatedWrapper = ({ children, dependency, duration, enabled = true, className })=>{
81
- const { ref, style } = useAnimatedHeight(dependency, {
82
- duration,
83
- enabled
84
- });
85
- return jsx("div", {
86
- ref: ref,
87
- style: style,
88
- className: className,
89
- children: children
90
- });
91
- };
92
- export { AnimatedWrapper, useAnimatedHeight };
@@ -1,49 +0,0 @@
1
- export type UseAnimatedHeightOptions = {
2
- /**
3
- * Animation duration in milliseconds.
4
- * @default 300
5
- */
6
- duration?: number;
7
- /**
8
- * Whether animation is enabled.
9
- * @default true
10
- */
11
- enabled?: boolean;
12
- };
13
- export type UseAnimatedHeightReturn<T extends HTMLElement> = {
14
- /**
15
- * Ref to attach to the container element.
16
- */
17
- ref: React.RefObject<T | null>;
18
- /**
19
- * Style object to apply to the container.
20
- */
21
- style: React.CSSProperties;
22
- /**
23
- * Whether an animation is currently in progress.
24
- */
25
- isAnimating: boolean;
26
- };
27
- /**
28
- * Hook that provides smooth height animations when content changes.
29
- *
30
- * Uses FLIP technique: captures height before render via a persistent ref, then
31
- * animates from old height to new height after the DOM updates.
32
- *
33
- * @param dependency - Value that triggers animation when changed.
34
- * @param options - Configuration options.
35
- *
36
- * @example
37
- * ```tsx
38
- * const items = useMemo(() => data.slice(0, visibleCount), [data, visibleCount]);
39
- * const { ref, style } = useAnimatedHeight(items.length);
40
- *
41
- * return (
42
- * <div ref={ref} style={style}>
43
- * {items.map((item) => <Row key={item.id} {...item} />)}
44
- * </div>
45
- * );
46
- * ```
47
- *
48
- */
49
- export declare function useAnimatedHeight<T, E extends HTMLElement = HTMLDivElement>(dependency: T, options?: UseAnimatedHeightOptions): UseAnimatedHeightReturn<E>;