/** @license MIT | @cube-dev/ui-kit v0.147.0 | Cube Dev Team */
import { mergeProps as mergeProps$1 } from "../../../utils/react/mergeProps.js";
import { useEvent } from "../../../_internal/hooks/use-event.js";
import { BoardHostContext } from "./board-context.js";
import { calcGridColWidth, calcGridItemPosition } from "./grid-core/calculate.js";
import { tasty } from "@tenphi/tasty";
import { useMemo, useRef, useState } from "react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
import { useFocusRing, useFocusWithin, useHover, useMove } from "react-aria";
import { createPortal } from "react-dom";

//#region src/components/layout/Board/WidgetHost.tsx
/**
* Slack (px) absorbed when converting an auto-height widget's content height to
* whole rows, so sub-pixel measurement/rounding noise never bumps an extra row.
*/
const AUTO_HEIGHT_TOLERANCE = 4;
const WidgetElement = tasty({
	qa: "BoardWidget",
	styles: {
		position: "absolute",
		top: 0,
		left: 0,
		fill: "#surface-2",
		radius: "1cr",
		border: {
			"": false,
			card: true
		},
		shadow: {
			"": false,
			"hovered & !card & (draggable | resizing)": "0 0 0 1bw #border",
			"drag | resizing": "$dialog-shadow"
		},
		outline: {
			"": "1bw #primary-text.0",
			"focus-visible": "1bw #primary-text"
		},
		outlineOffset: "1bw",
		zIndex: {
			"": 1,
			"drag | resizing": 10
		},
		opacity: {
			"": 1,
			floating: .8
		},
		transition: {
			"": "theme, shadow, opacity",
			settled: "theme, shadow, opacity, inset, width, height",
			"drag | floating | resizing": "theme, shadow, opacity"
		},
		boxSizing: "border-box",
		userSelect: {
			"": "auto",
			"drag | resizing": "none"
		},
		cursor: {
			"": "auto",
			draggable: "grab",
			drag: "grabbing"
		},
		touchAction: "none",
		overflow: "hidden"
	}
});
const HandleElement = tasty({
	qa: "BoardResizeHandle",
	styles: {
		position: "absolute",
		zIndex: 20,
		fill: "#clear",
		"--handle-size": "24px",
		"--handle-overhang": "-8px",
		"--handle-inset": "8px",
		width: {
			"": "$handle-size",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "auto"
		},
		height: {
			"": "$handle-size",
			"[data-axis=\"e\"] | [data-axis=\"w\"]": "auto"
		},
		top: {
			"": "auto",
			"[data-axis=\"n\"] | [data-axis=\"ne\"] | [data-axis=\"nw\"]": "$handle-overhang",
			"[data-axis=\"e\"] | [data-axis=\"w\"]": "$handle-inset"
		},
		bottom: {
			"": "auto",
			"[data-axis=\"s\"] | [data-axis=\"se\"] | [data-axis=\"sw\"]": "$handle-overhang",
			"[data-axis=\"e\"] | [data-axis=\"w\"]": "$handle-inset"
		},
		left: {
			"": "auto",
			"[data-axis=\"w\"] | [data-axis=\"nw\"] | [data-axis=\"sw\"]": "$handle-overhang",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "$handle-inset"
		},
		right: {
			"": "auto",
			"[data-axis=\"e\"] | [data-axis=\"ne\"] | [data-axis=\"se\"]": "$handle-overhang",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "$handle-inset"
		},
		cursor: {
			"": "default",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "ns-resize",
			"[data-axis=\"e\"] | [data-axis=\"w\"]": "ew-resize",
			"[data-axis=\"ne\"] | [data-axis=\"sw\"]": "nesw-resize",
			"[data-axis=\"nw\"] | [data-axis=\"se\"]": "nwse-resize"
		},
		touchAction: "none"
	}
});
const GripElement = tasty({
	qa: "BoardResizeGrip",
	styles: {
		position: "absolute",
		width: "10px",
		height: "10px",
		boxSizing: "border-box",
		pointerEvents: "none",
		opacity: {
			"": 0,
			revealed: 1
		},
		transition: "opacity 120ms ease-in-out",
		borderTop: {
			"": "0",
			"[data-axis=\"ne\"] | [data-axis=\"nw\"]": "2px solid #dark.40"
		},
		borderBottom: {
			"": "0",
			"[data-axis=\"se\"] | [data-axis=\"sw\"]": "2px solid #dark.40"
		},
		borderLeft: {
			"": "0",
			"[data-axis=\"nw\"] | [data-axis=\"sw\"]": "2px solid #dark.40"
		},
		borderRight: {
			"": "0",
			"[data-axis=\"ne\"] | [data-axis=\"se\"]": "2px solid #dark.40"
		},
		radius: {
			"": "0",
			"[data-axis=\"se\"]": "0 0 4px 0",
			"[data-axis=\"sw\"]": "0 0 0 4px",
			"[data-axis=\"ne\"]": "0 4px 0 0",
			"[data-axis=\"nw\"]": "4px 0 0 0"
		},
		top: {
			"": "auto",
			"[data-axis=\"ne\"] | [data-axis=\"nw\"]": "4px"
		},
		bottom: {
			"": "auto",
			"[data-axis=\"se\"] | [data-axis=\"sw\"]": "4px"
		},
		left: {
			"": "auto",
			"[data-axis=\"nw\"] | [data-axis=\"sw\"]": "4px"
		},
		right: {
			"": "auto",
			"[data-axis=\"ne\"] | [data-axis=\"se\"]": "4px"
		}
	}
});
const EdgeGripElement = tasty({
	qa: "BoardResizeEdgeGrip",
	styles: {
		position: "absolute",
		display: "grid",
		gap: "2bw",
		boxSizing: "border-box",
		pointerEvents: "none",
		opacity: {
			"": 0,
			revealed: 1
		},
		transition: "opacity 120ms ease-in-out",
		gridColumns: {
			"": "3px",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "3px 3px 3px 3px 3px"
		},
		gridRows: {
			"": "3px 3px 3px 3px 3px",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "3px"
		},
		top: {
			"": "50%",
			"[data-axis=\"n\"]": "3px",
			"[data-axis=\"s\"]": "auto"
		},
		bottom: {
			"": "auto",
			"[data-axis=\"s\"]": "3px"
		},
		left: {
			"": "auto",
			"[data-axis=\"w\"]": "3px",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "50%"
		},
		right: {
			"": "auto",
			"[data-axis=\"e\"]": "3px"
		},
		transform: {
			"": "translate(0, 0)",
			"[data-axis=\"e\"] | [data-axis=\"w\"]": "translate(0, -50%)",
			"[data-axis=\"n\"] | [data-axis=\"s\"]": "translate(-50%, 0)"
		},
		Dot: {
			width: "3px",
			height: "3px",
			radius: "round",
			fill: {
				"": "#dark-03",
				resizing: "#dark-02"
			}
		}
	}
});
/** Corner axes get a visible grip affordance on hover/focus/resize. */
function isCornerAxis(axis) {
	return axis.length === 2;
}
/** Edge axes (n/s/e/w) get a dotted grip affordance. */
function isEdgeAxis(axis) {
	return axis.length === 1;
}
function ResizeHandle({ axis, onResize }) {
	const { moveProps } = useMove({
		onMoveStart() {
			onResize(axis, "start", 0, 0);
		},
		onMove(e) {
			onResize(axis, "move", e.deltaX, e.deltaY);
		},
		onMoveEnd() {
			onResize(axis, "end", 0, 0);
		}
	});
	const stopProps = {
		onPointerDown: (e) => e.stopPropagation(),
		onMouseDown: (e) => e.stopPropagation(),
		onTouchStart: (e) => e.stopPropagation()
	};
	return /* @__PURE__ */ jsx(HandleElement, {
		"data-axis": axis,
		...mergeProps$1(stopProps, moveProps),
		"aria-hidden": "true"
	});
}
/**
* The positioned, interactive wrapper a board renders for each layout item it
* owns. Content is pulled from the shared store (by id), so any board can host
* any widget. Dragging uses React Aria `useMove`; during a drag the widget
* renders into the shared overlay portal so it can float outside its board.
*/
function WidgetHost(props) {
	const { boardId, item, positionParams, registration, isCard, styles: widgetStyles, isDraggable, isResizable, resizeHandles, isAutoHeight, qa, dragCancel, dragHandle, registry, dragState, settled, onResize, onAutoHeight, onDragLifecycle } = props;
	const hostRef = useRef(null);
	const isActiveDrag = dragState?.itemId === item.i;
	const requestHeightDeficit = useEvent((deficitPx) => {
		if (!isAutoHeight || isActiveDrag) return;
		const step = positionParams.rowHeight + positionParams.margin[1];
		if (step <= 0) return;
		const neededPx = calcGridItemPosition(positionParams, item.x, item.y, item.w, item.h).height + deficitPx;
		const neededRows = Math.max(1, Math.ceil((neededPx + positionParams.margin[1] - AUTO_HEIGHT_TOLERANCE) / step));
		onAutoHeight(item.i, neededRows);
	});
	const hostValue = useMemo(() => ({
		isAutoHeight,
		requestHeightDeficit
	}), [isAutoHeight, requestHeightDeficit]);
	const useOverlay = isActiveDrag && dragState?.pointerType !== "keyboard";
	const [isResizing, setIsResizing] = useState(false);
	const [isFocusWithin, setIsFocusWithin] = useState(false);
	const { hoverProps, isHovered } = useHover({ isDisabled: isActiveDrag });
	const { focusProps, isFocusVisible } = useFocusRing();
	const { focusWithinProps } = useFocusWithin({ onFocusWithinChange: setIsFocusWithin });
	const gripsRevealed = isResizable && !item.static && !isActiveDrag && (isHovered || isFocusWithin || isResizing);
	const { moveProps } = useMove({
		onMoveStart(e) {
			if (!isDraggable) return;
			const rect = hostRef.current?.getBoundingClientRect();
			const pos = calcGridItemPosition(positionParams, item.x, item.y, item.w, item.h);
			const vr = rect ? {
				left: rect.left,
				top: rect.top,
				width: rect.width,
				height: rect.height
			} : {
				left: pos.left,
				top: pos.top,
				width: pos.width,
				height: pos.height
			};
			registry.onDragStart(boardId, item.i, vr, e.pointerType, hostRef.current);
			onDragLifecycle?.(item.i, "start");
		},
		onMove(e) {
			if (!isDraggable) return;
			if (e.pointerType === "keyboard") {
				const stepX = calcGridColWidth(positionParams) + positionParams.margin[0];
				const stepY = positionParams.rowHeight + positionParams.margin[1];
				registry.onDragMove(Math.sign(e.deltaX) * stepX, Math.sign(e.deltaY) * stepY, e.pointerType);
				onDragLifecycle?.(item.i, "move");
				return;
			}
			registry.onDragMove(e.deltaX, e.deltaY, e.pointerType);
			onDragLifecycle?.(item.i, "move");
		},
		onMoveEnd() {
			if (!isDraggable) return;
			registry.onDragEnd();
			onDragLifecycle?.(item.i, "end");
		}
	});
	const a11yProps = {
		tabIndex: isDraggable ? 0 : void 0,
		"aria-roledescription": isDraggable ? "Draggable widget" : void 0,
		"aria-label": qa ?? item.i
	};
	const stopBubbleProps = isDraggable ? {
		onPointerDown: (e) => e.stopPropagation(),
		onMouseDown: (e) => e.stopPropagation(),
		onTouchStart: (e) => e.stopPropagation()
	} : {};
	const shouldGateDrag = (target) => {
		if (!(target instanceof Element)) return false;
		if (dragHandle && !target.closest(dragHandle)) return true;
		return !!(dragCancel && target.closest(dragCancel));
	};
	const gatedMoveProps = !isDraggable ? {} : {
		...moveProps,
		...moveProps.onPointerDown && { onPointerDown: (e) => {
			if (shouldGateDrag(e.target)) return;
			hostRef.current?.focus({ preventScroll: true });
			moveProps.onPointerDown(e);
		} },
		...moveProps.onMouseDown && { onMouseDown: (e) => {
			if (shouldGateDrag(e.target)) return;
			hostRef.current?.focus({ preventScroll: true });
			moveProps.onMouseDown(e);
		} },
		...moveProps.onTouchStart && { onTouchStart: (e) => {
			if (shouldGateDrag(e.target)) return;
			moveProps.onTouchStart(e);
		} },
		...moveProps.onKeyDown && { onKeyDown: (e) => {
			if (e.target !== e.currentTarget) return;
			moveProps.onKeyDown(e);
		} }
	};
	const handleResize = (axis, phase, dx, dy) => {
		if (phase === "start") setIsResizing(true);
		else if (phase === "end") setIsResizing(false);
		onResize(item.i, axis, phase, dx, dy);
	};
	const mods = {
		drag: isActiveDrag,
		draggable: isDraggable && !isActiveDrag,
		static: !!item.static,
		resizing: isResizing,
		card: isCard,
		hovered: isHovered,
		"focus-visible": isFocusVisible
	};
	const content = /* @__PURE__ */ jsxs(BoardHostContext.Provider, {
		value: hostValue,
		children: [registration?.content, isResizable && !item.static ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
			resizeHandles.map((axis) => /* @__PURE__ */ jsx(ResizeHandle, {
				axis,
				onResize: handleResize
			}, axis)),
			resizeHandles.filter(isCornerAxis).map((axis) => /* @__PURE__ */ jsx(GripElement, {
				"data-axis": axis,
				mods: { revealed: gripsRevealed },
				"aria-hidden": "true"
			}, `grip-${axis}`)),
			resizeHandles.filter(isEdgeAxis).map((axis) => /* @__PURE__ */ jsxs(EdgeGripElement, {
				"data-axis": axis,
				mods: {
					revealed: gripsRevealed,
					resizing: isResizing
				},
				"aria-hidden": "true",
				children: [
					/* @__PURE__ */ jsx("div", { "data-element": "Dot" }),
					/* @__PURE__ */ jsx("div", { "data-element": "Dot" }),
					/* @__PURE__ */ jsx("div", { "data-element": "Dot" }),
					/* @__PURE__ */ jsx("div", { "data-element": "Dot" }),
					/* @__PURE__ */ jsx("div", { "data-element": "Dot" })
				]
			}, `edge-grip-${axis}`))
		] }) : null]
	});
	const pos = calcGridItemPosition(positionParams, item.x, item.y, item.w, item.h);
	const overlayNode = registry.overlayRef.current;
	const floatInOverlay = useOverlay && !!overlayNode && !!dragState;
	const hostStyle = {
		left: `${pos.left}px`,
		top: `${pos.top}px`,
		width: `${pos.width}px`,
		height: `${pos.height}px`,
		...floatInOverlay ? {
			opacity: 0,
			pointerEvents: "none"
		} : null
	};
	const hostMods = {
		...mods,
		drag: isActiveDrag && !floatInOverlay,
		settled
	};
	return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(WidgetElement, {
		ref: hostRef,
		"data-board-widget-host": "",
		...mergeProps$1(gatedMoveProps, stopBubbleProps, hoverProps, focusProps, focusWithinProps, a11yProps, { style: hostStyle }),
		qa,
		mods: hostMods,
		styles: widgetStyles,
		children: floatInOverlay ? null : content
	}), floatInOverlay ? createPortal(/* @__PURE__ */ jsx(WidgetElement, {
		style: {
			position: "absolute",
			left: `${dragState.rect.left}px`,
			top: `${dragState.rect.top}px`,
			width: `${dragState.rect.width}px`,
			height: `${dragState.rect.height}px`,
			pointerEvents: "none"
		},
		mods: {
			...mods,
			drag: true,
			floating: true
		},
		styles: widgetStyles,
		"aria-hidden": "true",
		children: content
	}), overlayNode) : null] });
}

//#endregion
export { WidgetHost };
//# sourceMappingURL=WidgetHost.js.map