;
+ wrap?: (child: React.ReactElement) => React.ReactElement;
+}
+
+/**
+ * A hook implementing the body of a middleware. Receives the incoming props
+ * (without `Component`) and returns an optional set of props to inject plus an
+ * optional wrapper. The same body hook can back both a panel and a widget
+ * middleware (see {@link createPanelMiddleware} / {@link createWidgetMiddleware}),
+ * so a plugin expresses its behavior once.
+ *
+ * Type the `props` parameter as wide as the middleware needs (e.g. intersect
+ * with `IrisGridTableOptionsWidgetProps`) — the factory passes the runtime
+ * props through unchanged.
+ */
+export type MiddlewareBody = (props: P) => MiddlewareBodyResult;
+
+/**
+ * Builds a panel-path middleware component from a single body hook, owning the
+ * `React.forwardRef` ceremony and ref forwarding that golden-layout state
+ * persistence depends on.
+ *
+ * The returned component is ref-capable and always forwards its `ref` to the
+ * wrapped `Component`, so a middleware author can never accidentally drop it
+ * (which would silently break `componentState` persistence — sorts, filters,
+ * column moves — on reload). The body hook only decides what to inject and how
+ * to wrap; it never sees the ref.
+ */
+export function createPanelMiddleware<
+ T = unknown,
+ P extends WidgetPanelProps = WidgetPanelProps,
+>(
+ useBody: MiddlewareBody,
+ displayName = 'PanelMiddleware'
+): React.ForwardRefExoticComponent<
+ WidgetMiddlewarePanelProps & React.RefAttributes
+> {
+ const PanelMiddleware = React.forwardRef<
+ unknown,
+ WidgetMiddlewarePanelProps
+ >(({ Component, ...rest }, ref) => {
+ const { inject, wrap } = useBody(rest as unknown as P);
+ const Next = Component as unknown as React.ForwardRefExoticComponent<
+ Record & React.RefAttributes
+ >;
+ const child = (
+ // eslint-disable-next-line react/jsx-props-no-spreading
+
+ );
+ return wrap != null ? wrap(child) : child;
+ });
+ PanelMiddleware.displayName = displayName;
+ return PanelMiddleware;
+}
+
+/**
+ * Builds a widget-path middleware component from a single body hook. The widget
+ * path takes no ref, so this is a plain function component; otherwise it mirrors
+ * {@link createPanelMiddleware} (same `inject` / `wrap` contract), letting a
+ * plugin reuse one body hook for both paths.
+ */
+export function createWidgetMiddleware<
+ T = unknown,
+ P extends WidgetComponentProps = WidgetComponentProps,
+>(
+ useBody: MiddlewareBody,
+ displayName = 'WidgetMiddleware'
+): React.ComponentType> {
+ function WidgetMiddleware({
+ Component,
+ ...rest
+ }: WidgetMiddlewareComponentProps): React.ReactElement {
+ const { inject, wrap } = useBody(rest as unknown as P);
+ const Next = Component as unknown as React.ComponentType<
+ Record
+ >;
+ const child = (
+ // eslint-disable-next-line react/jsx-props-no-spreading
+
);
+ return wrap != null ? wrap(child) : child;
+ }
+ WidgetMiddleware.displayName = displayName;
+ return WidgetMiddleware;
}
export type PluginManifestPluginInfo = {