@tiny-design/react 1.2.0 → 1.3.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/es/drawer/drawer.js +3 -2
- package/es/drawer/drawer.js.map +1 -1
- package/es/message/message.js +3 -2
- package/es/message/message.js.map +1 -1
- package/es/modal/modal.js +3 -2
- package/es/modal/modal.js.map +1 -1
- package/es/overlay/overlay.js +2 -2
- package/es/overlay/overlay.js.map +1 -1
- package/es/transition/index.js +1 -0
- package/es/transition/index.js.map +1 -1
- package/es/transition/transition.d.ts +20 -5
- package/es/transition/transition.js +33 -8
- package/es/transition/transition.js.map +1 -1
- package/es/transition/use-transition.js +137 -0
- package/es/transition/use-transition.js.map +1 -0
- package/es/waterfall/waterfall.js +62 -39
- package/es/waterfall/waterfall.js.map +1 -1
- package/lib/drawer/drawer.js +5 -4
- package/lib/drawer/drawer.js.map +1 -1
- package/lib/message/message.js +3 -2
- package/lib/message/message.js.map +1 -1
- package/lib/modal/modal.js +5 -4
- package/lib/modal/modal.js.map +1 -1
- package/lib/overlay/overlay.js +3 -3
- package/lib/overlay/overlay.js.map +1 -1
- package/lib/transition/index.js +1 -0
- package/lib/transition/index.js.map +1 -1
- package/lib/transition/transition.d.ts +20 -5
- package/lib/transition/transition.js +32 -7
- package/lib/transition/transition.js.map +1 -1
- package/lib/transition/use-transition.js +138 -0
- package/lib/transition/use-transition.js.map +1 -0
- package/lib/waterfall/waterfall.js +61 -38
- package/lib/waterfall/waterfall.js.map +1 -1
- package/package.json +3 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.js");
|
|
2
2
|
const require_config_context = require("../config-provider/config-context.js");
|
|
3
3
|
const require_general = require("../_utils/general.js");
|
|
4
|
+
const require_index = require("../transition/index.js");
|
|
4
5
|
const require_use_breakpoint = require("./hooks/use-breakpoint.js");
|
|
5
6
|
const require_use_positions = require("./hooks/use-positions.js");
|
|
6
7
|
let react = require("react");
|
|
@@ -8,7 +9,6 @@ react = require_runtime.__toESM(react);
|
|
|
8
9
|
let classnames = require("classnames");
|
|
9
10
|
classnames = require_runtime.__toESM(classnames);
|
|
10
11
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
|
-
let react_transition_group = require("react-transition-group");
|
|
12
12
|
//#region src/waterfall/waterfall.tsx
|
|
13
13
|
const Waterfall = react.default.forwardRef((props, ref) => {
|
|
14
14
|
const { prefixCls: customisedCls, className, style, columns = 3, gutter = 0, items, itemRender, onLayoutChange, ...otherProps } = props;
|
|
@@ -72,6 +72,31 @@ const Waterfall = react.default.forwardRef((props, ref) => {
|
|
|
72
72
|
items,
|
|
73
73
|
onLayoutChange
|
|
74
74
|
]);
|
|
75
|
+
const prevItemsRef = (0, react.useRef)(items || []);
|
|
76
|
+
const [exitingItems, setExitingItems] = (0, react.useState)(/* @__PURE__ */ new Map());
|
|
77
|
+
(0, react.useEffect)(() => {
|
|
78
|
+
const currentKeys = new Set((items || []).map((item, i) => item.key ?? i));
|
|
79
|
+
const removed = /* @__PURE__ */ new Map();
|
|
80
|
+
prevItemsRef.current.forEach((item, index) => {
|
|
81
|
+
const key = item.key ?? index;
|
|
82
|
+
if (!currentKeys.has(key)) removed.set(key, item);
|
|
83
|
+
});
|
|
84
|
+
if (removed.size > 0) setExitingItems((prev) => {
|
|
85
|
+
const next = new Map(prev);
|
|
86
|
+
removed.forEach((item, key) => next.set(key, item));
|
|
87
|
+
return next;
|
|
88
|
+
});
|
|
89
|
+
prevItemsRef.current = items || [];
|
|
90
|
+
}, [items]);
|
|
91
|
+
const handleExited = (0, react.useCallback)((key) => {
|
|
92
|
+
itemRefsMap.current.delete(key);
|
|
93
|
+
setExitingItems((prev) => {
|
|
94
|
+
const next = new Map(prev);
|
|
95
|
+
next.delete(key);
|
|
96
|
+
return next;
|
|
97
|
+
});
|
|
98
|
+
collectItemSizes();
|
|
99
|
+
}, [collectItemSizes]);
|
|
75
100
|
const cls = (0, classnames.default)(prefixCls, className);
|
|
76
101
|
const containerStyle = {
|
|
77
102
|
...style,
|
|
@@ -79,49 +104,47 @@ const Waterfall = react.default.forwardRef((props, ref) => {
|
|
|
79
104
|
height: totalHeight || void 0
|
|
80
105
|
};
|
|
81
106
|
const mergedItems = items || [];
|
|
82
|
-
|
|
107
|
+
const renderItem = (item, index, isExiting) => {
|
|
108
|
+
const key = item.key ?? index;
|
|
109
|
+
const position = itemPositions.get(key);
|
|
110
|
+
const hasPosition = !!position;
|
|
111
|
+
const columnIndex = position?.column ?? 0;
|
|
112
|
+
const itemStyle = {
|
|
113
|
+
position: "absolute",
|
|
114
|
+
width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,
|
|
115
|
+
left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,
|
|
116
|
+
top: position?.top ?? 0,
|
|
117
|
+
transition: hasPosition ? "top 0.3s ease, left 0.3s ease, opacity 0.3s ease" : "none",
|
|
118
|
+
opacity: hasPosition ? 1 : 0
|
|
119
|
+
};
|
|
120
|
+
const content = item.children ?? itemRender?.({
|
|
121
|
+
...item,
|
|
122
|
+
index,
|
|
123
|
+
column: columnIndex
|
|
124
|
+
});
|
|
125
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_index.default, {
|
|
126
|
+
in: !isExiting,
|
|
127
|
+
timeout: 300,
|
|
128
|
+
appear: false,
|
|
129
|
+
unmountOnExit: true,
|
|
130
|
+
classNames: `${prefixCls}__item-fade`,
|
|
131
|
+
onExited: () => handleExited(key),
|
|
132
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
133
|
+
ref: (el) => setItemRef(key, el),
|
|
134
|
+
className: `${prefixCls}__item`,
|
|
135
|
+
style: itemStyle,
|
|
136
|
+
children: content
|
|
137
|
+
})
|
|
138
|
+
}, key);
|
|
139
|
+
};
|
|
140
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
83
141
|
ref,
|
|
84
142
|
...otherProps,
|
|
85
143
|
className: cls,
|
|
86
144
|
style: containerStyle,
|
|
87
145
|
onLoad: collectItemSizes,
|
|
88
146
|
onError: collectItemSizes,
|
|
89
|
-
children:
|
|
90
|
-
component: null,
|
|
91
|
-
children: mergedItems.map((item, index) => {
|
|
92
|
-
const key = item.key ?? index;
|
|
93
|
-
const position = itemPositions.get(key);
|
|
94
|
-
const hasPosition = !!position;
|
|
95
|
-
const columnIndex = position?.column ?? 0;
|
|
96
|
-
const itemStyle = {
|
|
97
|
-
position: "absolute",
|
|
98
|
-
width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,
|
|
99
|
-
left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,
|
|
100
|
-
top: position?.top ?? 0,
|
|
101
|
-
transition: hasPosition ? "top 0.3s ease, left 0.3s ease, opacity 0.3s ease" : "none",
|
|
102
|
-
opacity: hasPosition ? 1 : 0
|
|
103
|
-
};
|
|
104
|
-
const content = item.children ?? itemRender?.({
|
|
105
|
-
...item,
|
|
106
|
-
index,
|
|
107
|
-
column: columnIndex
|
|
108
|
-
});
|
|
109
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_transition_group.CSSTransition, {
|
|
110
|
-
timeout: 300,
|
|
111
|
-
classNames: `${prefixCls}__item-fade`,
|
|
112
|
-
onExited: () => {
|
|
113
|
-
itemRefsMap.current.delete(key);
|
|
114
|
-
collectItemSizes();
|
|
115
|
-
},
|
|
116
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
117
|
-
ref: (el) => setItemRef(key, el),
|
|
118
|
-
className: `${prefixCls}__item`,
|
|
119
|
-
style: itemStyle,
|
|
120
|
-
children: content
|
|
121
|
-
})
|
|
122
|
-
}, key);
|
|
123
|
-
})
|
|
124
|
-
})
|
|
147
|
+
children: [mergedItems.map((item, index) => renderItem(item, index, false)), Array.from(exitingItems.entries()).map(([key, item]) => renderItem(item, Number(key), true))]
|
|
125
148
|
});
|
|
126
149
|
});
|
|
127
150
|
Waterfall.displayName = "Waterfall";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"waterfall.js","names":["React","getPrefixCls","ConfigContext","useBreakpoint","responsiveArray","usePositions","TransitionGroup","CSSTransition"],"sources":["../../src/waterfall/waterfall.tsx"],"sourcesContent":["import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport classNames from 'classnames';\nimport { CSSTransition, TransitionGroup } from 'react-transition-group';\nimport { ConfigContext } from '../config-provider/config-context';\nimport { getPrefixCls } from '../_utils/general';\nimport { Breakpoint, WaterfallItem, WaterfallProps } from './types';\nimport useBreakpoint, { responsiveArray } from './hooks/use-breakpoint';\nimport usePositions, { ItemHeightData } from './hooks/use-positions';\n\nconst Waterfall = React.forwardRef<HTMLDivElement, WaterfallProps>((props, ref) => {\n const {\n prefixCls: customisedCls,\n className,\n style,\n columns = 3,\n gutter = 0,\n items,\n itemRender,\n onLayoutChange,\n ...otherProps\n } = props;\n\n const configContext = useContext(ConfigContext);\n const prefixCls = getPrefixCls('waterfall', configContext.prefixCls, customisedCls);\n\n // ===================== Breakpoint =====================\n const screens = useBreakpoint();\n\n const columnCount = React.useMemo<number>(() => {\n if (typeof columns === 'number') {\n return columns;\n }\n\n const matchingBreakpoint = responsiveArray.find(\n (bp: Breakpoint) => screens[bp] && columns[bp] !== undefined,\n );\n\n if (matchingBreakpoint) {\n return columns[matchingBreakpoint] as number;\n }\n\n return columns.xs ?? 1;\n }, [columns, screens]);\n\n // ====================== Gutter ======================\n const [horizontalGutter, verticalGutter] = Array.isArray(gutter)\n ? gutter\n : [gutter, gutter];\n\n // =================== Item Refs ===================\n const itemRefsMap = useRef<Map<React.Key, HTMLDivElement | null>>(new Map());\n\n const setItemRef = useCallback((key: React.Key, el: HTMLDivElement | null) => {\n itemRefsMap.current.set(key, el);\n }, []);\n\n // ================= Item Heights ==================\n const [itemHeights, setItemHeights] = useState<ItemHeightData[]>([]);\n\n const collectItemSizes = useCallback(() => {\n if (!items || items.length === 0) {\n setItemHeights([]);\n return;\n }\n\n const nextHeights = items.map<ItemHeightData>((item, index) => {\n const key = item.key ?? index;\n const el = itemRefsMap.current.get(key);\n const height = el ? el.getBoundingClientRect().height : 0;\n return [key, height, item.column];\n });\n\n setItemHeights((prev) => {\n const isSame =\n prev.length === nextHeights.length &&\n prev.every((p, i) => p[0] === nextHeights[i][0] && p[1] === nextHeights[i][1]);\n return isSame ? prev : nextHeights;\n });\n }, [items]);\n\n // ================= Positions ==================\n const [itemPositions, totalHeight] = usePositions(itemHeights, columnCount, verticalGutter);\n\n // Collect sizes on items/columns change\n useEffect(() => {\n collectItemSizes();\n }, [items, columnCount, collectItemSizes]);\n\n // ResizeObserver for dynamic content\n useEffect(() => {\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => {\n collectItemSizes();\n });\n\n for (const [, el] of itemRefsMap.current) {\n if (el) observer.observe(el);\n }\n\n return () => observer.disconnect();\n }, [items, collectItemSizes]);\n\n // ================ onLayoutChange ================\n useEffect(() => {\n if (!onLayoutChange || !items || items.length === 0) return;\n\n const allPositioned = items.every((item) => itemPositions.has(item.key));\n if (!allPositioned) return;\n\n const sortInfo = items.map((item) => ({\n key: item.key,\n column: itemPositions.get(item.key)!.column,\n }));\n onLayoutChange(sortInfo);\n }, [itemPositions, items, onLayoutChange]);\n\n // ==================== Render ====================\n const cls = classNames(prefixCls, className);\n\n const containerStyle: React.CSSProperties = {\n ...style,\n position: 'relative',\n height: totalHeight || undefined,\n };\n\n const mergedItems = items || [];\n\n return (\n <div\n ref={ref}\n {...otherProps}\n className={cls}\n style={containerStyle}\n onLoad={collectItemSizes}\n onError={collectItemSizes}\n >\n <TransitionGroup component={null}>\n {mergedItems.map((item, index) => {\n const key = item.key ?? index;\n const position = itemPositions.get(key);\n const hasPosition = !!position;\n const columnIndex = position?.column ?? 0;\n\n const itemStyle: React.CSSProperties = {\n position: 'absolute',\n width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,\n left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,\n top: position?.top ?? 0,\n // Only transition position changes after initial placement\n transition: hasPosition ? 'top 0.3s ease, left 0.3s ease, opacity 0.3s ease' : 'none',\n // Hide until position is computed so items don't flash at (0,0)\n opacity: hasPosition ? 1 : 0,\n };\n\n const content = item.children ?? itemRender?.({ ...item, index, column: columnIndex });\n\n return (\n <CSSTransition\n key={key}\n timeout={300}\n classNames={`${prefixCls}__item-fade`}\n onExited={() => {\n itemRefsMap.current.delete(key);\n collectItemSizes();\n }}\n >\n <div\n ref={(el) => setItemRef(key, el)}\n className={`${prefixCls}__item`}\n style={itemStyle}\n >\n {content}\n </div>\n </CSSTransition>\n );\n })}\n </TransitionGroup>\n </div>\n );\n});\n\nWaterfall.displayName = 'Waterfall';\n\nexport default Waterfall;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"waterfall.js","names":["React","getPrefixCls","ConfigContext","useBreakpoint","responsiveArray","usePositions","Transition"],"sources":["../../src/waterfall/waterfall.tsx"],"sourcesContent":["import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport classNames from 'classnames';\nimport Transition from '../transition';\nimport { ConfigContext } from '../config-provider/config-context';\nimport { getPrefixCls } from '../_utils/general';\nimport { Breakpoint, WaterfallItem, WaterfallProps } from './types';\nimport useBreakpoint, { responsiveArray } from './hooks/use-breakpoint';\nimport usePositions, { ItemHeightData } from './hooks/use-positions';\n\nconst Waterfall = React.forwardRef<HTMLDivElement, WaterfallProps>((props, ref) => {\n const {\n prefixCls: customisedCls,\n className,\n style,\n columns = 3,\n gutter = 0,\n items,\n itemRender,\n onLayoutChange,\n ...otherProps\n } = props;\n\n const configContext = useContext(ConfigContext);\n const prefixCls = getPrefixCls('waterfall', configContext.prefixCls, customisedCls);\n\n // ===================== Breakpoint =====================\n const screens = useBreakpoint();\n\n const columnCount = React.useMemo<number>(() => {\n if (typeof columns === 'number') {\n return columns;\n }\n\n const matchingBreakpoint = responsiveArray.find(\n (bp: Breakpoint) => screens[bp] && columns[bp] !== undefined,\n );\n\n if (matchingBreakpoint) {\n return columns[matchingBreakpoint] as number;\n }\n\n return columns.xs ?? 1;\n }, [columns, screens]);\n\n // ====================== Gutter ======================\n const [horizontalGutter, verticalGutter] = Array.isArray(gutter)\n ? gutter\n : [gutter, gutter];\n\n // =================== Item Refs ===================\n const itemRefsMap = useRef<Map<React.Key, HTMLDivElement | null>>(new Map());\n\n const setItemRef = useCallback((key: React.Key, el: HTMLDivElement | null) => {\n itemRefsMap.current.set(key, el);\n }, []);\n\n // ================= Item Heights ==================\n const [itemHeights, setItemHeights] = useState<ItemHeightData[]>([]);\n\n const collectItemSizes = useCallback(() => {\n if (!items || items.length === 0) {\n setItemHeights([]);\n return;\n }\n\n const nextHeights = items.map<ItemHeightData>((item, index) => {\n const key = item.key ?? index;\n const el = itemRefsMap.current.get(key);\n const height = el ? el.getBoundingClientRect().height : 0;\n return [key, height, item.column];\n });\n\n setItemHeights((prev) => {\n const isSame =\n prev.length === nextHeights.length &&\n prev.every((p, i) => p[0] === nextHeights[i][0] && p[1] === nextHeights[i][1]);\n return isSame ? prev : nextHeights;\n });\n }, [items]);\n\n // ================= Positions ==================\n const [itemPositions, totalHeight] = usePositions(itemHeights, columnCount, verticalGutter);\n\n // Collect sizes on items/columns change\n useEffect(() => {\n collectItemSizes();\n }, [items, columnCount, collectItemSizes]);\n\n // ResizeObserver for dynamic content\n useEffect(() => {\n if (typeof ResizeObserver === 'undefined') return;\n\n const observer = new ResizeObserver(() => {\n collectItemSizes();\n });\n\n for (const [, el] of itemRefsMap.current) {\n if (el) observer.observe(el);\n }\n\n return () => observer.disconnect();\n }, [items, collectItemSizes]);\n\n // ================ onLayoutChange ================\n useEffect(() => {\n if (!onLayoutChange || !items || items.length === 0) return;\n\n const allPositioned = items.every((item) => itemPositions.has(item.key));\n if (!allPositioned) return;\n\n const sortInfo = items.map((item) => ({\n key: item.key,\n column: itemPositions.get(item.key)!.column,\n }));\n onLayoutChange(sortInfo);\n }, [itemPositions, items, onLayoutChange]);\n\n // ============== Exiting items (replaces TransitionGroup) ==============\n const prevItemsRef = useRef<WaterfallItem[]>(items || []);\n const [exitingItems, setExitingItems] = useState<Map<React.Key, WaterfallItem>>(new Map());\n\n useEffect(() => {\n const currentKeys = new Set((items || []).map((item, i) => item.key ?? i));\n const removed = new Map<React.Key, WaterfallItem>();\n\n prevItemsRef.current.forEach((item, index) => {\n const key = item.key ?? index;\n if (!currentKeys.has(key)) {\n removed.set(key, item);\n }\n });\n\n if (removed.size > 0) {\n setExitingItems((prev) => {\n const next = new Map(prev);\n removed.forEach((item, key) => next.set(key, item));\n return next;\n });\n }\n\n prevItemsRef.current = items || [];\n }, [items]);\n\n const handleExited = useCallback((key: React.Key) => {\n itemRefsMap.current.delete(key);\n setExitingItems((prev) => {\n const next = new Map(prev);\n next.delete(key);\n return next;\n });\n collectItemSizes();\n }, [collectItemSizes]);\n\n // ==================== Render ====================\n const cls = classNames(prefixCls, className);\n\n const containerStyle: React.CSSProperties = {\n ...style,\n position: 'relative',\n height: totalHeight || undefined,\n };\n\n const mergedItems = items || [];\n\n const renderItem = (item: WaterfallItem, index: number, isExiting: boolean) => {\n const key = item.key ?? index;\n const position = itemPositions.get(key);\n const hasPosition = !!position;\n const columnIndex = position?.column ?? 0;\n\n const itemStyle: React.CSSProperties = {\n position: 'absolute',\n width: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount})`,\n left: `calc((100% - ${horizontalGutter * (columnCount - 1)}px) / ${columnCount} * ${columnIndex} + ${horizontalGutter * columnIndex}px)`,\n top: position?.top ?? 0,\n // Only transition position changes after initial placement\n transition: hasPosition ? 'top 0.3s ease, left 0.3s ease, opacity 0.3s ease' : 'none',\n // Hide until position is computed so items don't flash at (0,0)\n opacity: hasPosition ? 1 : 0,\n };\n\n const content = item.children ?? itemRender?.({ ...item, index, column: columnIndex });\n\n return (\n <Transition\n key={key}\n in={!isExiting}\n timeout={300}\n appear={false}\n unmountOnExit={true}\n classNames={`${prefixCls}__item-fade`}\n onExited={() => handleExited(key)}\n >\n <div\n ref={(el) => setItemRef(key, el)}\n className={`${prefixCls}__item`}\n style={itemStyle}\n >\n {content}\n </div>\n </Transition>\n );\n };\n\n return (\n <div\n ref={ref}\n {...otherProps}\n className={cls}\n style={containerStyle}\n onLoad={collectItemSizes}\n onError={collectItemSizes}\n >\n {mergedItems.map((item, index) => renderItem(item, index, false))}\n {Array.from(exitingItems.entries()).map(([key, item]) =>\n renderItem(item, Number(key), true)\n )}\n </div>\n );\n});\n\nWaterfall.displayName = 'Waterfall';\n\nexport default Waterfall;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiny-design/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A friendly UI component set for React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -53,10 +53,9 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@popperjs/core": "^2.11.4",
|
|
55
55
|
"classnames": "^2.3.1",
|
|
56
|
-
"react-transition-group": "^4.4.2",
|
|
57
56
|
"tslib": "^2.3.1",
|
|
58
|
-
"@tiny-design/icons": "1.
|
|
59
|
-
"@tiny-design/tokens": "1.
|
|
57
|
+
"@tiny-design/icons": "1.3.0",
|
|
58
|
+
"@tiny-design/tokens": "1.3.0"
|
|
60
59
|
},
|
|
61
60
|
"devDependencies": {
|
|
62
61
|
"@testing-library/jest-dom": "^6.0.0",
|
|
@@ -64,7 +63,6 @@
|
|
|
64
63
|
"@types/jest": "^29.0.0",
|
|
65
64
|
"@types/react": "^18.2.0",
|
|
66
65
|
"@types/react-dom": "^18.2.0",
|
|
67
|
-
"@types/react-transition-group": "^4.4.4",
|
|
68
66
|
"jest": "^29.0.0",
|
|
69
67
|
"jest-environment-jsdom": "^29.0.0",
|
|
70
68
|
"autoprefixer": "^10.4.4",
|