Browse Source

Drag n Drop
Selector
part

Fred Lefévère-Laoide 1 month ago
parent
commit
23830e33ca

+ 72 - 0
frontend/taipy-gui/package-lock.json

@@ -24,6 +24,8 @@
         "notistack": "^3.0.0",
         "plotly.js": "^3.0.0",
         "react": "^18.3.1",
+        "react-dnd": "^16.0.1",
+        "react-dnd-html5-backend": "^16.0.1",
         "react-dom": "^18.3.1",
         "react-error-boundary": "^5.0.0",
         "react-helmet-async": "^2.0.1",
@@ -2418,6 +2420,21 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
+    "node_modules/@react-dnd/asap": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
+      "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A=="
+    },
+    "node_modules/@react-dnd/invariant": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
+      "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw=="
+    },
+    "node_modules/@react-dnd/shallowequal": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
+      "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
+    },
     "node_modules/@shikijs/engine-oniguruma": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.2.1.tgz",
@@ -5486,6 +5503,16 @@
         "node": ">=8"
       }
     },
+    "node_modules/dnd-core": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
+      "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
+      "dependencies": {
+        "@react-dnd/asap": "^5.0.1",
+        "@react-dnd/invariant": "^4.0.1",
+        "redux": "^4.2.0"
+      }
+    },
     "node_modules/doctrine": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -12251,6 +12278,43 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-dnd": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
+      "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
+      "dependencies": {
+        "@react-dnd/invariant": "^4.0.1",
+        "@react-dnd/shallowequal": "^4.0.1",
+        "dnd-core": "^16.0.1",
+        "fast-deep-equal": "^3.1.3",
+        "hoist-non-react-statics": "^3.3.2"
+      },
+      "peerDependencies": {
+        "@types/hoist-non-react-statics": ">= 3.3.1",
+        "@types/node": ">= 12",
+        "@types/react": ">= 16",
+        "react": ">= 16.14"
+      },
+      "peerDependenciesMeta": {
+        "@types/hoist-non-react-statics": {
+          "optional": true
+        },
+        "@types/node": {
+          "optional": true
+        },
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/react-dnd-html5-backend": {
+      "version": "16.0.1",
+      "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
+      "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
+      "dependencies": {
+        "dnd-core": "^16.0.1"
+      }
+    },
     "node_modules/react-dom": {
       "version": "18.3.1",
       "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
@@ -12491,6 +12555,14 @@
         "node": ">=8"
       }
     },
+    "node_modules/redux": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+      "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+      "dependencies": {
+        "@babel/runtime": "^7.9.2"
+      }
+    },
     "node_modules/reflect.getprototypeof": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",

+ 2 - 0
frontend/taipy-gui/package.json

@@ -19,6 +19,8 @@
     "notistack": "^3.0.0",
     "plotly.js": "^3.0.0",
     "react": "^18.3.1",
+    "react-dnd": "^16.0.1",
+    "react-dnd-html5-backend": "^16.0.1",
     "react-dom": "^18.3.1",
     "react-error-boundary": "^5.0.0",
     "react-helmet-async": "^2.0.1",

+ 61 - 53
frontend/taipy-gui/src/components/Router.tsx

@@ -23,6 +23,8 @@ import { SnackbarProvider } from "notistack";
 import { HelmetProvider } from "react-helmet-async";
 import { BrowserRouter, Route, Routes } from "react-router";
 import { ErrorBoundary } from "react-error-boundary";
+import { DndProvider } from "react-dnd";
+import { HTML5Backend } from "react-dnd-html5-backend";
 
 import { PageContext, TaipyContext } from "../context/taipyContext";
 import {
@@ -111,62 +113,68 @@ const Router = () => {
                 <ThemeProvider theme={state.theme}>
                     <SnackbarProvider maxSnack={5}>
                         <LocalizationProvider dateAdapter={AdapterDateFns}>
-                            <PageContext.Provider value={pageStore}>
-                                <BrowserRouter>
-                                    <Box style={containerSx}>
-                                        <CssBaseline />
-                                        <ErrorBoundary FallbackComponent={ErrorFallback}>
-                                            <Menu {...state.menu} />
-                                        </ErrorBoundary>
-                                        <Box component="main" sx={mainSx}>
+                            <DndProvider backend={HTML5Backend}>
+                                <PageContext.Provider value={pageStore}>
+                                    <BrowserRouter>
+                                        <Box style={containerSx}>
+                                            <CssBaseline />
                                             <ErrorBoundary FallbackComponent={ErrorFallback}>
-                                                {Object.keys(routes).length ? (
-                                                    <Routes>
-                                                        <Route
-                                                            path={baseURL}
-                                                            element={
-                                                                <MainPage
-                                                                    path={routes["/"]}
-                                                                    route={Object.keys(routes).find(
-                                                                        (path) => path !== "/",
-                                                                    )}
-                                                                />
-                                                            }
-                                                        >
-                                                            {Object.entries(routes)
-                                                                .filter(([path]) => path !== "/")
-                                                                .map(([path, name]) => (
-                                                                    <Route
-                                                                        key={name}
-                                                                        path={path.substring(1)}
-                                                                        element={<TaipyRendered />}
-                                                                    />
-                                                                ))}
-                                                            <Route path="*" key="NotFound" element={<NotFound404 />} />
-                                                        </Route>
-                                                    </Routes>
-                                                ) : null}
+                                                <Menu {...state.menu} />
                                             </ErrorBoundary>
-                                        </Box>
-                                        {state.ackList.length ? (
-                                            <Box sx={progressSx} className="taipy-busy">
-                                                <CircularProgress size="1em" disableShrink />
+                                            <Box component="main" sx={mainSx}>
+                                                <ErrorBoundary FallbackComponent={ErrorFallback}>
+                                                    {Object.keys(routes).length ? (
+                                                        <Routes>
+                                                            <Route
+                                                                path={baseURL}
+                                                                element={
+                                                                    <MainPage
+                                                                        path={routes["/"]}
+                                                                        route={Object.keys(routes).find(
+                                                                            (path) => path !== "/"
+                                                                        )}
+                                                                    />
+                                                                }
+                                                            >
+                                                                {Object.entries(routes)
+                                                                    .filter(([path]) => path !== "/")
+                                                                    .map(([path, name]) => (
+                                                                        <Route
+                                                                            key={name}
+                                                                            path={path.substring(1)}
+                                                                            element={<TaipyRendered />}
+                                                                        />
+                                                                    ))}
+                                                                <Route
+                                                                    path="*"
+                                                                    key="NotFound"
+                                                                    element={<NotFound404 />}
+                                                                />
+                                                            </Route>
+                                                        </Routes>
+                                                    ) : null}
+                                                </ErrorBoundary>
                                             </Box>
-                                        ) : null}
-                                    </Box>
-                                    <ErrorBoundary FallbackComponent={ErrorFallback}>
-                                        <TaipyNotification notifications={state.notifications} />
-                                        <UIBlocker block={state.block} />
-                                        <Navigate
-                                            to={state.navigateTo}
-                                            params={state.navigateParams}
-                                            tab={state.navigateTab}
-                                            force={state.navigateForce}
-                                        />
-                                        <GuiDownload download={state.download} />
-                                    </ErrorBoundary>
-                                </BrowserRouter>
-                            </PageContext.Provider>
+                                            {state.ackList.length ? (
+                                                <Box sx={progressSx} className="taipy-busy">
+                                                    <CircularProgress size="1em" disableShrink />
+                                                </Box>
+                                            ) : null}
+                                        </Box>
+                                        <ErrorBoundary FallbackComponent={ErrorFallback}>
+                                            <TaipyNotification notifications={state.notifications} />
+                                            <UIBlocker block={state.block} />
+                                            <Navigate
+                                                to={state.navigateTo}
+                                                params={state.navigateParams}
+                                                tab={state.navigateTab}
+                                                force={state.navigateForce}
+                                            />
+                                            <GuiDownload download={state.download} />
+                                        </ErrorBoundary>
+                                    </BrowserRouter>
+                                </PageContext.Provider>
+                            </DndProvider>
                         </LocalizationProvider>
                     </SnackbarProvider>
                 </ThemeProvider>

+ 90 - 5
frontend/taipy-gui/src/components/Taipy/Part.tsx

@@ -11,14 +11,17 @@
  * specific language governing permissions and limitations under the License.
  */
 
-import React, { ReactNode, useContext, useMemo } from "react";
+import React, { ReactNode, useCallback, useContext, useMemo, useRef } from "react";
 import Box from "@mui/material/Box";
 
-import { useClassNames, useDynamicProperty } from "../../utils/hooks";
+import { useClassNames, useDynamicProperty, useModule } from "../../utils/hooks";
 import TaipyRendered from "../pages/TaipyRendered";
 import { expandSx, getCssSize, TaipyBaseProps } from "./utils";
 import { TaipyContext } from "../../context/taipyContext";
 import { getComponentClassName } from "./TaipyStyle";
+import { useDrag, useDrop } from "react-dnd";
+import { createSendActionNameAction } from "../../context/taipyReducers";
+import { DragItem, dragSx } from "./lovUtils";
 
 interface PartProps extends TaipyBaseProps {
     render?: boolean;
@@ -31,6 +34,10 @@ interface PartProps extends TaipyBaseProps {
     height?: string;
     defaultHeight?: string;
     width?: string | number;
+    dragType?: string;
+    dropTypes?: string;
+    onAction?: string;
+    dragParameters?: string;
 }
 
 const IframeStyle = {
@@ -40,7 +47,8 @@ const IframeStyle = {
 
 const Part = (props: PartProps) => {
     const { id, partial, defaultPartial } = props;
-    const { state } = useContext(TaipyContext);
+    const { state, dispatch } = useContext(TaipyContext);
+    const module = useModule();
 
     const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
     const render = useDynamicProperty(props.render, props.defaultRender, true);
@@ -57,9 +65,86 @@ const Part = (props: PartProps) => {
         return false;
     }, [state.locations, page, defaultPartial]);
 
-    const boxSx = useMemo(() => expandSx(height ? { height: height } : undefined, props.width ? {width: getCssSize(props.width)}: undefined), [height, props.width]);
+    // Droppable area for drag and drop
+    const dropTypes = useMemo(() => {
+        if (props.dropTypes) {
+            try {
+                return JSON.parse(props.dropTypes);
+            } catch (e) {
+                console.error("Invalid dropTypes JSON string", e);
+            }
+        }
+        return [];
+    }, [props.dropTypes]);
+    const handleDrop = useCallback(
+        (itemId: string, _dropIndex: number, _targetVarName: string, targetId?: string, dragParameters?: unknown) => {
+            dispatch(
+                createSendActionNameAction(props.onAction, module, {
+                    reason: "drop",
+                    source_id: id,
+                    item_id: itemId,
+                    target_id: targetId,
+                    drag_parameters: dragParameters,
+                })
+            );
+        },
+        [dispatch, module, props.onAction, id]
+    );
+    const dragParameters = useMemo(() => {
+        if (props.dragType && props.dragParameters) {
+            try {
+                return JSON.parse(props.dragParameters);
+            } catch (e) {
+                console.error("Invalid dragParameters JSON string", e);
+            }
+        }
+        return undefined;
+    }
+    , [props.dragType, props.dragParameters]);
+
+    const itemRef = useRef<HTMLDivElement>(null);
+    const getDragItem = useCallback(() => (props.dragType ? { id: "", index: -1 } : null), [props.dragType]);
+
+    const [{ isDragging }, drag] = useDrag(
+        () => ({
+            type: props.dragType || "",
+            item: getDragItem,
+            collect: (monitor) => ({
+                isDragging: monitor.isDragging(),
+            }),
+            end: (item: DragItem, monitor) => {
+                const dropResult = monitor.getDropResult();
+                if (dropResult) {
+                    handleDrop?.(item.id, item.index, "", item.targetId, dragParameters);
+                }
+            },
+        }),
+        [props.dragType, getDragItem, id]
+    );
+    const [, drop] = useDrop(
+        () => ({
+            accept: dropTypes || "",
+            hover: (item: DragItem) => {
+                item.index = -1;
+                item.targetId = id;
+            },
+        }),
+        [dropTypes]
+    );
+    drag(drop(itemRef));
+
+    const boxSx = useMemo(
+        () =>
+            expandSx(
+                height ? { height: height } : undefined,
+                props.width ? { width: getCssSize(props.width) } : undefined,
+                isDragging ? dragSx : undefined
+            ),
+        [height, props.width, isDragging]
+    );
+
     return render ? (
-        <Box id={id} className={`${className} ${getComponentClassName(props.children)}`} sx={boxSx}>
+        <Box id={id} className={`${className} ${getComponentClassName(props.children)}`} sx={boxSx} ref={itemRef}>
             {iFrame ? (
                 <iframe src={page} style={IframeStyle} />
             ) : page ? (

+ 157 - 38
frontend/taipy-gui/src/components/Taipy/Selector.tsx

@@ -16,6 +16,7 @@ import React, {
     useCallback,
     useEffect,
     useMemo,
+    useRef,
     CSSProperties,
     MouseEvent,
     ChangeEvent,
@@ -46,10 +47,21 @@ import RadioGroup from "@mui/material/RadioGroup";
 import Select, { SelectChangeEvent } from "@mui/material/Select";
 import TextField from "@mui/material/TextField";
 import { Theme, useTheme } from "@mui/material";
+import { useDrag, useDrop } from "react-dnd";
 
 import { doNotPropagateEvent, getSuffixedClassNames, getUpdateVar } from "./utils";
-import { createSendUpdateAction } from "../../context/taipyReducers";
-import { ItemProps, LovImage, paperBaseSx, SelTreeProps, showItem, SingleItem, useLovListMemo } from "./lovUtils";
+import { createSendActionNameAction, createSendUpdateAction } from "../../context/taipyReducers";
+import {
+    DragItem,
+    dragSx,
+    ItemProps,
+    LovImage,
+    paperBaseSx,
+    SelTreeProps,
+    showItem,
+    SingleItem,
+    useLovListMemo,
+} from "./lovUtils";
 import {
     useClassNames,
     useDispatch,
@@ -61,26 +73,81 @@ import { Icon } from "../../utils/icon";
 import { LovItem } from "../../utils/lov";
 import { getComponentClassName } from "./TaipyStyle";
 
-const MultipleItem = ({ value, clickHandler, selectedValue, item, disabled }: ItemProps) => (
-    <ListItemButton onClick={clickHandler} data-id={value} dense disabled={disabled}>
-        <ListItemIcon>
-            <Checkbox
-                disabled={disabled}
-                edge="start"
-                checked={selectedValue.includes(value)}
-                tabIndex={-1}
-                disableRipple
-            />
-        </ListItemIcon>
-        {typeof item === "string" ? (
-            <ListItemText primary={item} />
-        ) : (
-            <ListItemAvatar>
-                <LovImage item={item} />
-            </ListItemAvatar>
-        )}
-    </ListItemButton>
-);
+const MultipleItem = ({
+    value,
+    clickHandler,
+    selectedValue,
+    item,
+    disabled,
+    dragType = "",
+    dropTypes,
+    handleDrop,
+    index = -1,
+    lovVarName,
+    targetId,
+}: ItemProps) => {
+    const itemRef = useRef<HTMLDivElement>(null);
+    const getDragItem = useCallback(
+        () => (dragType && !disabled ? { id: value, index: -1 } : null),
+        [dragType, disabled, value]
+    );
+
+    const [{ isDragging }, drag] = useDrag(
+        () => ({
+            type: dragType,
+            item: getDragItem,
+            collect: (monitor) => ({
+                isDragging: monitor.isDragging(),
+            }),
+            end: (item: DragItem, monitor) => {
+                const dropResult = monitor.getDropResult();
+                if (dropResult) {
+                    handleDrop?.(item.id, item.index, lovVarName || "", item.targetId);
+                }
+            },
+        }),
+        [dragType, getDragItem, lovVarName, targetId]
+    );
+    const [, drop] = useDrop<DragItem, void, { handlerId: string }>(
+        () => ({
+            accept: dropTypes || "",
+            hover: (item: DragItem) => {
+                item.index = index;
+                item.targetId = targetId;
+            },
+        }),
+        [dropTypes, index, targetId]
+    );
+    drag(drop(itemRef));
+
+    return (
+        <ListItemButton
+            onClick={clickHandler}
+            data-id={value}
+            dense
+            disabled={disabled}
+            ref={itemRef}
+            sx={isDragging ? dragSx : undefined}
+        >
+            <ListItemIcon>
+                <Checkbox
+                    disabled={disabled}
+                    edge="start"
+                    checked={selectedValue.includes(value)}
+                    tabIndex={-1}
+                    disableRipple
+                />
+            </ListItemIcon>
+            {typeof item === "string" ? (
+                <ListItemText primary={item} />
+            ) : (
+                <ListItemAvatar>
+                    <LovImage item={item} />
+                </ListItemAvatar>
+            )}
+        </ListItemButton>
+    );
+};
 
 const ITEM_HEIGHT = 48;
 const ITEM_PADDING_TOP = 8;
@@ -168,6 +235,46 @@ const Selector = (props: SelectorProps) => {
     const dropdown = isRadio || isCheck || props.dropdown === undefined ? false : props.dropdown;
     const multiple = isCheck ? true : isRadio || props.multiple === undefined ? false : props.multiple;
 
+    const lovVarName = useMemo(() => getUpdateVar(updateVars, "lov"), [updateVars]);
+
+    // Droppable area for drag and drop
+    const dropTypes = useMemo(() => {
+        if (props.dropTypes) {
+            try {
+                return JSON.parse(props.dropTypes);
+            } catch (e) {
+                console.error("Invalid dropTypes JSON string", e);
+            }
+        }
+        return [];
+    }, [props.dropTypes]);
+    const [, dropRef] = useDrop(
+        () => ({
+            accept: dropTypes,
+            hover: (item: DragItem) => {
+                item.index = -1;
+                item.targetId = id;
+            },
+        }),
+        [dropTypes, id]
+    );
+    const handleDrop = useCallback(
+        (itemId: string, dropIndex: number, targetVarName: string, targetId?: string) => {
+            dispatch(
+                createSendActionNameAction(props.onAction, module, {
+                    reason: "drop",
+                    source_var: lovVarName,
+                    source_id: id,
+                    item_id: itemId,
+                    drop_index: dropIndex,
+                    target_var: targetVarName,
+                    target_id: targetId,
+                })
+            );
+        },
+        [lovVarName, dispatch, module, props.onAction, id]
+    );
+
     const lovList = useLovListMemo(lov, defaultLov);
     const listSx = useMemo(
         () => ({
@@ -246,7 +353,7 @@ const Selector = (props: SelectorProps) => {
                             module,
                             props.onChange,
                             propagate,
-                            valueById ? undefined : getUpdateVar(updateVars, "lov")
+                            valueById ? undefined : lovVarName
                         )
                     );
                     return newKeys;
@@ -258,14 +365,14 @@ const Selector = (props: SelectorProps) => {
                             module,
                             props.onChange,
                             propagate,
-                            valueById ? undefined : getUpdateVar(updateVars, "lov")
+                            valueById ? undefined : lovVarName
                         )
                     );
                     return [key];
                 }
             });
         },
-        [updateVarName, dispatch, multiple, propagate, updateVars, valueById, props.onChange, module]
+        [updateVarName, dispatch, multiple, propagate, lovVarName, valueById, props.onChange, module]
     );
 
     const clickHandler = useCallback(
@@ -301,11 +408,11 @@ const Selector = (props: SelectorProps) => {
                     module,
                     props.onChange,
                     propagate,
-                    valueById ? undefined : getUpdateVar(updateVars, "lov")
+                    valueById ? undefined : lovVarName
                 )
             );
         },
-        [dispatch, updateVarName, propagate, updateVars, valueById, props.onChange, module]
+        [dispatch, updateVarName, propagate, lovVarName, valueById, props.onChange, module]
     );
 
     const handleCheckAllChange = useCallback(
@@ -319,11 +426,11 @@ const Selector = (props: SelectorProps) => {
                     module,
                     props.onChange,
                     propagate,
-                    valueById ? undefined : getUpdateVar(updateVars, "lov")
+                    valueById ? undefined : lovVarName
                 )
             );
         },
-        [lovList, dispatch, updateVarName, propagate, updateVars, valueById, props.onChange, module]
+        [lovList, dispatch, updateVarName, propagate, lovVarName, valueById, props.onChange, module]
     );
 
     const [autoValue, setAutoValue] = useState<LovItem | LovItem[] | null>(() => (multiple ? [] : null));
@@ -338,11 +445,11 @@ const Selector = (props: SelectorProps) => {
                     module,
                     props.onChange,
                     propagate,
-                    valueById ? undefined : getUpdateVar(updateVars, "lov")
+                    valueById ? undefined : lovVarName
                 )
             );
         },
-        [dispatch, updateVarName, propagate, updateVars, valueById, props.onChange, module]
+        [dispatch, updateVarName, propagate, lovVarName, valueById, props.onChange, module]
     );
 
     const handleDelete = useCallback(
@@ -358,13 +465,13 @@ const Selector = (props: SelectorProps) => {
                             module,
                             props.onChange,
                             propagate,
-                            valueById ? undefined : getUpdateVar(updateVars, "lov")
+                            valueById ? undefined : lovVarName
                         )
                     );
                     return keys;
                 });
         },
-        [updateVarName, propagate, dispatch, updateVars, valueById, props.onChange, module]
+        [updateVarName, propagate, dispatch, lovVarName, valueById, props.onChange, module]
     );
 
     const handleInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => setSearchValue(e.target.value), []);
@@ -602,10 +709,9 @@ const Selector = (props: SelectorProps) => {
                                     />
                                 </Box>
                             ) : null}
-                            <List sx={listSx} id={id}>
-                                {lovList
-                                    .filter((elt) => showItem(elt, searchValue))
-                                    .map((elt) =>
+                            <List sx={listSx} id={id} ref={dropRef}>
+                                {lovList.map((elt, idx) =>
+                                    showItem(elt, searchValue) ? (
                                         multiple ? (
                                             <MultipleItem
                                                 key={elt.id}
@@ -614,6 +720,12 @@ const Selector = (props: SelectorProps) => {
                                                 selectedValue={selectedValue}
                                                 clickHandler={clickHandler}
                                                 disabled={!active}
+                                                dragType={props.dragType}
+                                                dropTypes={dropTypes}
+                                                index={idx}
+                                                handleDrop={handleDrop}
+                                                lovVarName={lovVarName}
+                                                targetId={id}
                                             />
                                         ) : (
                                             <SingleItem
@@ -623,9 +735,16 @@ const Selector = (props: SelectorProps) => {
                                                 selectedValue={selectedValue}
                                                 clickHandler={clickHandler}
                                                 disabled={!active}
+                                                dragType={props.dragType}
+                                                dropTypes={dropTypes}
+                                                index={idx}
+                                                handleDrop={handleDrop}
+                                                lovVarName={lovVarName}
+                                                targetId={id}
                                             />
                                         )
-                                    )}
+                                    ) : null
+                                )}
                             </List>
                         </Paper>
                     </Tooltip>

+ 140 - 17
frontend/taipy-gui/src/components/Taipy/TreeView.tsx

@@ -19,20 +19,30 @@ import React, {
     SyntheticEvent,
     HTMLAttributes,
     forwardRef,
-    Ref,
     CSSProperties,
+    RefObject,
 } from "react";
 import Box from "@mui/material/Box";
 import { SimpleTreeView as MuiTreeView } from "@mui/x-tree-view/SimpleTreeView";
 import ChevronRightIcon from "@mui/icons-material/ChevronRight";
-import { TreeItem, TreeItemContentProps, useTreeItemState, TreeItemProps } from "@mui/x-tree-view/TreeItem";
+import { TreeItemContentProps, useTreeItemState, TreeItemProps } from "@mui/x-tree-view/TreeItem";
+import { TreeItem2 } from "@mui/x-tree-view/TreeItem2";
 import Paper from "@mui/material/Paper";
 import TextField from "@mui/material/TextField";
 import Tooltip from "@mui/material/Tooltip";
 import Typography from "@mui/material/Typography";
 
-import { createSendUpdateAction } from "../../context/taipyReducers";
-import { isLovParent, LovImage, paperBaseSx, SelTreeProps, showItem, useLovListMemo } from "./lovUtils";
+import { createSendActionNameAction, createSendUpdateAction } from "../../context/taipyReducers";
+import {
+    DragItem,
+    dragSx,
+    isLovParent,
+    LovImage,
+    paperBaseSx,
+    SelTreeProps,
+    showItem,
+    useLovListMemo,
+} from "./lovUtils";
 import {
     useClassNames,
     useDispatch,
@@ -41,16 +51,27 @@ import {
     useModule,
 } from "../../utils/hooks";
 import { LovItem } from "../../utils/lov";
-import { getUpdateVar } from "./utils";
+import { expandSx, getUpdateVar } from "./utils";
 import { Icon } from "../../utils/icon";
 import { getComponentClassName } from "./TaipyStyle";
+import { useDrag, useDrop } from "react-dnd";
 
 const treeSlots = { expandIcon: ChevronRightIcon };
 
 const CustomContent = forwardRef(function CustomContent(props: TreeItemContentProps, ref) {
     // need a display name
     const { classes, className, label, itemId, icon: iconProp, expansionIcon, displayIcon } = props;
-    const { allowSelection, lovIcon, height } = props as unknown as CustomTreeProps;
+    const {
+        allowSelection,
+        lovIcon,
+        height,
+        dragType = "",
+        dropTypes,
+        index = -1,
+        handleDrop,
+        lovVarName,
+        targetId,
+    } = props as unknown as CustomTreeProps;
 
     const { disabled, expanded, selected, focused, handleExpansion, handleSelection, preventSelection } =
         useTreeItemState(itemId);
@@ -70,13 +91,47 @@ const CustomContent = forwardRef(function CustomContent(props: TreeItemContentPr
     if (disabled) {
         classNames.push(classes.disabled);
     }
-    const divStyle = useMemo(() => (height ? { height: height } : undefined), [height]);
+
+    const getDragItem = useCallback(
+        () => (dragType && !disabled ? { id: itemId, index: -1 } : null),
+        [dragType, disabled, itemId]
+    );
+
+    const [{ isDragging }, drag] = useDrag(
+        () => ({
+            type: dragType,
+            item: getDragItem,
+            collect: (monitor) => ({
+                isDragging: monitor.isDragging(),
+            }),
+            end: (item: DragItem, monitor) => {
+                const dropResult = monitor.getDropResult();
+                if (dropResult) {
+                    handleDrop?.(item.id, item.index, lovVarName || "", item.targetId);
+                }
+            },
+        }),
+        [dragType, getDragItem]
+    );
+    const [, drop] = useDrop<DragItem, void, { handlerId: string }>(
+        () => ({
+            accept: dropTypes || "",
+            hover: (item: DragItem) => {
+                item.index = index;
+                item.targetId = targetId;
+            },
+        }),
+        [dropTypes, index, targetId]
+    );
+    drag(drop(ref as RefObject<HTMLDivElement>));
+
+    const divStyle = useMemo(() => expandSx(height ? { height: height } : undefined, isDragging ? dragSx: undefined) as CSSProperties, [height, isDragging]);
 
     return (
         <div
             className={classNames.join(" ")}
             onMouseDown={preventSelection}
-            ref={ref as Ref<HTMLDivElement>}
+            ref={ref as RefObject<HTMLDivElement>}
             style={divStyle}
         >
             <div onClick={handleExpansion} className={classes.iconContainer}>
@@ -97,12 +152,28 @@ interface CustomTreeProps extends HTMLAttributes<HTMLElement> {
     allowSelection: boolean;
     lovIcon?: Icon;
     height?: string;
+    dragType?: string;
+    dropTypes?: string[];
+    index?: number;
+    handleDrop?: (itemId: string, dropIndex: number, targetVarName: string, targetId?: string) => void;
+    lovVarName?: string;
+    targetId?: string;
 }
 
 const CustomTreeItem = (props: TreeItemProps & CustomTreeProps) => {
-    const { allowSelection, lovIcon, height, ...tiProps } = props;
-    const ctProps = { allowSelection, lovIcon, height } as CustomTreeProps;
-    return <TreeItem ContentComponent={CustomContent} ContentProps={ctProps} {...tiProps} />;
+    const { allowSelection, lovIcon, height, dragType, dropTypes, handleDrop, lovVarName, targetId, ...tiProps } =
+        props;
+    const ctProps = {
+        allowSelection,
+        lovIcon,
+        height,
+        dragType,
+        dropTypes,
+        handleDrop,
+        lovVarName,
+        targetId,
+    } as CustomTreeProps;
+    return <TreeItem2 ContentComponent={CustomContent} ContentProps={ctProps} {...tiProps} />;
 };
 
 const renderTree = (
@@ -110,10 +181,16 @@ const renderTree = (
     active: boolean,
     searchValue: string,
     selectLeafsOnly: boolean,
-    rowHeight?: string
+    rowHeight?: string,
+    dragType?: string,
+    dropTypes?: string[],
+    index: number = 0,
+    handleDrop: ((itemId: string, dropIndex: number, targetVarName: string, targetId?: string) => void) | undefined = undefined,
+    lovVarName?: string,
+    id?: string
 ) => {
     return lov.map((li) => {
-        const children = li.children ? renderTree(li.children, active, searchValue, selectLeafsOnly, rowHeight) : [];
+        const children = li.children ? renderTree(li.children, active, searchValue, selectLeafsOnly, rowHeight, dragType, dropTypes, index, handleDrop, lovVarName, id) : [];
         if (!children.filter((c) => c).length && !showItem(li, searchValue)) {
             return null;
         }
@@ -126,6 +203,12 @@ const renderTree = (
                 allowSelection={selectLeafsOnly ? !children || children.length == 0 : true}
                 lovIcon={typeof li.item !== "string" ? (li.item as Icon) : undefined}
                 height={rowHeight}
+                dragType={dragType}
+                dropTypes={dropTypes}
+                index={index}
+                handleDrop={handleDrop}
+                lovVarName={lovVarName}
+                targetId={id}
             >
                 {children}
             </CustomTreeItem>
@@ -175,6 +258,8 @@ const TreeView = (props: TreeViewProps) => {
 
     useDispatchRequestUpdateOnFirstRender(dispatch, id, module, updateVars, updateVarName);
 
+    const lovVarName = useMemo(() => getUpdateVar(updateVars, "lov"), [updateVars]);
+
     const lovList = useLovListMemo(lov, defaultLov, true);
     const treeSx = useMemo(
         () => ({ bgcolor: "transparent", overflowY: "auto", width: "100%", maxWidth: width }),
@@ -185,6 +270,44 @@ const TreeView = (props: TreeViewProps) => {
         return { ...sx, overflow: "hidden", py: 1 };
     }, [height]);
 
+    // Droppable area for drag and drop
+    const dropTypes = useMemo(() => {
+        if (props.dropTypes) {
+            try {
+                return JSON.parse(props.dropTypes);
+            } catch (e) {
+                console.error("Invalid dropTypes JSON string", e);
+            }
+        }
+        return [];
+    }, [props.dropTypes]);
+    const [, dropRef] = useDrop(
+        () => ({
+            accept: dropTypes,
+            hover: (item: DragItem) => {
+                item.index = -1;
+                item.targetId = id;
+            },
+        }),
+        [dropTypes, id]
+    );
+    const handleDrop = useCallback(
+        (itemId: string, dropIndex: number, targetVarName: string, targetId?: string) => {
+            dispatch(
+                createSendActionNameAction(props.onAction, module, {
+                    reason: "drop",
+                    source_var: lovVarName,
+                    source_id: id,
+                    item_id: itemId,
+                    drop_index: dropIndex,
+                    target_var: targetVarName,
+                    target_id: targetId,
+                })
+            );
+        },
+        [lovVarName, dispatch, module, props.onAction, id]
+    );
+
     useEffect(() => {
         let refExp = false;
         let oneExp = false;
@@ -248,11 +371,11 @@ const TreeView = (props: TreeViewProps) => {
                         module,
                         props.onChange,
                         propagate,
-                        valueById ? undefined : getUpdateVar(updateVars, "lov")
+                        valueById ? undefined : lovVarName
                     )
                 );
         },
-        [updateVarName, dispatch, propagate, updateVars, valueById, props.onChange, module]
+        [updateVarName, dispatch, propagate, lovVarName, valueById, props.onChange, module]
     );
 
     const handleInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => setSearchValue(e.target.value), []);
@@ -287,7 +410,7 @@ const TreeView = (props: TreeViewProps) => {
     );
 
     return (
-        <Box id={id} sx={boxSx} className={`${className} ${getComponentClassName(props.children)}`}>
+        <Box id={id} sx={boxSx} className={`${className} ${getComponentClassName(props.children)}`} ref={dropRef}>
             <Tooltip title={hover || ""}>
                 <Paper sx={paperSx}>
                     <Box>
@@ -311,7 +434,7 @@ const TreeView = (props: TreeViewProps) => {
                         onExpandedItemsChange={handleNodeToggle}
                         {...treeProps}
                     >
-                        {renderTree(lovList, !!active, searchValue, selectLeafsOnly, rowHeight)}
+                        {renderTree(lovList, !!active, searchValue, selectLeafsOnly, rowHeight, props.dragType, dropTypes, -1, handleDrop, lovVarName, id)}
                     </MuiTreeView>
                 </Paper>
             </Tooltip>

+ 91 - 31
frontend/taipy-gui/src/components/Taipy/lovUtils.tsx

@@ -11,7 +11,7 @@
  * specific language governing permissions and limitations under the License.
  */
 
-import React, { CSSProperties, useMemo, MouseEvent } from "react";
+import React, { CSSProperties, useMemo, MouseEvent, useCallback, useRef } from "react";
 import Avatar from "@mui/material/Avatar";
 import CardHeader from "@mui/material/CardHeader";
 import ListItemButton from "@mui/material/ListItemButton";
@@ -20,6 +20,7 @@ import ListItemAvatar from "@mui/material/ListItemAvatar";
 import Tooltip from "@mui/material/Tooltip";
 import { TypographyProps } from "@mui/material";
 import { SxProps } from "@mui/system";
+import { useDrag, useDrop } from "react-dnd";
 
 import { TaipyActiveProps, TaipyChangeProps, TaipyLabelProps } from "./utils";
 import { getInitials } from "../../utils";
@@ -30,6 +31,9 @@ export interface SelTreeProps extends LovProps, TaipyLabelProps {
     filter?: boolean;
     multiple?: boolean;
     width?: string | number;
+    dragType?: string;
+    dropTypes?: string;
+    onAction?: string;
 }
 
 export interface LovProps<T = string | string[], U = string> extends TaipyActiveProps, TaipyChangeProps {
@@ -122,7 +126,7 @@ export const LovImage = ({
             avatar={<IconAvatar img={item} sx={sx} />}
             title={item.text}
             disableTypography={disableTypo}
-            titleTypographyProps={titleTypographyProps}
+            slotProps={{ title: titleTypographyProps }}
         />
     );
 };
@@ -136,6 +140,13 @@ export const showItem = (elt: LovItem, searchValue: string) => {
     );
 };
 
+export interface DragItem {
+    index: number;
+    id: string;
+    targetId?: string;
+}
+
+export const dragSx = { opacity: 0.5, cursor: "move" } as SxProps;
 export interface ItemProps {
     value: string;
     clickHandler: (evt: MouseEvent<HTMLElement>) => void;
@@ -144,6 +155,12 @@ export interface ItemProps {
     disabled: boolean;
     withAvatar?: boolean;
     titleTypographyProps?: TypographyProps<"span", { component?: "span" }>;
+    dragType?: string;
+    dropTypes?: string[];
+    index?: number;
+    handleDrop?: (itemId: string, dropIndex: number, targetVarName: string, targetId?: string) => void;
+    lovVarName?: string;
+    targetId?: string;
 }
 
 export const SingleItem = ({
@@ -154,37 +171,80 @@ export const SingleItem = ({
     disabled,
     withAvatar = false,
     titleTypographyProps,
-}: ItemProps) => (
-    <ListItemButton
-        onClick={clickHandler}
-        data-id={value}
-        selected={Array.isArray(selectedValue) ? selectedValue.indexOf(value) !== -1 : selectedValue === value}
-        disabled={disabled}
-    >
-        {typeof item === "string" ? (
-            withAvatar ? (
+    dragType = "",
+    dropTypes,
+    index = -1,
+    handleDrop,
+    lovVarName,
+    targetId,
+}: ItemProps) => {
+    const itemRef = useRef<HTMLDivElement>(null);
+    const getDragItem = useCallback(() => (dragType && !disabled ? { id: value, index: -1 } : null), [dragType, disabled, value]);
+
+    const [{ isDragging }, drag] = useDrag(
+        () => ({
+            type: dragType,
+            item: getDragItem,
+            collect: (monitor) => ({
+                isDragging: monitor.isDragging(),
+            }),
+            end: (item: DragItem, monitor) => {
+                const dropResult = monitor.getDropResult();
+                if (dropResult) {
+                    handleDrop?.(item.id, item.index, lovVarName || "", item.targetId);
+                }
+            },
+        }),
+        [dragType, getDragItem]
+    );
+    const [, drop] = useDrop<DragItem, void, { handlerId: string }>(
+        () => ({
+            accept: dropTypes || "",
+            hover: (item: DragItem) => {
+                item.index = index;
+                item.targetId = targetId;
+            },
+        }),
+        [dropTypes, index, targetId]
+    );
+    drag(drop(itemRef));
+
+    return (
+        <ListItemButton
+            onClick={clickHandler}
+            data-id={value}
+            selected={Array.isArray(selectedValue) ? selectedValue.indexOf(value) !== -1 : selectedValue === value}
+            disabled={disabled}
+            ref={itemRef}
+            sx={isDragging ? dragSx : undefined}
+        >
+            {typeof item === "string" ? (
+                withAvatar ? (
+                    <ListItemAvatar>
+                        <CardHeader
+                            sx={cardSx}
+                            avatar={
+                                <Tooltip title={item}>
+                                    <Avatar sx={avatarSx}>{getInitials(item)}</Avatar>
+                                </Tooltip>
+                            }
+                            title={item}
+                            slotProps={{
+                                title: titleTypographyProps,
+                            }}
+                        />
+                    </ListItemAvatar>
+                ) : (
+                    <ListItemText primary={item} />
+                )
+            ) : (
                 <ListItemAvatar>
-                    <CardHeader
-                        sx={cardSx}
-                        avatar={
-                            <Tooltip title={item}>
-                                <Avatar sx={avatarSx}>{getInitials(item)}</Avatar>
-                            </Tooltip>
-                        }
-                        title={item}
-                        titleTypographyProps={titleTypographyProps}
-                    />
+                    <LovImage item={item} titleTypographyProps={titleTypographyProps} />
                 </ListItemAvatar>
-            ) : (
-                <ListItemText primary={item} />
-            )
-        ) : (
-            <ListItemAvatar>
-                <LovImage item={item} titleTypographyProps={titleTypographyProps} />
-            </ListItemAvatar>
-        )}
-    </ListItemButton>
-);
+            )}
+        </ListItemButton>
+    );
+};
 
 export const isLovParent = (lov: LovItem[] | undefined, id: string, childId: string, path: string[] = []): boolean => {
     if (!lov) {

+ 0 - 1461
package-lock.json

@@ -1,1461 +0,0 @@
-{
-  "name": "taipy",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "dependencies": {
-        "@emotion/react": "^11.13.3",
-        "@emotion/styled": "^11.13.0",
-        "@mui/material": "^6.1.6",
-        "@textea/json-viewer": "^4.0.0",
-        "react-json-tree": "^0.19.0",
-        "react-json-view": "^1.21.3"
-      }
-    },
-    "node_modules/@babel/code-frame": {
-      "version": "7.26.2",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
-      "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/helper-validator-identifier": "^7.25.9",
-        "js-tokens": "^4.0.0",
-        "picocolors": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/generator": {
-      "version": "7.26.2",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz",
-      "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/parser": "^7.26.2",
-        "@babel/types": "^7.26.0",
-        "@jridgewell/gen-mapping": "^0.3.5",
-        "@jridgewell/trace-mapping": "^0.3.25",
-        "jsesc": "^3.0.2"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/helper-module-imports": {
-      "version": "7.25.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
-      "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/traverse": "^7.25.9",
-        "@babel/types": "^7.25.9"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/helper-string-parser": {
-      "version": "7.25.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
-      "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/helper-validator-identifier": {
-      "version": "7.25.9",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
-      "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/parser": {
-      "version": "7.26.2",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz",
-      "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/types": "^7.26.0"
-      },
-      "bin": {
-        "parser": "bin/babel-parser.js"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@babel/runtime": {
-      "version": "7.26.0",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
-      "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
-      "license": "MIT",
-      "dependencies": {
-        "regenerator-runtime": "^0.14.0"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/template": {
-      "version": "7.25.9",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz",
-      "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/code-frame": "^7.25.9",
-        "@babel/parser": "^7.25.9",
-        "@babel/types": "^7.25.9"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/traverse": {
-      "version": "7.25.9",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz",
-      "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/code-frame": "^7.25.9",
-        "@babel/generator": "^7.25.9",
-        "@babel/parser": "^7.25.9",
-        "@babel/template": "^7.25.9",
-        "@babel/types": "^7.25.9",
-        "debug": "^4.3.1",
-        "globals": "^11.1.0"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/types": {
-      "version": "7.26.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
-      "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/helper-string-parser": "^7.25.9",
-        "@babel/helper-validator-identifier": "^7.25.9"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@emotion/babel-plugin": {
-      "version": "11.12.0",
-      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
-      "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/helper-module-imports": "^7.16.7",
-        "@babel/runtime": "^7.18.3",
-        "@emotion/hash": "^0.9.2",
-        "@emotion/memoize": "^0.9.0",
-        "@emotion/serialize": "^1.2.0",
-        "babel-plugin-macros": "^3.1.0",
-        "convert-source-map": "^1.5.0",
-        "escape-string-regexp": "^4.0.0",
-        "find-root": "^1.1.0",
-        "source-map": "^0.5.7",
-        "stylis": "4.2.0"
-      }
-    },
-    "node_modules/@emotion/cache": {
-      "version": "11.13.1",
-      "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz",
-      "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==",
-      "license": "MIT",
-      "dependencies": {
-        "@emotion/memoize": "^0.9.0",
-        "@emotion/sheet": "^1.4.0",
-        "@emotion/utils": "^1.4.0",
-        "@emotion/weak-memoize": "^0.4.0",
-        "stylis": "4.2.0"
-      }
-    },
-    "node_modules/@emotion/hash": {
-      "version": "0.9.2",
-      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
-      "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
-      "license": "MIT"
-    },
-    "node_modules/@emotion/is-prop-valid": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz",
-      "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==",
-      "license": "MIT",
-      "dependencies": {
-        "@emotion/memoize": "^0.9.0"
-      }
-    },
-    "node_modules/@emotion/memoize": {
-      "version": "0.9.0",
-      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
-      "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
-      "license": "MIT"
-    },
-    "node_modules/@emotion/react": {
-      "version": "11.13.3",
-      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz",
-      "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.18.3",
-        "@emotion/babel-plugin": "^11.12.0",
-        "@emotion/cache": "^11.13.0",
-        "@emotion/serialize": "^1.3.1",
-        "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
-        "@emotion/utils": "^1.4.0",
-        "@emotion/weak-memoize": "^0.4.0",
-        "hoist-non-react-statics": "^3.3.1"
-      },
-      "peerDependencies": {
-        "react": ">=16.8.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@emotion/serialize": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz",
-      "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==",
-      "license": "MIT",
-      "dependencies": {
-        "@emotion/hash": "^0.9.2",
-        "@emotion/memoize": "^0.9.0",
-        "@emotion/unitless": "^0.10.0",
-        "@emotion/utils": "^1.4.1",
-        "csstype": "^3.0.2"
-      }
-    },
-    "node_modules/@emotion/sheet": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
-      "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
-      "license": "MIT"
-    },
-    "node_modules/@emotion/styled": {
-      "version": "11.13.0",
-      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz",
-      "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.18.3",
-        "@emotion/babel-plugin": "^11.12.0",
-        "@emotion/is-prop-valid": "^1.3.0",
-        "@emotion/serialize": "^1.3.0",
-        "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
-        "@emotion/utils": "^1.4.0"
-      },
-      "peerDependencies": {
-        "@emotion/react": "^11.0.0-rc.0",
-        "react": ">=16.8.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@emotion/unitless": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
-      "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
-      "license": "MIT"
-    },
-    "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz",
-      "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==",
-      "license": "MIT",
-      "peerDependencies": {
-        "react": ">=16.8.0"
-      }
-    },
-    "node_modules/@emotion/utils": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz",
-      "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==",
-      "license": "MIT"
-    },
-    "node_modules/@emotion/weak-memoize": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
-      "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
-      "license": "MIT"
-    },
-    "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
-      "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/set-array": "^1.2.1",
-        "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.24"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/resolve-uri": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
-      "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/set-array": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
-      "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
-      "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
-      "license": "MIT"
-    },
-    "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.25",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
-      "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/resolve-uri": "^3.1.0",
-        "@jridgewell/sourcemap-codec": "^1.4.14"
-      }
-    },
-    "node_modules/@mui/core-downloads-tracker": {
-      "version": "6.1.6",
-      "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.6.tgz",
-      "integrity": "sha512-nz1SlR9TdBYYPz4qKoNasMPRiGb4PaIHFkzLzhju0YVYS5QSuFF2+n7CsiHMIDcHv3piPu/xDWI53ruhOqvZwQ==",
-      "license": "MIT",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui-org"
-      }
-    },
-    "node_modules/@mui/material": {
-      "version": "6.1.6",
-      "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.6.tgz",
-      "integrity": "sha512-1yvejiQ/601l5AK3uIdUlAVElyCxoqKnl7QA+2oFB/2qYPWfRwDgavW/MoywS5Y2gZEslcJKhe0s2F3IthgFgw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.26.0",
-        "@mui/core-downloads-tracker": "^6.1.6",
-        "@mui/system": "^6.1.6",
-        "@mui/types": "^7.2.19",
-        "@mui/utils": "^6.1.6",
-        "@popperjs/core": "^2.11.8",
-        "@types/react-transition-group": "^4.4.11",
-        "clsx": "^2.1.1",
-        "csstype": "^3.1.3",
-        "prop-types": "^15.8.1",
-        "react-is": "^18.3.1",
-        "react-transition-group": "^4.4.5"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui-org"
-      },
-      "peerDependencies": {
-        "@emotion/react": "^11.5.0",
-        "@emotion/styled": "^11.3.0",
-        "@mui/material-pigment-css": "^6.1.6",
-        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
-        "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
-        "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@emotion/react": {
-          "optional": true
-        },
-        "@emotion/styled": {
-          "optional": true
-        },
-        "@mui/material-pigment-css": {
-          "optional": true
-        },
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@mui/private-theming": {
-      "version": "6.1.6",
-      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.6.tgz",
-      "integrity": "sha512-ioAiFckaD/fJSnTrUMWgjl9HYBWt7ixCh7zZw7gDZ+Tae7NuprNV6QJK95EidDT7K0GetR2rU3kAeIR61Myttw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.26.0",
-        "@mui/utils": "^6.1.6",
-        "prop-types": "^15.8.1"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui-org"
-      },
-      "peerDependencies": {
-        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
-        "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@mui/styled-engine": {
-      "version": "6.1.6",
-      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.6.tgz",
-      "integrity": "sha512-I+yS1cSuSvHnZDBO7e7VHxTWpj+R7XlSZvTC4lS/OIbUNJOMMSd3UDP6V2sfwzAdmdDNBi7NGCRv2SZ6O9hGDA==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.26.0",
-        "@emotion/cache": "^11.13.1",
-        "@emotion/serialize": "^1.3.2",
-        "@emotion/sheet": "^1.4.0",
-        "csstype": "^3.1.3",
-        "prop-types": "^15.8.1"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui-org"
-      },
-      "peerDependencies": {
-        "@emotion/react": "^11.4.1",
-        "@emotion/styled": "^11.3.0",
-        "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@emotion/react": {
-          "optional": true
-        },
-        "@emotion/styled": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@mui/system": {
-      "version": "6.1.6",
-      "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.6.tgz",
-      "integrity": "sha512-qOf1VUE9wK8syiB0BBCp82oNBAVPYdj4Trh+G1s+L+ImYiKlubWhhqlnvWt3xqMevR+D2h1CXzA1vhX2FvA+VQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.26.0",
-        "@mui/private-theming": "^6.1.6",
-        "@mui/styled-engine": "^6.1.6",
-        "@mui/types": "^7.2.19",
-        "@mui/utils": "^6.1.6",
-        "clsx": "^2.1.1",
-        "csstype": "^3.1.3",
-        "prop-types": "^15.8.1"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui-org"
-      },
-      "peerDependencies": {
-        "@emotion/react": "^11.5.0",
-        "@emotion/styled": "^11.3.0",
-        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
-        "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@emotion/react": {
-          "optional": true
-        },
-        "@emotion/styled": {
-          "optional": true
-        },
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@mui/types": {
-      "version": "7.2.19",
-      "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz",
-      "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==",
-      "license": "MIT",
-      "peerDependencies": {
-        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@mui/utils": {
-      "version": "6.1.6",
-      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.6.tgz",
-      "integrity": "sha512-sBS6D9mJECtELASLM+18WUcXF6RH3zNxBRFeyCRg8wad6NbyNrdxLuwK+Ikvc38sTZwBzAz691HmSofLqHd9sQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.26.0",
-        "@mui/types": "^7.2.19",
-        "@types/prop-types": "^15.7.13",
-        "clsx": "^2.1.1",
-        "prop-types": "^15.8.1",
-        "react-is": "^18.3.1"
-      },
-      "engines": {
-        "node": ">=14.0.0"
-      },
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/mui-org"
-      },
-      "peerDependencies": {
-        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
-        "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@popperjs/core": {
-      "version": "2.11.8",
-      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
-      "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
-      "license": "MIT",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/popperjs"
-      }
-    },
-    "node_modules/@textea/json-viewer": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/@textea/json-viewer/-/json-viewer-4.0.0.tgz",
-      "integrity": "sha512-TOrvWJ3E1Qg8pRu2eTdMSYJl/JwaYtMGD6EIzYsaicFIA0jICZa/WH4D7/0anH5At8eYfubPTfjjBqnair5WIA==",
-      "license": "MIT",
-      "dependencies": {
-        "clsx": "^2.1.1",
-        "copy-to-clipboard": "^3.3.3",
-        "zustand": "^4.5.5"
-      },
-      "peerDependencies": {
-        "@emotion/react": "^11",
-        "@emotion/styled": "^11",
-        "@mui/material": "^6",
-        "react": "^17 || ^18",
-        "react-dom": "^17 || ^18"
-      }
-    },
-    "node_modules/@types/lodash": {
-      "version": "4.17.13",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.13.tgz",
-      "integrity": "sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==",
-      "license": "MIT"
-    },
-    "node_modules/@types/parse-json": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
-      "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
-      "license": "MIT"
-    },
-    "node_modules/@types/prop-types": {
-      "version": "15.7.13",
-      "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
-      "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
-      "license": "MIT"
-    },
-    "node_modules/@types/react": {
-      "version": "18.3.12",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
-      "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/prop-types": "*",
-        "csstype": "^3.0.2"
-      }
-    },
-    "node_modules/@types/react-transition-group": {
-      "version": "4.4.11",
-      "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
-      "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/react": "*"
-      }
-    },
-    "node_modules/asap": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-      "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
-      "license": "MIT"
-    },
-    "node_modules/babel-plugin-macros": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
-      "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.12.5",
-        "cosmiconfig": "^7.0.0",
-        "resolve": "^1.19.0"
-      },
-      "engines": {
-        "node": ">=10",
-        "npm": ">=6"
-      }
-    },
-    "node_modules/base16": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
-      "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==",
-      "license": "MIT"
-    },
-    "node_modules/callsites": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/clsx": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
-      "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/color": {
-      "version": "4.2.3",
-      "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
-      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
-      "license": "MIT",
-      "dependencies": {
-        "color-convert": "^2.0.1",
-        "color-string": "^1.9.0"
-      },
-      "engines": {
-        "node": ">=12.5.0"
-      }
-    },
-    "node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "license": "MIT",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
-      "engines": {
-        "node": ">=7.0.0"
-      }
-    },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "license": "MIT"
-    },
-    "node_modules/color-string": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
-      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
-      "license": "MIT",
-      "dependencies": {
-        "color-name": "^1.0.0",
-        "simple-swizzle": "^0.2.2"
-      }
-    },
-    "node_modules/convert-source-map": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
-      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
-      "license": "MIT"
-    },
-    "node_modules/copy-to-clipboard": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
-      "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
-      "license": "MIT",
-      "dependencies": {
-        "toggle-selection": "^1.0.6"
-      }
-    },
-    "node_modules/cosmiconfig": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
-      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/parse-json": "^4.0.0",
-        "import-fresh": "^3.2.1",
-        "parse-json": "^5.0.0",
-        "path-type": "^4.0.0",
-        "yaml": "^1.10.0"
-      },
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/cross-fetch": {
-      "version": "3.1.8",
-      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
-      "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
-      "license": "MIT",
-      "dependencies": {
-        "node-fetch": "^2.6.12"
-      }
-    },
-    "node_modules/csstype": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
-      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
-      "license": "MIT"
-    },
-    "node_modules/debug": {
-      "version": "4.3.7",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
-      "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
-      "license": "MIT",
-      "dependencies": {
-        "ms": "^2.1.3"
-      },
-      "engines": {
-        "node": ">=6.0"
-      },
-      "peerDependenciesMeta": {
-        "supports-color": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/dom-helpers": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
-      "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.8.7",
-        "csstype": "^3.0.2"
-      }
-    },
-    "node_modules/error-ex": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-      "license": "MIT",
-      "dependencies": {
-        "is-arrayish": "^0.2.1"
-      }
-    },
-    "node_modules/escape-string-regexp": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/fbemitter": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz",
-      "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==",
-      "license": "BSD-3-Clause",
-      "dependencies": {
-        "fbjs": "^3.0.0"
-      }
-    },
-    "node_modules/fbjs": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
-      "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
-      "license": "MIT",
-      "dependencies": {
-        "cross-fetch": "^3.1.5",
-        "fbjs-css-vars": "^1.0.0",
-        "loose-envify": "^1.0.0",
-        "object-assign": "^4.1.0",
-        "promise": "^7.1.1",
-        "setimmediate": "^1.0.5",
-        "ua-parser-js": "^1.0.35"
-      }
-    },
-    "node_modules/fbjs-css-vars": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
-      "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==",
-      "license": "MIT"
-    },
-    "node_modules/find-root": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
-      "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
-      "license": "MIT"
-    },
-    "node_modules/flux": {
-      "version": "4.0.4",
-      "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz",
-      "integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==",
-      "license": "BSD-3-Clause",
-      "dependencies": {
-        "fbemitter": "^3.0.0",
-        "fbjs": "^3.0.1"
-      },
-      "peerDependencies": {
-        "react": "^15.0.2 || ^16.0.0 || ^17.0.0"
-      }
-    },
-    "node_modules/function-bind": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
-      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/globals": {
-      "version": "11.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/hasown": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
-      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-      "license": "MIT",
-      "dependencies": {
-        "function-bind": "^1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/hoist-non-react-statics": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
-      "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
-      "license": "BSD-3-Clause",
-      "dependencies": {
-        "react-is": "^16.7.0"
-      }
-    },
-    "node_modules/hoist-non-react-statics/node_modules/react-is": {
-      "version": "16.13.1",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
-      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
-      "license": "MIT"
-    },
-    "node_modules/import-fresh": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
-      "license": "MIT",
-      "dependencies": {
-        "parent-module": "^1.0.0",
-        "resolve-from": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/is-arrayish": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
-      "license": "MIT"
-    },
-    "node_modules/is-core-module": {
-      "version": "2.15.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
-      "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
-      "license": "MIT",
-      "dependencies": {
-        "hasown": "^2.0.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "license": "MIT"
-    },
-    "node_modules/jsesc": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
-      "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
-      "license": "MIT",
-      "bin": {
-        "jsesc": "bin/jsesc"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/json-parse-even-better-errors": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
-      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
-      "license": "MIT"
-    },
-    "node_modules/lines-and-columns": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
-      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
-      "license": "MIT"
-    },
-    "node_modules/lodash-es": {
-      "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
-      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
-      "license": "MIT"
-    },
-    "node_modules/lodash.curry": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
-      "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==",
-      "license": "MIT"
-    },
-    "node_modules/lodash.flow": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
-      "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==",
-      "license": "MIT"
-    },
-    "node_modules/loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "license": "MIT",
-      "dependencies": {
-        "js-tokens": "^3.0.0 || ^4.0.0"
-      },
-      "bin": {
-        "loose-envify": "cli.js"
-      }
-    },
-    "node_modules/ms": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-      "license": "MIT"
-    },
-    "node_modules/node-fetch": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
-      "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
-      "license": "MIT",
-      "dependencies": {
-        "whatwg-url": "^5.0.0"
-      },
-      "engines": {
-        "node": "4.x || >=6.0.0"
-      },
-      "peerDependencies": {
-        "encoding": "^0.1.0"
-      },
-      "peerDependenciesMeta": {
-        "encoding": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/parent-module": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-      "license": "MIT",
-      "dependencies": {
-        "callsites": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/parse-json": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
-      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/code-frame": "^7.0.0",
-        "error-ex": "^1.3.1",
-        "json-parse-even-better-errors": "^2.3.0",
-        "lines-and-columns": "^1.1.6"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/path-parse": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-      "license": "MIT"
-    },
-    "node_modules/path-type": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/picocolors": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
-      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
-      "license": "ISC"
-    },
-    "node_modules/promise": {
-      "version": "7.3.1",
-      "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
-      "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
-      "license": "MIT",
-      "dependencies": {
-        "asap": "~2.0.3"
-      }
-    },
-    "node_modules/prop-types": {
-      "version": "15.8.1",
-      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
-      "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
-      "license": "MIT",
-      "dependencies": {
-        "loose-envify": "^1.4.0",
-        "object-assign": "^4.1.1",
-        "react-is": "^16.13.1"
-      }
-    },
-    "node_modules/prop-types/node_modules/react-is": {
-      "version": "16.13.1",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
-      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
-      "license": "MIT"
-    },
-    "node_modules/pure-color": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
-      "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==",
-      "license": "MIT"
-    },
-    "node_modules/react": {
-      "version": "17.0.2",
-      "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
-      "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "loose-envify": "^1.1.0",
-        "object-assign": "^4.1.1"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/react-base16-styling": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.10.0.tgz",
-      "integrity": "sha512-H1k2eFB6M45OaiRru3PBXkuCcn2qNmx+gzLb4a9IPMR7tMH8oBRXU5jGbPDYG1Hz+82d88ED0vjR8BmqU3pQdg==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/lodash": "^4.17.0",
-        "color": "^4.2.3",
-        "csstype": "^3.1.3",
-        "lodash-es": "^4.17.21"
-      }
-    },
-    "node_modules/react-dom": {
-      "version": "17.0.2",
-      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
-      "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "loose-envify": "^1.1.0",
-        "object-assign": "^4.1.1",
-        "scheduler": "^0.20.2"
-      },
-      "peerDependencies": {
-        "react": "17.0.2"
-      }
-    },
-    "node_modules/react-is": {
-      "version": "18.3.1",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
-      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
-      "license": "MIT"
-    },
-    "node_modules/react-json-tree": {
-      "version": "0.19.0",
-      "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.19.0.tgz",
-      "integrity": "sha512-PqT1WRVcWP+RROsZPQfNEKIC1iM/ZMfY4g5jN6oDnXp5593PPRAYgoHcgYCDjflAHQMtxl8XGdlTwIBdEGUXvw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/lodash": "^4.17.0",
-        "react-base16-styling": "^0.10.0"
-      },
-      "peerDependencies": {
-        "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
-      }
-    },
-    "node_modules/react-json-view": {
-      "version": "1.21.3",
-      "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz",
-      "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==",
-      "license": "MIT",
-      "dependencies": {
-        "flux": "^4.0.1",
-        "react-base16-styling": "^0.6.0",
-        "react-lifecycles-compat": "^3.0.4",
-        "react-textarea-autosize": "^8.3.2"
-      },
-      "peerDependencies": {
-        "react": "^17.0.0 || ^16.3.0 || ^15.5.4",
-        "react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4"
-      }
-    },
-    "node_modules/react-json-view/node_modules/react-base16-styling": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz",
-      "integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==",
-      "license": "MIT",
-      "dependencies": {
-        "base16": "^1.0.0",
-        "lodash.curry": "^4.0.1",
-        "lodash.flow": "^3.3.0",
-        "pure-color": "^1.2.0"
-      }
-    },
-    "node_modules/react-lifecycles-compat": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
-      "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
-      "license": "MIT"
-    },
-    "node_modules/react-textarea-autosize": {
-      "version": "8.5.4",
-      "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.4.tgz",
-      "integrity": "sha512-eSSjVtRLcLfFwFcariT77t9hcbVJHQV76b51QjQGarQIHml2+gM2lms0n3XrhnDmgK5B+/Z7TmQk5OHNzqYm/A==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.20.13",
-        "use-composed-ref": "^1.3.0",
-        "use-latest": "^1.2.1"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "peerDependencies": {
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
-      }
-    },
-    "node_modules/react-transition-group": {
-      "version": "4.4.5",
-      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
-      "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
-      "license": "BSD-3-Clause",
-      "dependencies": {
-        "@babel/runtime": "^7.5.5",
-        "dom-helpers": "^5.0.1",
-        "loose-envify": "^1.4.0",
-        "prop-types": "^15.6.2"
-      },
-      "peerDependencies": {
-        "react": ">=16.6.0",
-        "react-dom": ">=16.6.0"
-      }
-    },
-    "node_modules/regenerator-runtime": {
-      "version": "0.14.1",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
-      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
-      "license": "MIT"
-    },
-    "node_modules/resolve": {
-      "version": "1.22.8",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
-      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
-      "license": "MIT",
-      "dependencies": {
-        "is-core-module": "^2.13.0",
-        "path-parse": "^1.0.7",
-        "supports-preserve-symlinks-flag": "^1.0.0"
-      },
-      "bin": {
-        "resolve": "bin/resolve"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/resolve-from": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/scheduler": {
-      "version": "0.20.2",
-      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
-      "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
-      "license": "MIT",
-      "peer": true,
-      "dependencies": {
-        "loose-envify": "^1.1.0",
-        "object-assign": "^4.1.1"
-      }
-    },
-    "node_modules/setimmediate": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
-      "license": "MIT"
-    },
-    "node_modules/simple-swizzle": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
-      "license": "MIT",
-      "dependencies": {
-        "is-arrayish": "^0.3.1"
-      }
-    },
-    "node_modules/simple-swizzle/node_modules/is-arrayish": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
-      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
-      "license": "MIT"
-    },
-    "node_modules/source-map": {
-      "version": "0.5.7",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
-      "license": "BSD-3-Clause",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/stylis": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
-      "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
-      "license": "MIT"
-    },
-    "node_modules/supports-preserve-symlinks-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/toggle-selection": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
-      "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
-      "license": "MIT"
-    },
-    "node_modules/tr46": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
-      "license": "MIT"
-    },
-    "node_modules/ua-parser-js": {
-      "version": "1.0.39",
-      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.39.tgz",
-      "integrity": "sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==",
-      "funding": [
-        {
-          "type": "opencollective",
-          "url": "https://opencollective.com/ua-parser-js"
-        },
-        {
-          "type": "paypal",
-          "url": "https://paypal.me/faisalman"
-        },
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/faisalman"
-        }
-      ],
-      "license": "MIT",
-      "bin": {
-        "ua-parser-js": "script/cli.js"
-      },
-      "engines": {
-        "node": "*"
-      }
-    },
-    "node_modules/use-composed-ref": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz",
-      "integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==",
-      "license": "MIT",
-      "peerDependencies": {
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
-      }
-    },
-    "node_modules/use-isomorphic-layout-effect": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
-      "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
-      "license": "MIT",
-      "peerDependencies": {
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/use-latest": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz",
-      "integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==",
-      "license": "MIT",
-      "dependencies": {
-        "use-isomorphic-layout-effect": "^1.1.1"
-      },
-      "peerDependencies": {
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/use-sync-external-store": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
-      "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
-      "license": "MIT",
-      "peerDependencies": {
-        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
-      }
-    },
-    "node_modules/webidl-conversions": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
-      "license": "BSD-2-Clause"
-    },
-    "node_modules/whatwg-url": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
-      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
-      "license": "MIT",
-      "dependencies": {
-        "tr46": "~0.0.3",
-        "webidl-conversions": "^3.0.0"
-      }
-    },
-    "node_modules/yaml": {
-      "version": "1.10.2",
-      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
-      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
-      "license": "ISC",
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/zustand": {
-      "version": "4.5.5",
-      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz",
-      "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==",
-      "license": "MIT",
-      "dependencies": {
-        "use-sync-external-store": "1.2.2"
-      },
-      "engines": {
-        "node": ">=12.7.0"
-      },
-      "peerDependencies": {
-        "@types/react": ">=16.8",
-        "immer": ">=9.0.6",
-        "react": ">=16.8"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        },
-        "immer": {
-          "optional": true
-        },
-        "react": {
-          "optional": true
-        }
-      }
-    }
-  }
-}

+ 7 - 5
taipy/gui/_renderers/builder.py

@@ -356,8 +356,9 @@ class _Builder:
         if isinstance(value, list):
             self.__set_json_attribute(_to_camel_case(f"default_{name}"), value)
         if hash := self.__hashes.get(name):
-            self.__update_vars.append(f"{name}={hash}")
-            self.__set_react_attribute(name, hash)
+            prop_name = _to_camel_case(name)
+            self.__update_vars.append(f"{prop_name}={hash}")
+            self.__set_react_attribute(prop_name, hash)
         return self
 
     def __set_list_attribute(
@@ -373,11 +374,12 @@ class _Builder:
         if not hash and isinstance(value, str):
             value = [elt_type(t.strip()) for t in value.split(";")]
         if isinstance(value, list):
+            prop_name = _to_camel_case(name)
             if hash and dynamic:
-                self.__set_react_attribute(name, hash)
-                return [f"{name}={hash}"]
+                self.__set_react_attribute(prop_name, hash)
+                return [f"{prop_name}={hash}"]
             else:
-                self.__set_json_attribute(name, value)
+                self.__set_json_attribute(prop_name, value)
         elif value is not None:
             _warn(f"{self.__element_name}: {name} should be a list of {elt_type}.")
         return []

+ 11 - 1
taipy/gui/_renderers/factory.py

@@ -373,7 +373,7 @@ class _Factory:
                 ("hover_text", PropertyType.dynamic_string),
                 ("width",),
                 ("width[mobile]",),
-                ("expanded",PropertyType.boolean, False),
+                ("expanded", PropertyType.boolean, False),
             ]
         )
         ._set_propagate(),
@@ -475,6 +475,10 @@ class _Factory:
                 ("height", PropertyType.dynamic_string),
                 ("content", PropertyType.toHtmlContent),
                 ("width", PropertyType.string_or_number),
+                ("drag_type", PropertyType.string),
+                ("drop_types", PropertyType.string_list),
+                ("on_action", PropertyType.function),
+                ("drag_parameters", PropertyType.dict),
             ]
         ),
         "progress": lambda gui, control_type, attrs: _Builder(
@@ -514,6 +518,9 @@ class _Factory:
                 ("lov", PropertyType.lov),
                 ("selection_message", PropertyType.dynamic_string),
                 ("show_select_all", PropertyType.boolean),
+                ("drag_type", PropertyType.string),
+                ("drop_types", PropertyType.string_list),
+                ("on_action", PropertyType.function),
             ]
         )
         ._set_propagate(),
@@ -670,6 +677,9 @@ class _Factory:
                 ("select_leafs_only", PropertyType.boolean),
                 ("row_height", PropertyType.string),
                 ("lov", PropertyType.lov),
+                ("drag_type", PropertyType.string),
+                ("drop_types", PropertyType.string_list),
+                ("on_action", PropertyType.function),
             ]
         )
         ._set_propagate(),

+ 69 - 6
taipy/gui/viselements.json

@@ -1156,6 +1156,35 @@
                         "name": "height",
                         "type": "Union[str, int]",
                         "doc": "The height of the selector, in CSS units."
+                    },
+                    {
+                        "name": "drag_type",
+                        "type": "str",
+                        "doc": "The draggable type associated to this selector."
+                    },
+                    {
+                        "name": "drop_types",
+                        "type": "list(str)",
+                        "doc": "The list of the draggable types that can be dropped on this selector."
+                    },
+                    {
+                        "name": "on_action",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user drops a draggable item.<br/>This function is invoked with the following parameters:<ul><li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>id</i> (str): the selector id.</li><li><i>payload</i> (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul><li><i>action</i>: the name of the action that triggered this callback.</li><li><i>reason</i> (str): the reason that triggered this action here \"drop\", the item id, the item index on which the item was dropped, the source lov variable name if any, the source component id if any, the target lov variable name if any, the target component id if any.</li></ul></li></ul>",
+                        "signature": [
+                            [
+                                "state",
+                                "State"
+                            ],
+                            [
+                                "id",
+                                "str"
+                            ],
+                            [
+                                "payload",
+                                "dict"
+                            ]
+                        ]
                     }
                 ]
             }
@@ -1660,8 +1689,8 @@
                     },
                     {
                         "name": "expanded",
-                        "type":"bool",
-                        "default_value":"False",
+                        "type": "bool",
+                        "default_value": "False",
                         "doc": "Defines whether the menu starts expanded or folded"
                     }
                 ]
@@ -1959,6 +1988,40 @@
                         "name": "content",
                         "type": "dynamic(Any)",
                         "doc": "The content provided to the part. See the documentation section on content providers."
+                    },
+                    {
+                        "name": "drag_type",
+                        "type": "str",
+                        "doc": "The draggable type associated to this part."
+                    },
+                    {
+                        "name": "drop_types",
+                        "type": "list(str)",
+                        "doc": "The list of the draggable types that can be dropped on this part."
+                    },
+                    {
+                        "name": "drag_parameters",
+                        "type": "dict",
+                        "doc": "The parameters associated to the part if draggable."
+                    },
+                    {
+                        "name": "on_action",
+                        "type": "Union[str, Callable]",
+                        "doc": "A function or the name of a function that is triggered when the user drops a draggable item.<br/>This function is invoked with the following parameters:<ul><li><i>state</i> (<code>State^</code>): the state instance.</li><li><i>id</i> (str): the part id.</li><li><i>payload</i> (dict): the details on this callback's invocation.<br/>This dictionary has the following keys:\n<ul><li><i>action</i>: the name of the action that triggered this callback.</li><li><i>reason</i> (str): the reason that triggered this action here \"drop\", the item id if any, the source component id if any, the target component id if any, the drag parameters if any.</li></ul></li></ul>",
+                        "signature": [
+                            [
+                                "state",
+                                "State"
+                            ],
+                            [
+                                "id",
+                                "str"
+                            ],
+                            [
+                                "payload",
+                                "dict"
+                            ]
+                        ]
                     }
                 ]
             }
@@ -2044,10 +2107,10 @@
                         "doc": "The height of the dialog, in CSS units."
                     },
                     {
-			"name": "ref_id",
-			"type": "dynamic(str)",
-			"doc": "The id of an HTML element or a query selector that identifies the reference element serving as the anchor for the dialog."
-		    }
+                        "name": "ref_id",
+                        "type": "dynamic(str)",
+                        "doc": "The id of an HTML element or a query selector that identifies the reference element serving as the anchor for the dialog."
+                    }
                 ]
             }
         ],