import {
  PAGE_ROW_COMPONENT_ID,
  assertIsElement,
  getApp,
  getChildNodes,
  getElementNodeComponentId,
  getNode,
  getPageDisplayName,
  getPageTitle,
  isElement,
  isMutation,
  isPage,
  isPageLayoutComponent,
  isPageRow,
  isQuery
} from "./chunk-ZUJ4UAKT.mjs";

// src/runtime/AppLayout.tsx
import * as React from "react";
import { Box, Drawer, List, ListItem, ListItemButton, ListItemText } from "@mui/material";
import { Link, useSearchParams } from "react-router-dom";

// src/runtime/constants.ts
var HTML_ID_EDITOR_OVERLAY = "editor-overlay";
var IS_PREVIEW = process.env.NODE_ENV !== "production";
var IS_CUSTOM_SERVER = process.env.TOOLPAD_CUSTOM_SERVER === "true";
var PREVIEW_HEADER_HEIGHT = 52;

// src/runtime/AppLayout.tsx
var TOOLPAD_DISPLAY_MODE_URL_PARAM = "toolpad-display";
var RETAINED_URL_PARAMS = /* @__PURE__ */ new Set([TOOLPAD_DISPLAY_MODE_URL_PARAM]);
var DRAWER_WIDTH = 250;
function AppPagesNavigation({
  activePage,
  pages,
  clipped = false,
  search
}) {
  const navListSubheaderId = React.useId();
  return /* @__PURE__ */ React.createElement(
    Drawer,
    {
      variant: "permanent",
      anchor: "left",
      open: true,
      sx: {
        width: DRAWER_WIDTH,
        flexShrink: 0,
        [`& .MuiDrawer-paper`]: {
          width: DRAWER_WIDTH,
          boxSizing: "border-box",
          border: "none"
        }
      }
    },
    clipped ? /* @__PURE__ */ React.createElement(Box, { sx: { height: PREVIEW_HEADER_HEIGHT } }) : null,
    /* @__PURE__ */ React.createElement(List, { component: "nav", sx: { px: 2 }, "aria-labelledby": navListSubheaderId }, pages.map((page) => /* @__PURE__ */ React.createElement(
      ListItem,
      {
        key: page.slug,
        disablePadding: true,
        sx: {
          borderRadius: "24px",
          overflow: "hidden"
        }
      },
      /* @__PURE__ */ React.createElement(
        ListItemButton,
        {
          component: Link,
          to: `pages/${page.slug}${search}`,
          selected: activePage === page.slug
        },
        /* @__PURE__ */ React.createElement(ListItemText, { primary: page.displayName, sx: { ml: 2 } })
      )
    )))
  );
}
function AppLayout({
  activePage,
  pages = [],
  hasShell: hasShellProp = true,
  children,
  clipped
}) {
  const [urlParams] = useSearchParams();
  const retainedSearch = React.useMemo(() => {
    for (const name of urlParams.keys()) {
      if (!RETAINED_URL_PARAMS.has(name)) {
        urlParams.delete(name);
      }
    }
    return urlParams.size > 0 ? `?${urlParams.toString()}` : "";
  }, [urlParams]);
  const navEntry = pages.find((page) => page.slug === activePage);
  const displayMode = urlParams.get(TOOLPAD_DISPLAY_MODE_URL_PARAM);
  const hasShell = hasShellProp && navEntry?.hasShell !== false && displayMode !== "standalone";
  return /* @__PURE__ */ React.createElement(Box, { sx: { flex: 1, display: "flex" } }, hasShell ? /* @__PURE__ */ React.createElement(
    AppPagesNavigation,
    {
      activePage,
      pages,
      clipped,
      search: retainedSearch
    }
  ) : null, /* @__PURE__ */ React.createElement(Box, { sx: { minWidth: 0, flex: 1, position: "relative" } }, children));
}

// src/runtime/ToolpadApp.tsx
import * as React8 from "react";
import {
  Stack,
  CssBaseline,
  Alert as Alert2,
  Box as Box4,
  styled as styled2,
  AlertTitle,
  LinearProgress,
  Container,
  Tooltip as Tooltip2,
  Typography as Typography2
} from "@mui/material";
import {
  createComponent,
  TOOLPAD_COMPONENT,
  Slots,
  Placeholder,
  getArgTypeDefaultValue,
  ComponentsContextProvider,
  isToolpadComponent,
  createToolpadComponentThatThrows,
  useComponents,
  useComponent
} from "@mui/toolpad-core";
import {
  createGlobalState,
  createProvidedContext,
  useAssertedContext
} from "@mui/toolpad-utils/react";
import { mapProperties, mapValues as mapValues2 } from "@mui/toolpad-utils/collections";
import { set as setObjectPath2 } from "lodash-es";
import { QueryClientProvider, useMutation as useMutation2 } from "@tanstack/react-query";
import {
  BrowserRouter,
  Routes,
  Route,
  useLocation,
  Navigate,
  useNavigate,
  useMatch as useMatch2
} from "react-router-dom";
import { ErrorBoundary } from "react-error-boundary";
import {
  CanvasEventsContext,
  NodeRuntimeWrapper,
  ResetNodeErrorsKeyProvider,
  UseDataProviderContext
} from "@mui/toolpad-core/runtime";
import ErrorIcon from "@mui/icons-material/Error";
import { getBrowserRuntime } from "@mui/toolpad-core/jsBrowserRuntime";
import * as builtIns from "@mui/toolpad-components";
import { errorFrom } from "@mui/toolpad-utils/errors";
import useBoolean from "@mui/toolpad-utils/hooks/useBoolean";
import usePageTitle from "@mui/toolpad-utils/hooks/usePageTitle";
import invariant3 from "invariant";
import useEventCallback from "@mui/utils/useEventCallback";

// src/runtime/bindings.ts
import { hasOwnProperty } from "@mui/toolpad-utils/collections";
function getBindingType(binding) {
  if (binding && typeof binding === "object") {
    if (hasOwnProperty(binding, "$$jsExpression")) {
      return "jsExpression";
    }
    if (hasOwnProperty(binding, "$$env")) {
      return "env";
    }
    if (hasOwnProperty(binding, "$$jsExpressionAction")) {
      return "jsExpressionAction";
    }
    if (hasOwnProperty(binding, "$$navigationAction")) {
      return "navigationAction";
    }
  }
  return "const";
}
function getBindingValue(binding) {
  if (binding && typeof binding === "object") {
    if (hasOwnProperty(binding, "$$jsExpression")) {
      return binding.$$jsExpression;
    }
    if (hasOwnProperty(binding, "$$env")) {
      return binding.$$env;
    }
    if (hasOwnProperty(binding, "$$jsExpressionAction")) {
      return binding.$$jsExpressionAction;
    }
    if (hasOwnProperty(binding, "$$navigationAction")) {
      return binding.$$navigationAction;
    }
  }
  return binding;
}

// src/runtime/AppThemeProvider.tsx
import * as React2 from "react";
import { createTheme, ThemeProvider } from "@mui/material";
import { deepmerge } from "@mui/utils";
function createMuiThemeFromToolpadTheme(toolpadTheme = {}) {
  return createTheme(
    deepmerge(
      {
        typography: {
          h1: {
            fontSize: `3.25rem`,
            fontWeight: 800
          },
          h2: {
            fontSize: `2.25rem`,
            fontWeight: 700
          },
          h3: {
            fontSize: `1.75rem`,
            fontWeight: 700
          },
          h4: {
            fontSize: `1.5rem`,
            fontWeight: 700
          },
          h5: {
            fontSize: `1.25rem`,
            fontWeight: 700
          },
          h6: {
            fontSize: `1.15rem`,
            fontWeight: 700
          }
        },
        fontFamilyMonospaced: 'Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace'
      },
      toolpadTheme
    )
  );
}
function createToolpadAppTheme(dom) {
  const root = getApp(dom);
  const { themes = [] } = getChildNodes(dom, root);
  const themeNode = themes.length > 0 ? themes[0] : null;
  const toolpadTheme = themeNode?.theme;
  return createMuiThemeFromToolpadTheme(toolpadTheme);
}
function AppThemeProvider({ dom, children }) {
  const theme = React2.useMemo(() => createToolpadAppTheme(dom), [dom]);
  return /* @__PURE__ */ React2.createElement(ThemeProvider, { theme }, children);
}

// src/runtime/evalJsBindings.ts
import { mapValues } from "@mui/toolpad-utils/collections";
import { setWith, clone, set as setObjectPath } from "lodash-es";
function updatePath(obj, path, value) {
  return setWith(clone(obj), path, value, clone);
}
function flattenDependency(deps, dep, history = /* @__PURE__ */ new Set([dep])) {
  const depDeps = deps.get(dep) ?? /* @__PURE__ */ new Set();
  const result = new Set(depDeps);
  for (const depDep of depDeps) {
    if (!history.has(depDep)) {
      const flat = flattenDependency(deps, depDep, /* @__PURE__ */ new Set([...history, depDep]));
      for (const flatted of flat) {
        result.add(flatted);
      }
    }
  }
  return result;
}
function flattenDependencies(deps) {
  const result = /* @__PURE__ */ new Map();
  for (const dep of deps.keys()) {
    result.set(dep, flattenDependency(deps, dep));
  }
  return result;
}
function bubbleError(flatDependencies, results, bindingId) {
  const result = results[bindingId];
  if (result.error) {
    return result.error;
  }
  const deps = flatDependencies.get(bindingId) ?? /* @__PURE__ */ new Set();
  for (const dep of deps) {
    const depResult = results[dep];
    if (depResult.error) {
      return depResult.error;
    }
  }
  return void 0;
}
function bubbleLoading(flatDependencies, results, bindingId) {
  const result = results[bindingId];
  if (result.loading) {
    return true;
  }
  const deps = flatDependencies.get(bindingId) ?? /* @__PURE__ */ new Set();
  for (const dep of deps) {
    const depResult = results[dep];
    if (depResult.loading) {
      return depResult.loading;
    }
  }
  return false;
}
function buildGlobalScope(base, bindings) {
  const globalScope = { ...base };
  for (const binding of Object.values(bindings)) {
    const value = binding.result?.value;
    if (binding.scopePath && getBindingType(value) === "const") {
      setObjectPath(globalScope, binding.scopePath, value);
    }
  }
  return globalScope;
}
function evalJsBindings(jsRuntime, bindings, globalScope) {
  const bindingsMap = new Map(Object.entries(bindings));
  const bindingIdMap = /* @__PURE__ */ new Map();
  for (const [bindingId, binding] of bindingsMap) {
    if (binding.scopePath) {
      bindingIdMap.set(binding.scopePath, bindingId);
    }
  }
  const computationStatuses = /* @__PURE__ */ new Map();
  let currentParentBinding;
  const dependencies = /* @__PURE__ */ new Map();
  let proxiedScope;
  const evaluateBinding = (bindingId, scopePath) => {
    const binding = bindingId && bindingsMap.get(bindingId);
    if (!binding) {
      return null;
    }
    if (currentParentBinding) {
      let bindingDependencies = dependencies.get(currentParentBinding);
      if (!bindingDependencies) {
        bindingDependencies = /* @__PURE__ */ new Set();
        dependencies.set(currentParentBinding, bindingDependencies);
      }
      bindingDependencies.add(bindingId);
    }
    const expression = binding.expression;
    if (expression) {
      const computed = computationStatuses.get(expression);
      if (computed) {
        if (computed.result) {
          return computed.result;
        }
        throw new Error(`Cycle detected "${scopePath}"`);
      }
      computationStatuses.set(expression, { result: null });
      const prevContext = currentParentBinding;
      currentParentBinding = bindingId;
      const result = jsRuntime.evaluateExpression(expression, proxiedScope);
      currentParentBinding = prevContext;
      computationStatuses.set(expression, { result });
      return result;
    }
    if (binding.result) {
      if (binding.dependencies) {
        dependencies.set(bindingId, new Set(binding.dependencies));
      }
      return binding.result;
    }
    const initializer = binding.initializer;
    if (initializer) {
      const result = evaluateBinding(initializer, scopePath);
      if (result) {
        return result;
      }
    }
    return null;
  };
  const proxify = (obj, label) => new Proxy(obj, {
    get(target, prop, receiver) {
      if (typeof prop === "symbol") {
        return Reflect.get(target, prop, receiver);
      }
      const scopePath = label ? `${label}.${prop}` : prop;
      const bindingId = bindingIdMap.get(scopePath);
      if (bindingId) {
        const evaluated = evaluateBinding(bindingId, scopePath);
        if (evaluated) {
          return evaluated.value;
        }
      }
      const result = target[prop];
      if (result && typeof result === "object") {
        return proxify(result, scopePath);
      }
      return Reflect.get(target, prop, receiver);
    }
  });
  const scope = buildGlobalScope(globalScope, bindings);
  proxiedScope = proxify(scope);
  const results = mapValues(bindings, (binding, bindingId) => {
    return evaluateBinding(bindingId) || { value: void 0 };
  });
  const flatDependencies = flattenDependencies(dependencies);
  return mapValues(bindings, (binding, bindingId) => {
    const { scopePath } = binding;
    let bindingResult = results[bindingId];
    let nestedBindingsLoading;
    let nestedBindingsError;
    const seen = /* @__PURE__ */ new Set();
    const mergeNestedBindings = (value, parentBindingId) => {
      if (value && typeof value === "object") {
        if (seen.has(value)) {
          return;
        }
        seen.add(value);
        for (const nestedPropName of Object.keys(value)) {
          const nestedBindingId = `${parentBindingId}${Array.isArray(value) ? `[${nestedPropName}]` : `.${nestedPropName}`}`;
          const nestedBindingResult = results[nestedBindingId];
          if (nestedBindingResult) {
            if (!nestedBindingsError) {
              nestedBindingsError = bubbleError(flatDependencies, results, nestedBindingId);
            }
            if (!nestedBindingsLoading) {
              nestedBindingsLoading = bubbleLoading(flatDependencies, results, nestedBindingId);
            }
            bindingResult = updatePath(
              bindingResult,
              `value.${nestedBindingId.replace(bindingId, "")}`,
              nestedBindingResult.value
            );
          } else {
            mergeNestedBindings(
              value[nestedPropName],
              nestedBindingId
            );
          }
        }
      }
    };
    mergeNestedBindings(bindingResult.value, bindingId);
    return {
      scopePath,
      dependencies: Array.from(flatDependencies.get(bindingId) ?? []),
      result: {
        ...bindingResult,
        error: nestedBindingsError || bubbleError(flatDependencies, results, bindingId),
        loading: nestedBindingsLoading || bubbleLoading(flatDependencies, results, bindingId)
      }
    };
  });
}

// src/runtime/toolpadComponents/layoutBox.ts
var layoutBoxArgTypes = {
  horizontalAlign: {
    helperText: "Horizontal alignment of the component",
    type: "string",
    enum: ["start", "center", "end", "space-between", "space-around", "space-evenly"],
    default: "start",
    label: "Horizontal alignment",
    control: { type: "HorizontalAlign", hideLabel: true }
  },
  verticalAlign: {
    helperText: "Vertical alignment of the component.",
    type: "string",
    enum: ["start", "center", "end", "space-between", "space-around", "space-evenly"],
    default: "start",
    label: "Vertical alignment",
    control: { type: "VerticalAlign", hideLabel: true }
  }
};

// src/runtime/useDataQuery.ts
import * as React4 from "react";
import { useQuery as useQuery2 } from "@tanstack/react-query";

// src/runtime/CanvasHooksContext.tsx
import * as React3 from "react";
var CanvasHooksContext = React3.createContext({});

// src/runtime/api.ts
import { QueryClient as QueryClient2 } from "@tanstack/react-query";

// src/rpcClient.ts
import * as superjson from "superjson";
import invariant from "invariant";
import {
  useMutation,
  useQuery,
  useSuspenseQuery
} from "@tanstack/react-query";
function createRpcClient(endpoint) {
  return new Proxy({}, {
    get(target, prop) {
      return async (...params) => {
        const body = {
          name: prop,
          params
        };
        const res = await fetch(endpoint, {
          method: "POST",
          headers: {
            "content-type": "application/json"
          },
          body: JSON.stringify(body)
        });
        if (res.ok) {
          const response = await res.json();
          if (response.error) {
            const toolpadError = new Error(response.error.message, {
              cause: response.error
            });
            if (response.error.code) {
              toolpadError.code = response.error.code;
            }
            throw toolpadError;
          }
          return superjson.parse(response.result);
        }
        throw new Error(`HTTP ${res.status}`);
      };
    }
  });
}
function createRpcApi(queryClient2, endpoint) {
  const methods = createRpcClient(endpoint);
  return {
    methods,
    useQuery: (key, params, options) => {
      return useQuery({
        ...options,
        enabled: !!params && options?.enabled !== false,
        queryKey: [key, params],
        queryFn: () => {
          invariant(params, `"enabled" prop of useQuery should prevent this call'`);
          return methods[key](...params);
        }
      });
    },
    useSuspenseQuery: (key, params, options) => {
      return useSuspenseQuery({
        ...options,
        queryKey: [key, params],
        queryFn: () => {
          invariant(params, "Query has no parameters");
          return methods[key](...params);
        }
      });
    },
    useMutation: (key, options) => useMutation({ mutationFn: (params) => methods[key](...params), ...options }),
    refetchQueries(key, params) {
      return queryClient2.refetchQueries({ queryKey: [key, params] });
    },
    invalidateQueries(key, params) {
      return queryClient2.invalidateQueries({ queryKey: [key, params] });
    }
  };
}

// src/runtime/api.ts
var queryClient = new QueryClient2({
  defaultOptions: {
    queries: {
      retry: false,
      networkMode: "always"
    },
    mutations: {
      networkMode: "always"
    }
  }
});
var api_default = createRpcApi(
  queryClient,
  new URL(`${process.env.BASE_URL}/api/runtime-rpc`, window.location.href)
);

// src/runtime/useDataQuery.ts
var EMPTY_ARRAY = [];
var EMPTY_OBJECT = {};
function useDataQuery(page, node, params, {
  enabled = true,
  ...options
}) {
  const { savedNodes } = React4.useContext(CanvasHooksContext);
  const queryName = node.name;
  const pageName = page.name;
  const isNodeAvailableOnServer = savedNodes ? !!savedNodes[node.id] : true;
  const {
    isLoading,
    isFetching,
    error: fetchError,
    data: responseData = EMPTY_OBJECT,
    refetch
  } = useQuery2({
    queryKey: [pageName, queryName, params],
    queryFn: () => api_default.methods.execQuery(pageName, queryName, params),
    ...options,
    enabled: isNodeAvailableOnServer && enabled
  });
  const { data, error: apiError } = responseData;
  const error = apiError || fetchError;
  const rows = Array.isArray(data) ? data : EMPTY_ARRAY;
  const result = React4.useMemo(
    () => ({
      isLoading: isLoading && enabled,
      isFetching,
      error,
      data,
      rows,
      refetch,
      fetch: async () => {
        throw new Error(`"fetch" is unsupported for automatic queries`);
      },
      call: async () => {
        throw new Error(`"call" is unsupported for automatic queries`);
      }
    }),
    [isLoading, enabled, isFetching, error, data, rows, refetch]
  );
  return result;
}

// src/runtime/PreviewHeader.tsx
import * as React5 from "react";
import {
  Button,
  Typography,
  Box as Box2,
  useTheme,
  Alert,
  Popover,
  styled,
  IconButton,
  Tooltip,
  Snackbar,
  popoverClasses
} from "@mui/material";
import EditIcon from "@mui/icons-material/Edit";
import { useMatch } from "react-router-dom";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
function CopyToClipboardButton({ content, onClick, ...props }) {
  const [confirmSnackbarOpen, setConfirmSnackbarOpen] = React5.useState(false);
  const handleClick = React5.useCallback(
    (event) => {
      window.navigator.clipboard.writeText(content);
      setConfirmSnackbarOpen(true);
      onClick?.(event);
    },
    [content, onClick]
  );
  const handleCopySnackbarClose = React5.useCallback(() => setConfirmSnackbarOpen(false), []);
  return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Tooltip, { title: "Copy to clipboard" }, /* @__PURE__ */ React5.createElement(IconButton, { ...props, onClick: handleClick }, /* @__PURE__ */ React5.createElement(ContentCopyIcon, { fontSize: "inherit" }))), /* @__PURE__ */ React5.createElement(
    Snackbar,
    {
      open: confirmSnackbarOpen,
      autoHideDuration: 3e3,
      onClose: handleCopySnackbarClose,
      message: "Copied to clipboard"
    }
  ));
}
var classes = {
  copyToClipboardButton: "Toolpad_CodeView_CopyToClipboardButton",
  hasCopyToClipboardButton: "Toolpad_CodeView_hasCopyToClipboardButton"
};
var CodeViewRoot = styled("pre")(({ theme }) => ({
  position: "relative",
  border: `1px solid ${theme.palette.divider}`,
  padding: theme.spacing(2),
  paddingRight: theme.spacing(5),
  borderRadius: theme.shape.borderRadius,
  fontFamily: theme.fontFamilyMonospaced,
  overflow: "hidden",
  textOverflow: "ellipsis",
  whiteSpace: "nowrap",
  [`& .${classes.copyToClipboardButton}`]: {
    position: "absolute",
    top: 0,
    right: 0,
    marginTop: theme.spacing(1),
    marginRight: theme.spacing(1)
  }
}));
function CodeView({ children }) {
  return /* @__PURE__ */ React5.createElement(CodeViewRoot, null, /* @__PURE__ */ React5.createElement(Typography, { noWrap: true, component: "code", fontFamily: "inherit" }, children), children ? /* @__PURE__ */ React5.createElement(
    CopyToClipboardButton,
    {
      size: "small",
      content: children,
      className: classes.copyToClipboardButton
    }
  ) : null);
}
function OpenInEditorButton({ children = "Open in editor", ...props }) {
  return /* @__PURE__ */ React5.createElement(Button, { color: "inherit", size: "small", startIcon: /* @__PURE__ */ React5.createElement(EditIcon, null), ...props }, children);
}
function CustomServerInstructions({ basename }) {
  const id = React5.useId();
  const [anchorEl, setAnchorEl] = React5.useState(null);
  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };
  const handleClose = () => {
    setAnchorEl(null);
  };
  const open = Boolean(anchorEl);
  const appUrl = React5.useMemo(() => {
    return new URL(basename, window.location.origin).href;
  }, [basename]);
  return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(OpenInEditorButton, { "aria-describedby": id, onClick: handleClick }), /* @__PURE__ */ React5.createElement(
    Popover,
    {
      id,
      open,
      anchorEl,
      onClose: handleClose,
      anchorOrigin: {
        vertical: "bottom",
        horizontal: "right"
      },
      transformOrigin: {
        vertical: "top",
        horizontal: "right"
      },
      sx: {
        [`& .${popoverClasses.paper}`]: {
          maxWidth: 700
        }
      }
    },
    /* @__PURE__ */ React5.createElement(Box2, { sx: { p: 2 } }, /* @__PURE__ */ React5.createElement(Typography, null, "This application is running under a custom server. Run the standalone Toolpad editor to make changes to this application."), /* @__PURE__ */ React5.createElement(CodeView, null, `npx @mui/toolpad editor ${appUrl}`))
  ));
}
function PreviewHeader({ basename }) {
  const pageMatch = useMatch("/pages/:slug");
  const activePage = pageMatch?.params.slug;
  const theme = useTheme();
  return /* @__PURE__ */ React5.createElement(
    Box2,
    {
      sx: {
        position: "fixed",
        width: "100%",
        height: PREVIEW_HEADER_HEIGHT,
        zIndex: theme.zIndex.drawer + 1
      }
    },
    /* @__PURE__ */ React5.createElement(
      Alert,
      {
        severity: "warning",
        sx: {
          borderRadius: 0
        },
        action: IS_CUSTOM_SERVER ? /* @__PURE__ */ React5.createElement(CustomServerInstructions, { basename }) : /* @__PURE__ */ React5.createElement(
          OpenInEditorButton,
          {
            component: "a",
            href: activePage ? `/_toolpad/app/pages/${activePage}` : "/_toolpad/app"
          }
        )
      },
      /* @__PURE__ */ React5.createElement(Typography, { variant: "body2" }, "This is a preview version of the application, not suitable for production.")
    )
  );
}

// src/runtime/useDataProvider.ts
import * as React6 from "react";
import { useQuery as useQuery3 } from "@tanstack/react-query";
import invariant2 from "invariant";
var useDataProvider = (id) => {
  const {
    isLoading,
    error,
    data: introspection
  } = useQuery3({
    queryKey: ["introspectDataProvider", id],
    enabled: !!id,
    queryFn: async () => {
      invariant2(id, "id is required");
      const [filePath, name] = id.split(":");
      return api_default.methods.introspectDataProvider(filePath, name);
    }
  });
  const dataProvider = React6.useMemo(() => {
    if (!introspection) {
      return null;
    }
    return {
      paginationMode: introspection.paginationMode,
      getRecords: async (...args) => {
        invariant2(id, "id is required");
        const [filePath, name] = id.split(":");
        return api_default.methods.getDataProviderRecords(filePath, name, ...args);
      },
      deleteRecord: introspection.hasDeleteRecord ? async (recordId) => {
        invariant2(id, "id is required");
        const [filePath, name] = id.split(":");
        return api_default.methods.deleteDataProviderRecord(filePath, name, recordId);
      } : void 0,
      updateRecord: introspection.hasUpdateRecord ? async (recordId, values) => {
        invariant2(id, "id is required");
        const [filePath, name] = id.split(":");
        return api_default.methods.updateDataProviderRecord(filePath, name, recordId, values);
      } : void 0,
      createRecord: introspection.hasCreateRecord ? async (values) => {
        invariant2(id, "id is required");
        const [filePath, name] = id.split(":");
        return api_default.methods.createDataProviderRecord(filePath, name, values);
      } : void 0
    };
  }, [id, introspection]);
  return { isLoading, error, dataProvider };
};

// src/runtime/auth.tsx
import * as React7 from "react";
import { asArray } from "@mui/toolpad-utils/collections";
import { Box as Box3 } from "@mui/material";
var UserContext = React7.createContext(null);
function AuthenticationProvider({ children, user = null }) {
  return /* @__PURE__ */ React7.createElement(UserContext.Provider, { value: user }, children);
}
function RequireAuthorization({ children, allowedRole }) {
  const user = React7.useContext(UserContext);
  const allowedRolesSet = React7.useMemo(
    () => new Set(asArray(allowedRole ?? [])),
    [allowedRole]
  );
  let reason = null;
  if (!user) {
    reason = "User is not authenticated.";
  } else if (!user.roles || user.roles.length <= 0) {
    reason = "User has no roles defined.";
  } else if (!user.roles.some((role) => allowedRolesSet.has(role))) {
    const rolesList = user?.roles?.map((role) => JSON.stringify(role)).join(", ");
    reason = `User with role(s) ${rolesList} is not allowed access to this resource.`;
  }
  return reason ? /* @__PURE__ */ React7.createElement(
    Box3,
    {
      sx: {
        flex: 1,
        display: "flex",
        alignItems: "center",
        justifyContent: "center"
      }
    },
    "Unauthorized. ",
    reason
  ) : children;
}

// src/runtime/ToolpadApp.tsx
var browserJsRuntime = getBrowserRuntime();
var IS_RENDERED_IN_CANVAS = typeof window === "undefined" ? false : !!window.frameElement?.dataset?.toolpadCanvas;
var SHOW_PREVIEW_HEADER = IS_PREVIEW && !IS_RENDERED_IN_CANVAS;
var componentsStore = createGlobalState({});
var pageComponentsStore = createGlobalState({});
var Pre = styled2("pre")(({ theme }) => ({
  margin: 0,
  fontFamily: theme.fontFamilyMonospaced
}));
var internalComponents = Object.fromEntries(
  Object.entries(builtIns).map(([name, builtIn]) => {
    if (!isToolpadComponent(builtIn)) {
      builtIn = createToolpadComponentThatThrows(
        new Error(`Imported builtIn "${name}" is not a ToolpadComponent`)
      );
    }
    return [name, builtIn];
  })
);
var ReactQueryDevtoolsProduction = React8.lazy(
  () => (
    // eslint-disable-next-line import/extensions
    import("@tanstack/react-query-devtools/build/modern/production.js").then((d) => ({
      default: d.ReactQueryDevtools
    }))
  )
);
var EMPTY_ARRAY2 = [];
var EMPTY_OBJECT2 = {};
var INITIAL_FETCH = {
  call: async () => {
  },
  refetch: async () => {
  },
  fetch: async () => {
  },
  isLoading: false,
  isFetching: false,
  error: null,
  data: null,
  rows: []
};
function usePageNavigator() {
  const navigate = useNavigate();
  const canvasEvents = React8.useContext(CanvasEventsContext);
  const navigateToPage = React8.useCallback(
    (pageName, pageParameters) => {
      const urlParams = pageParameters && new URLSearchParams(pageParameters);
      if (canvasEvents) {
        canvasEvents.emit("pageNavigationRequest", { pageName });
      } else {
        navigate({
          pathname: `/pages/${pageName}`,
          ...urlParams ? {
            search: urlParams.toString()
          } : {}
        });
      }
    },
    [canvasEvents, navigate]
  );
  return navigateToPage;
}
function isEqual(a, b) {
  return a.value === b.value && !!a.error === !!b.error && a.loading === b.loading;
}
var AppRoot = styled2("div")({
  overflow: "auto",
  position: "relative",
  minHeight: "100vh",
  display: "flex",
  flexDirection: "column",
  paddingTop: SHOW_PREVIEW_HEADER ? PREVIEW_HEADER_HEIGHT : 0
});
var EditorOverlay = styled2("div")({
  position: "absolute",
  inset: "0 0 0 0",
  pointerEvents: "none",
  overflow: "hidden"
});
function createScope(id, bindings, { localValues, parentScope, meta = {} }) {
  const scopeValues = { ...parentScope?.values, ...localValues };
  const evaluatedBindings = evalJsBindings(browserJsRuntime, bindings, scopeValues);
  return {
    id,
    parentScope,
    bindings: mapValues2(evaluatedBindings, (binding) => binding.result || { value: void 0 }),
    values: buildGlobalScope(scopeValues, evaluatedBindings),
    meta
  };
}
function useApplicationVm(onUpdate) {
  const vm = { scopes: {}, bindingScopes: {} };
  let scheduledUpdate;
  const scheduleUpdate = () => {
    if (scheduledUpdate) {
      return;
    }
    scheduledUpdate = Promise.resolve().then(() => {
      onUpdate(vm);
      scheduledUpdate = void 0;
    });
  };
  return React8.useRef({
    registerScope(scope) {
      if (vm.scopes[scope.id]) {
        throw new Error(`Scope with id "${scope.id}" already registered`);
      }
      vm.scopes[scope.id] = scope;
      scheduleUpdate();
      return () => {
        delete vm.scopes[scope.id];
        scheduleUpdate();
      };
    },
    registerBindingScope(bindingId, scope) {
      if (vm.bindingScopes[bindingId]) {
        return () => {
        };
      }
      vm.bindingScopes[bindingId] = scope.id;
      scheduleUpdate();
      return () => {
        delete vm.bindingScopes[bindingId];
        scheduleUpdate();
      };
    }
  });
}
var ApplicationVmApiContext = React8.createContext(void 0);
var RuntimeScopeContext = React8.createContext(void 0);
var [useDomContext, DomContextProvider] = createProvidedContext("Dom");
var [useEvaluateScopeExpression, EvaluateScopeExpressionProvider] = createProvidedContext("EvaluateScopeExpression");
var SetBindingContext = React8.createContext(void 0);
function getComponentId(elm) {
  const componentId = getElementNodeComponentId(elm);
  return componentId;
}
function flattenNestedBindables(params, prefix = "") {
  if (!params) {
    return [];
  }
  if (Array.isArray(params)) {
    return params.flatMap((param, i) => {
      return flattenNestedBindables(param[1], `${prefix}[${i}][1]`);
    });
  }
  if (typeof params !== "object" || getBindingType(params) !== "const") {
    return [[prefix, params]];
  }
  return Object.entries(params).flatMap(
    ([key, param]) => flattenNestedBindables(param, `${prefix}.${key}`)
  );
}
function resolveBindables(bindings, bindingId, params) {
  const result = {};
  const resultKey = "value";
  const flattened = flattenNestedBindables(params);
  for (const [path] of flattened) {
    const resolvedBinding = bindings[`${bindingId}${path}`];
    if (resolvedBinding?.error) {
      return { error: resolvedBinding?.error };
    }
    if (resolvedBinding?.loading) {
      return { loading: true };
    }
    setObjectPath2(result, `${resultKey}${path}`, resolvedBinding?.value);
  }
  return { value: result[resultKey] || {} };
}
function parseBinding(bindable, { scopePath } = {}) {
  const bindingType = getBindingType(bindable);
  if (bindingType === "const") {
    return {
      scopePath,
      result: { value: bindable }
    };
  }
  if (bindingType === "env") {
    return {
      scopePath,
      result: { value: bindable }
    };
  }
  if (bindingType === "jsExpression") {
    return {
      scopePath,
      expression: bindable.$$jsExpression
    };
  }
  return {
    scopePath,
    result: { value: void 0 }
  };
}
function getScopeElements(dom, rootNode, components) {
  if (Array.isArray(rootNode)) {
    return [...rootNode, ...rootNode.flatMap((child) => getScopeElements(dom, child, components))];
  }
  const childNodes = getChildNodes(dom, rootNode);
  const result = [];
  for (const [prop, children] of Object.entries(childNodes)) {
    if (isElement(rootNode)) {
      const componentId = getComponentId(rootNode);
      const Component = components[componentId];
      const componentConfig = Component?.[TOOLPAD_COMPONENT];
      const { argTypes = {} } = componentConfig ?? {};
      if (argTypes[prop]?.type !== "template") {
        result.push(
          ...children,
          ...children.flatMap((child) => getScopeElements(dom, child, components))
        );
      }
    } else {
      result.push(
        ...children,
        ...children.flatMap((child) => getScopeElements(dom, child, components))
      );
    }
  }
  return result;
}
function getQueryConfigBindings({ enabled, refetchInterval }) {
  return { enabled, refetchInterval };
}
function isBindableProp(componentConfig, propName) {
  const isResizableHeightProp = propName === componentConfig.resizableHeightProp;
  const argType = componentConfig.argTypes?.[propName];
  return !isResizableHeightProp && argType?.control?.bindable !== false && argType?.type !== "template" && argType?.type !== "event";
}
function parseBindings(dom, rootNode, components, location) {
  const scopeElements = getScopeElements(dom, rootNode, components);
  const parsedBindingsMap = /* @__PURE__ */ new Map();
  const controlled = /* @__PURE__ */ new Set();
  const scopeMeta = {};
  for (const elm of scopeElements) {
    if (isElement(elm)) {
      const componentId = getComponentId(elm);
      const Component = components[componentId];
      const componentConfig = Component?.[TOOLPAD_COMPONENT] ?? {};
      const { argTypes = {} } = componentConfig;
      const propsMeta = {};
      for (const [propName, argType] of Object.entries(argTypes)) {
        invariant3(argType, `Missing argType for prop "${propName}"`);
        const initializerId = argType.defaultValueProp ? `${elm.id}.props.${argType.defaultValueProp}` : void 0;
        const propValue = elm.props?.[propName];
        const binding = propValue ?? getArgTypeDefaultValue(argType);
        const bindingId = `${elm.id}.props.${propName}`;
        let scopePath;
        if (componentId !== PAGE_ROW_COMPONENT_ID && isBindableProp(componentConfig, propName)) {
          scopePath = `${elm.name}.${propName}`;
        }
        propsMeta[propName] = {
          tsType: argType?.tsType
        };
        if (argType) {
          if (argType.onChangeProp) {
            controlled.add(bindingId);
            parsedBindingsMap.set(bindingId, {
              scopePath,
              initializer: initializerId
            });
          } else {
            parsedBindingsMap.set(bindingId, parseBinding(binding, { scopePath }));
          }
        }
        const parseNestedBindings = (value, parentBindingId) => {
          if (value && typeof value === "object") {
            for (const [nestedPropName, nestedProp] of Object.entries(value)) {
              const nestedBindingId = `${parentBindingId}${Array.isArray(value) ? `[${nestedPropName}]` : `.${nestedPropName}`}`;
              if (nestedProp && getBindingType(nestedProp) !== "const") {
                parsedBindingsMap.set(nestedBindingId, parseBinding(nestedProp));
              } else {
                parseNestedBindings(
                  value[nestedPropName],
                  nestedBindingId
                );
              }
            }
          }
        };
        const propBindingValue = propValue && getBindingValue(propValue);
        parseNestedBindings(propBindingValue, bindingId);
      }
      if (componentId !== PAGE_ROW_COMPONENT_ID) {
        scopeMeta[elm.name] = {
          kind: "element",
          componentId,
          props: propsMeta
        };
      }
      if (!isPageLayoutComponent(elm)) {
        for (const [propName, argType] of Object.entries(layoutBoxArgTypes)) {
          const binding = elm.layout?.[propName] ?? (argType ? getArgTypeDefaultValue(argType) : void 0);
          const bindingId = `${elm.id}.layout.${propName}`;
          parsedBindingsMap.set(bindingId, parseBinding(binding, {}));
        }
      }
    }
    if (isQuery(elm)) {
      let kind = "query";
      if (elm.attributes.mode === "mutation") {
        kind = "action";
      }
      scopeMeta[elm.name] = {
        kind
      };
      if (elm.params) {
        const nestedBindablePaths2 = flattenNestedBindables(Object.fromEntries(elm.params ?? []));
        for (const [nestedPath, paramValue] of nestedBindablePaths2) {
          const bindingId = `${elm.id}.params${nestedPath}`;
          const scopePath = `${elm.name}.params${nestedPath}`;
          const bindable = paramValue;
          parsedBindingsMap.set(bindingId, parseBinding(bindable, { scopePath }));
        }
      }
      for (const [key, value] of Object.entries(INITIAL_FETCH)) {
        const bindingId = `${elm.id}.${key}`;
        const scopePath = `${elm.name}.${key}`;
        controlled.add(bindingId);
        parsedBindingsMap.set(bindingId, {
          scopePath,
          result: { value, loading: true }
        });
      }
      const configBindings = getQueryConfigBindings(elm.attributes);
      const nestedBindablePaths = flattenNestedBindables(configBindings);
      for (const [nestedPath, paramValue] of nestedBindablePaths) {
        const bindingId = `${elm.id}.config${nestedPath}`;
        const scopePath = `${elm.name}.config${nestedPath}`;
        const bindable = paramValue;
        parsedBindingsMap.set(bindingId, parseBinding(bindable, { scopePath }));
      }
    }
    if (isMutation(elm)) {
      if (elm.params) {
        for (const [paramName, bindable] of Object.entries(elm.params)) {
          const bindingId = `${elm.id}.params.${paramName}`;
          const scopePath = `${elm.name}.params.${paramName}`;
          const bindingType = getBindingType(bindable);
          if (bindingType === "const") {
            parsedBindingsMap.set(bindingId, {
              scopePath,
              result: { value: bindable }
            });
          } else if (bindingType === "jsExpression") {
            parsedBindingsMap.set(bindingId, {
              scopePath,
              expression: bindable.$$jsExpression
            });
          }
        }
      }
      for (const [key, value] of Object.entries(INITIAL_FETCH)) {
        const bindingId = `${elm.id}.${key}`;
        const scopePath = `${elm.name}.${key}`;
        controlled.add(bindingId);
        parsedBindingsMap.set(bindingId, {
          scopePath,
          result: { value, loading: true }
        });
      }
    }
  }
  if (!Array.isArray(rootNode) && isPage(rootNode)) {
    if (location && !Array.isArray(rootNode) && isPage(rootNode)) {
      const urlParams = new URLSearchParams(location.search);
      const pageParameters = rootNode.attributes.parameters || [];
      for (const [paramName, paramDefault] of pageParameters) {
        const bindingId = `${rootNode.id}.parameters.${paramName}`;
        const scopePath = `page.parameters.${paramName}`;
        parsedBindingsMap.set(bindingId, {
          scopePath,
          result: { value: urlParams.get(paramName) || paramDefault }
        });
      }
    }
  }
  const parsedBindings = Object.fromEntries(parsedBindingsMap);
  return { parsedBindings, controlled, scopeMeta };
}
function useElmToolpadComponent(elm) {
  const componentId = getElementNodeComponentId(elm);
  return useComponent(componentId);
}
function RenderedNode({ nodeId }) {
  const dom = useDomContext();
  const node = getNode(dom, nodeId, "element");
  const Component = useElmToolpadComponent(node);
  const childNodeGroups = getChildNodes(dom, node);
  return /* @__PURE__ */ React8.createElement(RenderedNodeContent, { node, childNodeGroups, Component });
}
function RuntimeScoped({
  id,
  parseBindingsResult,
  localScope,
  onUpdate,
  children
}) {
  const parentScope = React8.useContext(RuntimeScopeContext);
  const dom = useDomContext();
  const { parsedBindings, controlled, scopeMeta } = parseBindingsResult;
  const [scopeBindings, setScopeBindings] = React8.useState(parsedBindings);
  const prevDom = React8.useRef(dom);
  React8.useEffect(() => {
    if (dom === prevDom.current) {
      return;
    }
    prevDom.current = dom;
    setScopeBindings((existingBindings) => {
      const updated = {};
      for (const [key, binding] of Object.entries(parsedBindings)) {
        updated[key] = controlled.has(key) ? existingBindings[key] || binding : binding;
      }
      return updated;
    });
  }, [parsedBindings, controlled, dom]);
  const { setBindingByScopePath: setParentBindingByScopePath } = React8.useContext(SetBindingContext) ?? {};
  const setBinding = React8.useCallback(
    (bindingId, result) => {
      setScopeBindings((existingBindings) => {
        const { expression, initializer, ...parsedBinding } = parsedBindings[bindingId];
        const existingBinding = existingBindings[bindingId];
        if (existingBinding?.result && isEqual(existingBinding.result, result)) {
          return existingBindings;
        }
        return {
          ...existingBindings,
          ...{
            [bindingId]: { ...parsedBinding, result }
          }
        };
      });
    },
    [parsedBindings]
  );
  const bindingsByScopePath = React8.useMemo(
    () => new Map(
      Object.entries(scopeBindings).map(
        ([bindingId, binding]) => [binding.scopePath, bindingId]
      )
    ),
    [scopeBindings]
  );
  const setBindingByScopePath = React8.useCallback(
    (scopePath, result) => {
      const bindingToUpdateId = bindingsByScopePath.get(scopePath);
      if (bindingToUpdateId) {
        setBinding(bindingToUpdateId, result);
      } else if (setParentBindingByScopePath) {
        setParentBindingByScopePath(scopePath, result);
      } else {
        throw new Error(`No binding found for scope path "${scopePath}"`);
      }
    },
    [bindingsByScopePath, setBinding, setParentBindingByScopePath]
  );
  const setControlledBinding = React8.useCallback(
    (bindingId, result) => {
      if (!controlled.has(bindingId)) {
        throw new Error(`Not a controlled binding "${bindingId}"`);
      }
      setBinding(bindingId, result);
    },
    [controlled, setBinding]
  );
  const childScope = React8.useMemo(
    () => createScope(id, scopeBindings, {
      localValues: localScope,
      parentScope,
      meta: scopeMeta
    }),
    [id, localScope, parentScope, scopeBindings, scopeMeta]
  );
  const vmRef = React8.useContext(ApplicationVmApiContext);
  React8.useEffect(() => {
    if (!vmRef) {
      return () => {
      };
    }
    return vmRef.current.registerScope(childScope);
  }, [vmRef, childScope]);
  const evaluateScopeExpression = React8.useCallback(
    async (expression) => {
      const updates = {};
      const proxify = (obj, scopePathSegments) => {
        return new Proxy(obj, {
          get(target, prop, receiver) {
            if (typeof prop === "symbol") {
              return Reflect.get(target, prop, receiver);
            }
            const result2 = target[prop];
            if (result2 && typeof result2 === "object") {
              return proxify(result2, [...scopePathSegments, prop]);
            }
            return Reflect.get(target, prop, receiver);
          },
          set(target, prop, newValue, receiver) {
            if (typeof prop === "symbol") {
              return Reflect.set(target, prop, newValue, receiver);
            }
            const scopePath = [...scopePathSegments, prop].join(".");
            updates[scopePath] = newValue;
            return Reflect.set(target, prop, newValue, receiver);
          }
        });
      };
      const scopeValues = childScope.values;
      const result = browserJsRuntime.evaluateExpression(expression, proxify(scopeValues, []));
      await result.value;
      for (const [scopePath, newValue] of Object.entries(updates)) {
        setBindingByScopePath(scopePath, { value: newValue });
      }
      return result;
    },
    [childScope.values, setBindingByScopePath]
  );
  React8.useEffect(() => {
    onUpdate?.({
      scopeMeta,
      scope: childScope
    });
  }, [scopeMeta, childScope, onUpdate]);
  const setBindingContext = React8.useMemo(
    () => ({
      setBinding,
      setControlledBinding,
      setBindingByScopePath
    }),
    [setBinding, setControlledBinding, setBindingByScopePath]
  );
  return /* @__PURE__ */ React8.createElement(RuntimeScopeContext.Provider, { value: childScope }, /* @__PURE__ */ React8.createElement(SetBindingContext.Provider, { value: setBindingContext }, /* @__PURE__ */ React8.createElement(EvaluateScopeExpressionProvider, { value: evaluateScopeExpression }, children)));
}
function TemplateScoped({ id, node, localScope, propName, children }) {
  const dom = useDomContext();
  const components = useComponents();
  const location = useLocation();
  const parseBindingsResult = React8.useMemo(() => {
    const { [propName]: templateChildren = [] } = getChildNodes(dom, node);
    return parseBindings(dom, templateChildren, components, location);
  }, [components, dom, node, propName, location]);
  return /* @__PURE__ */ React8.createElement(RuntimeScoped, { id, parseBindingsResult, localScope }, children);
}
function NodeError({ error }) {
  return /* @__PURE__ */ React8.createElement(Tooltip2, { title: error.message }, /* @__PURE__ */ React8.createElement(
    "span",
    {
      style: {
        display: "inline-flex",
        flexDirection: "row",
        alignItems: "center",
        padding: 8,
        background: "red",
        color: "white"
      }
    },
    /* @__PURE__ */ React8.createElement(ErrorIcon, { color: "inherit", style: { marginRight: 8 } }),
    " Error"
  ));
}
function RenderedNodeContent({ node, childNodeGroups, Component }) {
  const { setControlledBinding } = React8.useContext(SetBindingContext) ?? {};
  invariant3(setControlledBinding, "Node must be rendered in a RuntimeScoped context");
  const nodeId = node.id;
  const componentConfig = Component[TOOLPAD_COMPONENT];
  const {
    argTypes = {},
    errorProp,
    loadingProp,
    loadingPropSource,
    errorPropSource
  } = componentConfig;
  const isLayoutNode = isPage(node) || isElement(node) && isPageLayoutComponent(node);
  const scope = useAssertedContext(RuntimeScopeContext);
  const liveBindings = scope.bindings;
  const boundProps = React8.useMemo(() => {
    const loadingPropSourceSet = loadingPropSource ? new Set(loadingPropSource) : null;
    const errorPropSourceSet = errorPropSource ? new Set(errorPropSource) : null;
    const hookResult = {};
    let error;
    let loading = false;
    for (const [propName, argType] of Object.entries(argTypes)) {
      const bindingId = `${nodeId}.props.${propName}`;
      const binding = liveBindings[bindingId];
      if (binding) {
        hookResult[propName] = binding.value;
        if (binding.loading && (!loadingPropSourceSet || loadingPropSourceSet.has(propName))) {
          loading = true;
        } else if (!error && binding.error && (!errorPropSourceSet || errorPropSourceSet.has(propName))) {
          error = binding.error;
        }
      }
      if (typeof hookResult[propName] === "undefined" && argType) {
        hookResult[propName] = getArgTypeDefaultValue(argType);
      }
    }
    if (error) {
      if (errorProp) {
        hookResult[errorProp] = error;
      } else {
        console.error(errorFrom(error));
      }
    }
    if (loadingProp && loading) {
      hookResult[loadingProp] = true;
    }
    return hookResult;
  }, [argTypes, errorProp, errorPropSource, liveBindings, loadingProp, loadingPropSource, nodeId]);
  const boundLayoutProps = React8.useMemo(() => {
    const hookResult = {};
    for (const [propName, argType] of isLayoutNode ? [] : Object.entries(layoutBoxArgTypes)) {
      const bindingId = `${nodeId}.layout.${propName}`;
      const binding = liveBindings[bindingId];
      if (binding) {
        hookResult[propName] = binding.value;
      }
      if (typeof hookResult[propName] === "undefined" && argType) {
        hookResult[propName] = getArgTypeDefaultValue(argType);
      }
    }
    return hookResult;
  }, [isLayoutNode, liveBindings, nodeId]);
  const onChangeHandlers = React8.useMemo(
    () => mapProperties(argTypes, ([key, argType]) => {
      if (!argType || !argType.onChangeProp) {
        return null;
      }
      const handler = (param) => {
        const bindingId = `${nodeId}.props.${key}`;
        const value = argType.onChangeHandler ? argType.onChangeHandler(param) : param;
        setControlledBinding(bindingId, { value });
      };
      return [argType.onChangeProp, handler];
    }),
    [argTypes, nodeId, setControlledBinding]
  );
  const navigateToPage = usePageNavigator();
  const evaluateScopeExpression = useEvaluateScopeExpression();
  const eventHandlers = React8.useMemo(() => {
    return mapProperties(argTypes, ([key, argType]) => {
      if (!argType || argType.type !== "event" || !isElement(node)) {
        return null;
      }
      const action = node.props?.[key];
      if (action?.$$navigationAction) {
        const handler = async () => {
          const { page, parameters = {} } = action.$$navigationAction;
          if (page) {
            const parsedParameterEntries = await Promise.all(
              Object.keys(parameters).map(async (parameterName) => {
                const parameterValue = parameters[parameterName];
                if (parameterValue?.$$jsExpression) {
                  const result = await evaluateScopeExpression(parameterValue.$$jsExpression);
                  return [parameterName, result.value];
                }
                return [parameterName, parameterValue];
              })
            );
            const parsedParameters = Object.fromEntries(parsedParameterEntries);
            navigateToPage(page, parsedParameters);
          }
        };
        return [key, handler];
      }
      if (action?.$$jsExpressionAction) {
        const handler = () => {
          const code = action.$$jsExpressionAction;
          const exprToEvaluate = `(async () => {${code}})()`;
          evaluateScopeExpression(exprToEvaluate);
        };
        return [key, handler];
      }
      return null;
    });
  }, [argTypes, node, navigateToPage, evaluateScopeExpression]);
  const reactChildren = React8.useMemo(() => {
    const result = {};
    for (const [prop, childNodes] of Object.entries(childNodeGroups)) {
      result[prop] = childNodes.map((child) => /* @__PURE__ */ React8.createElement(RenderedNode, { key: child.id, nodeId: child.id }));
    }
    return result;
  }, [childNodeGroups]);
  const layoutElementProps = React8.useMemo(() => {
    if (isElement(node) && isPageRow(node)) {
      return {
        layoutColumnSizes: childNodeGroups.children.map((child) => child.layout?.columnSize)
      };
    }
    return {};
  }, [childNodeGroups.children, node]);
  const props = React8.useMemo(() => {
    return {
      ...boundProps,
      ...onChangeHandlers,
      ...eventHandlers,
      ...layoutElementProps,
      ...reactChildren
    };
  }, [boundProps, eventHandlers, layoutElementProps, onChangeHandlers, reactChildren]);
  const previousProps = React8.useRef(props);
  const [hasSetInitialBindings, setHasSetInitialBindings] = React8.useState(false);
  React8.useEffect(() => {
    Object.entries(argTypes).forEach(([key, argType]) => {
      if (!argType?.defaultValueProp) {
        return;
      }
      if (hasSetInitialBindings && previousProps.current[argType.defaultValueProp] === props[argType.defaultValueProp]) {
        return;
      }
      const bindingIdToUpdate = `${nodeId}.props.${key}`;
      setControlledBinding(bindingIdToUpdate, { value: props[argType.defaultValueProp] });
    });
    previousProps.current = props;
    setHasSetInitialBindings(true);
  }, [props, argTypes, nodeId, setControlledBinding, hasSetInitialBindings]);
  const wrappedProps = React8.useMemo(() => {
    const hookResult = { ...props };
    for (const [propName, argType] of Object.entries(argTypes)) {
      const isElement2 = argType?.type === "element";
      const isTemplate = argType?.type === "template";
      if (isElement2 || isTemplate) {
        const value = hookResult[propName];
        let wrappedValue = value;
        if (argType.control?.type === "slots" || argType.control?.type === "layoutSlot") {
          wrappedValue = /* @__PURE__ */ React8.createElement(Slots, { prop: propName, hasLayout: argType.control?.type === "layoutSlot" }, value);
        } else if (argType.control?.type === "slot") {
          wrappedValue = /* @__PURE__ */ React8.createElement(Placeholder, { prop: propName }, value);
        }
        if (isTemplate) {
          assertIsElement(node);
          hookResult[propName] = (key, localScope) => {
            return /* @__PURE__ */ React8.createElement(
              TemplateScoped,
              {
                id: `${node.id}.props.${propName}.${key}`,
                localScope,
                node,
                propName
              },
              wrappedValue
            );
          };
        } else {
          hookResult[propName] = wrappedValue;
        }
      }
    }
    return hookResult;
  }, [argTypes, node, props]);
  const vmRef = React8.useContext(ApplicationVmApiContext);
  React8.useEffect(() => {
    if (!vmRef) {
      return () => {
      };
    }
    const unsubscribers = [];
    for (const propName of Object.keys(argTypes)) {
      const unsubscribe = vmRef.current.registerBindingScope(`${nodeId}.props.${propName}`, scope);
      unsubscribers.push(unsubscribe);
    }
    return () => {
      unsubscribers.forEach((unsubscribe) => unsubscribe());
    };
  }, [nodeId, argTypes, vmRef, scope]);
  return /* @__PURE__ */ React8.createElement(
    NodeRuntimeWrapper,
    {
      nodeId,
      nodeName: node.name,
      componentConfig: Component[TOOLPAD_COMPONENT],
      NodeError
    },
    isLayoutNode ? /* @__PURE__ */ React8.createElement(Component, { ...wrappedProps }) : /* @__PURE__ */ React8.createElement(
      Box4,
      {
        sx: {
          display: "flex",
          alignItems: boundLayoutProps.verticalAlign,
          justifyContent: boundLayoutProps.horizontalAlign
        }
      },
      /* @__PURE__ */ React8.createElement(Component, { ...wrappedProps })
    )
  );
}
function PageRoot({ children }) {
  return /* @__PURE__ */ React8.createElement(Container, null, /* @__PURE__ */ React8.createElement(
    Stack,
    {
      "data-testid": "page-root",
      direction: "column",
      sx: {
        my: 2,
        gap: 1
      }
    },
    children
  ));
}
var PageRootComponent = createComponent(PageRoot, {
  argTypes: {
    children: {
      type: "element",
      control: { type: "slots" }
    }
  }
});
function QueryNode({ page, node }) {
  const { setControlledBinding } = React8.useContext(SetBindingContext) ?? {};
  invariant3(setControlledBinding, "QueryNode must be rendered in a RuntimeScoped context");
  const { bindings } = useAssertedContext(RuntimeScopeContext);
  const params = resolveBindables(
    bindings,
    `${node.id}.params`,
    Object.fromEntries(node.params ?? [])
  );
  const configBindings = getQueryConfigBindings(node.attributes);
  const options = resolveBindables(bindings, `${node.id}.config`, configBindings);
  const inputError = params.error || options.error;
  const inputIsLoading = params.loading || options.loading;
  const queryResult = useDataQuery(page, node, params.value, {
    ...options.value,
    enabled: !inputIsLoading && !inputError
  });
  React8.useEffect(() => {
    const { isLoading: queryIsLoading, error: queryError, data, rows, ...result } = queryResult;
    const error = queryError || inputError;
    const isLoading = queryIsLoading || inputIsLoading;
    for (const [key, value] of Object.entries(result)) {
      const bindingId = `${node.id}.${key}`;
      setControlledBinding(bindingId, { value });
    }
    setControlledBinding(`${node.id}.isLoading`, { value: isLoading });
    setControlledBinding(`${node.id}.error`, {
      value: error ? String(error.message || error) : void 0
    });
    const deferredStatus = { loading: isLoading, error };
    setControlledBinding(`${node.id}.data`, { ...deferredStatus, value: data });
    setControlledBinding(`${node.id}.rows`, { ...deferredStatus, value: rows });
  }, [node.name, node.id, queryResult, setControlledBinding, inputError, inputIsLoading]);
  return null;
}
function MutationNode({ node, page }) {
  const { setControlledBinding } = React8.useContext(SetBindingContext) ?? {};
  invariant3(setControlledBinding, "MutationNode must be rendered in a RuntimeScoped context");
  const { bindings } = useAssertedContext(RuntimeScopeContext);
  const { value: params } = resolveBindables(
    bindings,
    `${node.id}.params`,
    Object.fromEntries(node.params ?? [])
  );
  const {
    isPending,
    data: responseData = EMPTY_OBJECT2,
    error: fetchError,
    mutateAsync
  } = useMutation2({
    mutationKey: [node.name, params],
    mutationFn: async (overrides = {}) => {
      return api_default.methods.execQuery(page.name, node.name, { ...params, ...overrides });
    }
  });
  const { data, error: apiError } = responseData || EMPTY_OBJECT2;
  const error = apiError || fetchError;
  const mutationResult = React8.useMemo(() => {
    const call = async (overrides = {}) => {
      await mutateAsync(overrides);
    };
    return {
      isLoading: isPending,
      isFetching: isPending,
      error,
      data,
      rows: Array.isArray(data) ? data : EMPTY_ARRAY2,
      call,
      fetch: call,
      refetch: () => {
        throw new Error(`refetch is not supported in manual queries`);
      }
    };
  }, [isPending, error, data, mutateAsync]);
  React8.useEffect(() => {
    for (const [key, value] of Object.entries(mutationResult)) {
      const bindingId = `${node.id}.${key}`;
      setControlledBinding(bindingId, { value });
    }
  }, [node.id, mutationResult, setControlledBinding]);
  return null;
}
function FetchNode({ node, page }) {
  const mode = node.attributes.mode || "query";
  switch (mode) {
    case "query":
      return /* @__PURE__ */ React8.createElement(QueryNode, { node, page });
    case "mutation":
      return /* @__PURE__ */ React8.createElement(MutationNode, { node, page });
    default:
      throw new Error(`Unrecognized fetch mode "${mode}"`);
  }
}
function RenderedProCodePage({ page }) {
  const pageComponents = pageComponentsStore.useValue();
  const PageComponent = pageComponents[page.name] ?? PageNotFound;
  return /* @__PURE__ */ React8.createElement(PageComponent, null);
}
function RenderedLowCodePage({ page }) {
  const dom = useDomContext();
  const { children = [], queries = [] } = getChildNodes(dom, page);
  usePageTitle(getPageTitle(page));
  const location = useLocation();
  const components = useComponents();
  const parseBindingsResult = React8.useMemo(
    () => parseBindings(dom, page, components, location),
    [components, dom, location, page]
  );
  const canvasEvents = React8.useContext(CanvasEventsContext);
  const onUpdate = useEventCallback(({ scope, scopeMeta }) => {
    if (canvasEvents) {
      canvasEvents.emit("pageStateUpdated", {
        pageState: scope.values,
        globalScopeMeta: scopeMeta
      });
      canvasEvents.emit("pageBindingsUpdated", { bindings: scope.bindings });
    }
  });
  const applicationVm = useApplicationVm((vm) => {
    if (canvasEvents) {
      canvasEvents.emit("vmUpdated", { vm });
    }
  });
  return /* @__PURE__ */ React8.createElement(ApplicationVmApiContext.Provider, { value: applicationVm }, /* @__PURE__ */ React8.createElement(RuntimeScoped, { id: "global", parseBindingsResult, onUpdate }, /* @__PURE__ */ React8.createElement(
    RenderedNodeContent,
    {
      node: page,
      childNodeGroups: { children },
      Component: PageRootComponent
    }
  ), queries.map((node) => /* @__PURE__ */ React8.createElement(FetchNode, { key: node.id, page, node }))));
}
function RenderedPage({ page }) {
  usePageTitle(getPageTitle(page));
  if (page.attributes.codeFile) {
    return /* @__PURE__ */ React8.createElement(RenderedProCodePage, { page });
  }
  return /* @__PURE__ */ React8.createElement(RenderedLowCodePage, { page });
}
function PageNotFound() {
  return /* @__PURE__ */ React8.createElement(
    Container,
    {
      sx: {
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        flexDirection: "column"
      }
    },
    /* @__PURE__ */ React8.createElement(Typography2, { variant: "h1" }, "Not found"),
    /* @__PURE__ */ React8.createElement(Typography2, null, "The page doesn't exist in this application.")
  );
}
function useAppHasAuthentication() {
  return false;
}
function RenderedPages({ pages }) {
  const defaultPage = pages[0];
  const defaultPageNavigation = /* @__PURE__ */ React8.createElement(Navigate, { to: `/pages/${defaultPage.name}`, replace: true });
  const { search } = useLocation();
  const appAuthenticationEnabled = useAppHasAuthentication();
  return /* @__PURE__ */ React8.createElement(Routes, null, pages.map((page) => {
    let pageContent = /* @__PURE__ */ React8.createElement(
      RenderedPage,
      {
        page,
        key: page.name
      }
    );
    if (!IS_RENDERED_IN_CANVAS && appAuthenticationEnabled && page.attributes.authorization) {
      pageContent = /* @__PURE__ */ React8.createElement(RequireAuthorization, { allowedRole: page.attributes.authorization.allowedRoles }, pageContent);
    }
    return /* @__PURE__ */ React8.createElement(Route, { key: page.name, path: `/pages/${page.name}`, element: pageContent });
  }), pages.flatMap(
    (page) => page.attributes.alias?.map((alias) => /* @__PURE__ */ React8.createElement(
      Route,
      {
        key: `${page.name}-${alias}`,
        path: `/pages/${alias}`,
        element: /* @__PURE__ */ React8.createElement(Navigate, { to: `/pages/${page.name}${search}`, replace: true })
      }
    ))
  ), /* @__PURE__ */ React8.createElement(Route, { path: "/pages", element: defaultPageNavigation }), /* @__PURE__ */ React8.createElement(Route, { path: "/", element: defaultPageNavigation }), /* @__PURE__ */ React8.createElement(Route, { path: "*", element: /* @__PURE__ */ React8.createElement(PageNotFound, null) }));
}
var FullPageCentered = styled2("div")({
  width: "100%",
  height: "100%",
  display: "flex",
  alignItems: "center",
  justifyContent: "center"
});
function AppLoading() {
  return /* @__PURE__ */ React8.createElement(LinearProgress, null);
}
function AppError({ error }) {
  return /* @__PURE__ */ React8.createElement(FullPageCentered, null, /* @__PURE__ */ React8.createElement(Alert2, { severity: "error" }, /* @__PURE__ */ React8.createElement(AlertTitle, null, "Something went wrong"), /* @__PURE__ */ React8.createElement(Pre, null, error.message), /* @__PURE__ */ React8.createElement(Pre, null, error.stack)));
}
function ToolpadAppLayout({ dom }) {
  const root = getApp(dom);
  const { pages = [] } = getChildNodes(dom, root);
  const pageMatch = useMatch2("/pages/:slug");
  const activePage = pageMatch?.params.slug;
  const navEntries = React8.useMemo(
    () => pages.map((page) => ({
      slug: page.name,
      displayName: getPageDisplayName(page),
      hasShell: page?.attributes.display !== "standalone"
    })),
    [pages]
  );
  return /* @__PURE__ */ React8.createElement(
    AppLayout,
    {
      activePage,
      pages: navEntries,
      hasShell: !IS_RENDERED_IN_CANVAS,
      clipped: SHOW_PREVIEW_HEADER
    },
    /* @__PURE__ */ React8.createElement(RenderedPages, { pages })
  );
}
function ToolpadApp({ rootRef, basename, state }) {
  const { dom } = state;
  const extraComponents = componentsStore.useValue();
  const components = React8.useMemo(
    () => ({ ...internalComponents, ...extraComponents }),
    [extraComponents]
  );
  const [resetNodeErrorsKey, setResetNodeErrorsKey] = React8.useState(0);
  React8.useEffect(() => setResetNodeErrorsKey((key) => key + 1), [dom]);
  const { value: showDevtools, toggle: toggleDevtools } = useBoolean(false);
  React8.useEffect(() => {
    window.toggleDevtools = () => toggleDevtools();
  }, [toggleDevtools]);
  const currentUser = null;
  return /* @__PURE__ */ React8.createElement(BrowserRouter, { basename }, /* @__PURE__ */ React8.createElement(UseDataProviderContext.Provider, { value: useDataProvider }, /* @__PURE__ */ React8.createElement(AppThemeProvider, { dom }, /* @__PURE__ */ React8.createElement(CssBaseline, { enableColorScheme: true }), SHOW_PREVIEW_HEADER ? /* @__PURE__ */ React8.createElement(PreviewHeader, { basename }) : null, /* @__PURE__ */ React8.createElement(AppRoot, { ref: rootRef }, /* @__PURE__ */ React8.createElement(ComponentsContextProvider, { value: components }, /* @__PURE__ */ React8.createElement(DomContextProvider, { value: dom }, /* @__PURE__ */ React8.createElement(ErrorBoundary, { FallbackComponent: AppError }, /* @__PURE__ */ React8.createElement(ResetNodeErrorsKeyProvider, { value: resetNodeErrorsKey }, /* @__PURE__ */ React8.createElement(React8.Suspense, { fallback: /* @__PURE__ */ React8.createElement(AppLoading, null) }, /* @__PURE__ */ React8.createElement(QueryClientProvider, { client: queryClient }, /* @__PURE__ */ React8.createElement(AuthenticationProvider, { user: currentUser }, /* @__PURE__ */ React8.createElement(ToolpadAppLayout, { dom })), showDevtools ? /* @__PURE__ */ React8.createElement(ReactQueryDevtoolsProduction, { initialIsOpen: false }) : null)))))), /* @__PURE__ */ React8.createElement(EditorOverlay, { id: HTML_ID_EDITOR_OVERLAY })))));
}

export {
  CanvasHooksContext,
  queryClient,
  api_default,
  AppLayout,
  ComponentsContextProvider,
  IS_RENDERED_IN_CANVAS,
  componentsStore,
  pageComponentsStore,
  DomContextProvider,
  RenderedPage,
  ToolpadApp
};
//# sourceMappingURL=chunk-UO6UIBP6.mjs.map