import { n as __exportAll } from "./chunk-B-1-B7_t.js";
import { n as cn } from "./utils-DXzSsU1e.js";
import { n as Badge_default } from "./badge-BbQrSqE-.js";
import { n as Button_default } from "./button-B9CnnuTu.js";
import { n as CardTitle_default, o as CardContent_default, r as CardHeader_default, s as Card_default } from "./card-X74FuL7B.js";
import { t as Input_default } from "./input-CwDp-vE8.js";
import { n as Label_default } from "./label-C5K3zowH.js";
import { n as useGridBuilder } from "./gridBuilderStore-D1Gd1Hlj.js";
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeModels, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, toDisplayString, unref, useModel, watch, withCtx, withModifiers } from "vue";
import { Plus, Trash2, X } from "@lucide/vue";
//#region src/components/compositions/elements/builder/GridBuilder.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = ["data-element-name"];
var _hoisted_2 = {
	class: "flex flex-col gap-2 border-r p-3 overflow-y-auto",
	"data-testid": "grid-builder-palette"
};
var _hoisted_3 = { class: "text-xs font-semibold uppercase tracking-wide text-muted-foreground" };
var _hoisted_4 = { class: "flex flex-col gap-1" };
var _hoisted_5 = [
	"data-testid",
	"disabled",
	"onClick"
];
var _hoisted_6 = { class: "font-medium" };
var _hoisted_7 = {
	key: 0,
	class: "text-xs text-muted-foreground"
};
var _hoisted_8 = {
	key: 1,
	class: "flex flex-col gap-0.5 text-xs text-destructive",
	role: "alert"
};
var _hoisted_9 = {
	class: "flex flex-col gap-3 overflow-y-auto p-3",
	"data-testid": "grid-builder-canvas"
};
var _hoisted_10 = { class: "flex items-center justify-between" };
var _hoisted_11 = [
	"data-testid",
	"onClick",
	"onPointerdown"
];
var _hoisted_12 = { class: "font-medium" };
var _hoisted_13 = { class: "font-mono text-[10px] text-muted-foreground" };
var _hoisted_14 = ["data-testid", "onPointerdown"];
var _hoisted_15 = {
	key: 1,
	class: "py-6 text-center text-xs text-muted-foreground",
	"data-testid": "grid-builder-canvas-empty"
};
var _hoisted_16 = {
	class: "flex flex-col gap-2 overflow-y-auto border-l p-3",
	"data-testid": "grid-builder-inspector"
};
var _hoisted_17 = { class: "flex items-center justify-between" };
var _hoisted_18 = {
	key: 0,
	class: "py-3 text-xs text-muted-foreground",
	"data-testid": "grid-builder-inspector-empty"
};
var _hoisted_19 = {
	key: 1,
	class: "flex flex-col gap-3",
	"data-testid": "grid-builder-inspector-fields"
};
var _hoisted_20 = { class: "flex flex-col gap-1" };
var _hoisted_21 = { class: "grid grid-cols-2 gap-2" };
var _hoisted_22 = { class: "flex flex-col gap-1" };
var _hoisted_23 = { class: "flex flex-col gap-1" };
var _hoisted_24 = { class: "flex flex-col gap-1" };
var _hoisted_25 = { class: "flex flex-col gap-1" };
var GridBuilder_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "GridBuilder",
	props: /* @__PURE__ */ mergeModels({
		modelValue: {},
		builderId: {},
		label: {},
		name: {},
		item: { default: () => ({}) },
		classList: {},
		helpText: {},
		errors: { default: () => [] },
		hideLabel: { type: Boolean },
		required: { type: Boolean },
		readonly: { type: Boolean },
		disabled: { type: Boolean }
	}, {
		"modelValue": {},
		"modelModifiers": {}
	}),
	emits: ["update:modelValue"],
	setup(__props) {
		/**
		* GridBuilder — MVP visual grid layout designer.
		*
		* Three-pane layout:
		*   - LEFT  (Palette):    "Add cell" button plus a set of preset size
		*                         buttons (1x1, 2x2, 4x2, 6x4, 12x1). Click any
		*                         to append a new cell of that size.
		*   - MIDDLE (Canvas):    CSS-grid preview of the current layout. Each
		*                         cell is a clickable card; empty rows render a
		*                         dashed placeholder hint.
		*   - RIGHT (Inspector):  Edit the selected cell's label, x/y position
		*                         and w/h span via number inputs. Includes a
		*                         Remove button.
		*
		* Pointer-driven drag-to-reposition and resize-from-corner are wired
		* directly on each cell. Drags snap to the 12-column grid; the
		* resize handle (bottom-right) adjusts `w` / `h`. The inspector
		* remains the canonical numeric editor.
		*
		* State lives in `gridBuilderStore` (Pinia). The component accepts an
		* optional `modelValue` schema (v-modelable) and emits the current
		* schema on every mutation so the host page can persist it.
		*/
		const props = __props;
		const model = useModel(__props, "modelValue");
		let nextAutoId = 0;
		function makeAutoId() {
			nextAutoId += 1;
			return `grid-builder-${Date.now()}-${nextAutoId}`;
		}
		const fallbackId = ref(makeAutoId());
		const builder = useGridBuilder(computed(() => props.builderId ?? fallbackId.value).value);
		function isGridBuilderSchema(value) {
			if (typeof value !== "object" || value === null) return false;
			const v = value;
			return typeof v.cols === "number" && typeof v.rowHeight === "number" && Array.isArray(v.items);
		}
		/** Seed the store from the initial modelValue. */
		onMounted(() => {
			const seed = model.value;
			if (isGridBuilderSchema(seed)) builder.loadSchema(seed);
		});
		/** Push schema changes back via v-model. */
		watch(() => builder.schema.value, (next) => {
			model.value = {
				cols: next.cols,
				rowHeight: next.rowHeight,
				items: next.items.map((it) => ({ ...it }))
			};
		}, { deep: true });
		const cellTemplates = [
			{
				label: "1×1",
				w: 1,
				h: 1
			},
			{
				label: "2×2",
				w: 2,
				h: 2
			},
			{
				label: "4×2",
				w: 4,
				h: 2
			},
			{
				label: "6×4",
				w: 6,
				h: 4
			},
			{
				label: "12×1",
				w: 12,
				h: 1
			}
		];
		const items = computed(() => builder.schema.value.items);
		const cols = computed(() => builder.schema.value.cols);
		const rowHeight = computed(() => builder.schema.value.rowHeight);
		const selectedItem = computed(() => {
			const sel = builder.selection.value;
			if (!sel.id) return null;
			return items.value.find((it) => it.id === sel.id) ?? null;
		});
		const gridStyle = computed(() => ({
			display: "grid",
			gridTemplateColumns: `repeat(${cols.value}, minmax(0, 1fr))`,
			gridAutoRows: `${rowHeight.value}px`,
			gap: "0.5rem"
		}));
		function cellStyle(it) {
			return {
				gridColumn: `${it.x + 1} / span ${it.w}`,
				gridRow: `${it.y + 1} / span ${it.h}`
			};
		}
		function onAddCell() {
			const id = builder.addItem();
			builder.select(id);
		}
		function onAddPresetCell(template) {
			const id = builder.addItem({
				w: template.w,
				h: template.h,
				label: `${template.label} cell`
			});
			builder.select(id);
		}
		function onCellClick(itemId) {
			builder.select(itemId);
		}
		function onRemove() {
			const sel = builder.selection.value;
			if (sel.id) builder.removeItem(sel.id);
		}
		function onClearSelection() {
			builder.select(null);
		}
		function patchSelected(patch) {
			const sel = builder.selection.value;
			if (sel.id) builder.updateItem(sel.id, patch);
		}
		function parseInt0(value) {
			const n = Number.parseInt(value, 10);
			return Number.isFinite(n) ? n : 0;
		}
		function parseInt1(value) {
			const n = Number.parseInt(value, 10);
			return Number.isFinite(n) && n >= 1 ? n : 1;
		}
		/** Ref to the canvas grid wrapper — used to measure column width. */
		const gridEl = ref(null);
		const activeDrag = ref(null);
		/** Id of the cell currently being dragged or resized — drives the
		* `ring-2 ring-primary` visual feedback. */
		const activeInteractionId = computed(() => activeDrag.value?.itemId ?? null);
		function measureCellWidth() {
			const el = gridEl.value;
			if (!el) return 0;
			return el.getBoundingClientRect().width / cols.value;
		}
		function beginDrag(it, event, mode) {
			if (props.disabled || props.readonly) return;
			event.preventDefault();
			event.stopPropagation();
			builder.select(it.id);
			const target = event.target;
			if (target && typeof target.setPointerCapture === "function") try {
				target.setPointerCapture(event.pointerId);
			} catch {}
			activeDrag.value = {
				mode,
				itemId: it.id,
				pointerId: event.pointerId,
				target: target ?? event.currentTarget,
				startClientX: event.clientX,
				startClientY: event.clientY,
				startX: it.x,
				startY: it.y,
				startW: it.w,
				startH: it.h,
				cellWidthPx: measureCellWidth()
			};
			window.addEventListener("pointermove", onPointerMove);
			window.addEventListener("pointerup", onPointerUp);
			window.addEventListener("pointercancel", onPointerUp);
		}
		function onCellPointerDown(it, event) {
			if (event.button !== void 0 && event.button !== 0) return;
			beginDrag(it, event, "drag");
		}
		function onResizeHandlePointerDown(it, event) {
			if (event.button !== void 0 && event.button !== 0) return;
			beginDrag(it, event, "resize");
		}
		function onPointerMove(event) {
			const state = activeDrag.value;
			if (!state) return;
			const cellW = state.cellWidthPx > 0 ? state.cellWidthPx : 1;
			const rowH = rowHeight.value > 0 ? rowHeight.value : 1;
			const dx = event.clientX - state.startClientX;
			const dy = event.clientY - state.startClientY;
			const colDelta = Math.round(dx / cellW);
			const rowDelta = Math.round(dy / rowH);
			if (state.mode === "drag") {
				const nextX = state.startX + colDelta;
				const nextY = state.startY + rowDelta;
				builder.updateItem(state.itemId, {
					x: nextX,
					y: nextY
				});
			} else {
				const nextW = Math.max(1, state.startW + colDelta);
				const nextH = Math.max(1, state.startH + rowDelta);
				builder.updateItem(state.itemId, {
					w: nextW,
					h: nextH
				});
			}
		}
		function onPointerUp(event) {
			const state = activeDrag.value;
			if (state) {
				const target = state.target;
				if (target && typeof target.releasePointerCapture === "function") try {
					target.releasePointerCapture(state.pointerId);
				} catch {}
			}
			activeDrag.value = null;
			window.removeEventListener("pointermove", onPointerMove);
			window.removeEventListener("pointerup", onPointerUp);
			window.removeEventListener("pointercancel", onPointerUp);
		}
		onBeforeUnmount(() => {
			window.removeEventListener("pointermove", onPointerMove);
			window.removeEventListener("pointerup", onPointerUp);
			window.removeEventListener("pointercancel", onPointerUp);
		});
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", {
				class: normalizeClass(unref(cn)("gxp-grid-builder grid gap-3 rounded-lg border bg-card", props.classList)),
				style: {
					"grid-template-columns": "220px 1fr 280px",
					"min-height": "24rem"
				},
				"data-testid": "grid-builder",
				"data-element-name": props.name ?? void 0
			}, [
				createElementVNode("aside", _hoisted_2, [
					createElementVNode("h4", _hoisted_3, toDisplayString(props.label ?? "Grid palette"), 1),
					createVNode(unref(Button_default), {
						type: "button",
						variant: "outline",
						size: "sm",
						class: "justify-start gap-2",
						"data-testid": "grid-builder-palette-add",
						disabled: props.disabled || props.readonly,
						onClick: onAddCell
					}, {
						default: withCtx(() => [createVNode(unref(Plus), { class: "h-3.5 w-3.5" }), _cache[6] || (_cache[6] = createTextVNode(" Add cell ", -1))]),
						_: 1
					}, 8, ["disabled"]),
					createElementVNode("div", _hoisted_4, [(openBlock(), createElementBlock(Fragment, null, renderList(cellTemplates, (tpl) => {
						return createElementVNode("button", {
							key: tpl.label,
							type: "button",
							class: "flex items-center gap-2 rounded-md border bg-background px-2 py-1.5 text-left text-xs transition-colors hover:border-primary hover:bg-accent/40 disabled:opacity-50",
							"data-testid": `grid-builder-palette-${tpl.w}x${tpl.h}`,
							disabled: props.disabled || props.readonly,
							onClick: ($event) => onAddPresetCell(tpl)
						}, [createVNode(unref(Plus), { class: "h-3.5 w-3.5 shrink-0" }), createElementVNode("span", _hoisted_6, toDisplayString(tpl.label) + " cell", 1)], 8, _hoisted_5);
					}), 64))]),
					props.helpText ? (openBlock(), createElementBlock("p", _hoisted_7, toDisplayString(props.helpText), 1)) : createCommentVNode("", true),
					props.errors.length ? (openBlock(), createElementBlock("ul", _hoisted_8, [(openBlock(true), createElementBlock(Fragment, null, renderList(props.errors, (err, i) => {
						return openBlock(), createElementBlock("li", { key: i }, toDisplayString(err), 1);
					}), 128))])) : createCommentVNode("", true)
				]),
				createElementVNode("section", _hoisted_9, [createElementVNode("header", _hoisted_10, [_cache[8] || (_cache[8] = createElementVNode("h4", { class: "text-xs font-semibold uppercase tracking-wide text-muted-foreground" }, " Preview ", -1)), createVNode(unref(Badge_default), {
					variant: "outline",
					class: "font-mono text-[10px]"
				}, {
					default: withCtx(() => [..._cache[7] || (_cache[7] = [createTextVNode(" builder/grid-builder ", -1)])]),
					_: 1
				})]), items.value.length > 0 ? (openBlock(), createElementBlock("div", {
					key: 0,
					ref_key: "gridEl",
					ref: gridEl,
					class: "rounded-md border border-dashed bg-background p-2",
					style: normalizeStyle(gridStyle.value),
					"data-testid": "grid-builder-canvas-grid"
				}, [(openBlock(true), createElementBlock(Fragment, null, renderList(items.value, (it) => {
					return openBlock(), createElementBlock("div", {
						key: it.id,
						style: normalizeStyle(cellStyle(it)),
						"data-testid": `grid-builder-cell-${it.id}`,
						class: normalizeClass(["relative flex cursor-move touch-none select-none flex-col items-center justify-center gap-1 rounded border bg-card px-2 py-1 text-center text-xs transition-colors hover:border-primary", [unref(builder).selection.value.id === it.id ? "border-primary bg-accent/30 ring-2 ring-primary/30" : "", activeInteractionId.value === it.id ? "ring-2 ring-primary" : ""]]),
						onClick: ($event) => onCellClick(it.id),
						onPointerdown: (e) => onCellPointerDown(it, e)
					}, [
						createElementVNode("span", _hoisted_12, toDisplayString(it.label), 1),
						createElementVNode("span", _hoisted_13, toDisplayString(it.w) + "×" + toDisplayString(it.h) + " @ (" + toDisplayString(it.x) + ", " + toDisplayString(it.y) + ") ", 1),
						createElementVNode("span", {
							class: "absolute bottom-0.5 right-0.5 h-2.5 w-2.5 cursor-nwse-resize rounded-sm border border-primary/70 bg-primary/30 hover:bg-primary",
							"data-testid": `grid-builder-resize-${it.id}`,
							onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"])),
							onPointerdown: withModifiers((e) => onResizeHandlePointerDown(it, e), ["stop"])
						}, null, 40, _hoisted_14)
					], 46, _hoisted_11);
				}), 128))], 4)) : (openBlock(), createElementBlock("p", _hoisted_15, " Click \"Add cell\" or a preset to start the layout. "))]),
				createElementVNode("aside", _hoisted_16, [createElementVNode("header", _hoisted_17, [_cache[9] || (_cache[9] = createElementVNode("h4", { class: "text-xs font-semibold uppercase tracking-wide text-muted-foreground" }, " Inspector ", -1)), unref(builder).selection.value.id ? (openBlock(), createBlock(unref(Button_default), {
					key: 0,
					variant: "ghost",
					size: "icon-sm",
					"aria-label": "Clear selection",
					onClick: onClearSelection
				}, {
					default: withCtx(() => [createVNode(unref(X), { class: "h-3.5 w-3.5" })]),
					_: 1
				})) : createCommentVNode("", true)]), !selectedItem.value ? (openBlock(), createElementBlock("p", _hoisted_18, " Select a cell on the canvas to edit its size and position. ")) : (openBlock(), createElementBlock("div", _hoisted_19, [createVNode(unref(Card_default), { class: "border-dashed" }, {
					default: withCtx(() => [createVNode(unref(CardHeader_default), { class: "py-2" }, {
						default: withCtx(() => [createVNode(unref(CardTitle_default), { class: "font-mono text-xs uppercase tracking-wide" }, {
							default: withCtx(() => [..._cache[10] || (_cache[10] = [createTextVNode(" cell ", -1)])]),
							_: 1
						})]),
						_: 1
					}), createVNode(unref(CardContent_default), { class: "flex flex-col gap-2 pb-3" }, {
						default: withCtx(() => [createElementVNode("div", _hoisted_20, [createVNode(unref(Label_default), { for: "gb-label" }, {
							default: withCtx(() => [..._cache[11] || (_cache[11] = [createTextVNode("Label", -1)])]),
							_: 1
						}), createVNode(unref(Input_default), {
							id: "gb-label",
							"model-value": selectedItem.value.label,
							"data-testid": "grid-builder-inspector-label",
							onInput: _cache[1] || (_cache[1] = (e) => patchSelected({ label: e.target.value }))
						}, null, 8, ["model-value"])]), createElementVNode("div", _hoisted_21, [
							createElementVNode("div", _hoisted_22, [createVNode(unref(Label_default), { for: "gb-x" }, {
								default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode("X (col)", -1)])]),
								_: 1
							}), createVNode(unref(Input_default), {
								id: "gb-x",
								type: "number",
								min: "0",
								"model-value": selectedItem.value.x,
								"data-testid": "grid-builder-inspector-x",
								onInput: _cache[2] || (_cache[2] = (e) => patchSelected({ x: parseInt0(e.target.value) }))
							}, null, 8, ["model-value"])]),
							createElementVNode("div", _hoisted_23, [createVNode(unref(Label_default), { for: "gb-y" }, {
								default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode("Y (row)", -1)])]),
								_: 1
							}), createVNode(unref(Input_default), {
								id: "gb-y",
								type: "number",
								min: "0",
								"model-value": selectedItem.value.y,
								"data-testid": "grid-builder-inspector-y",
								onInput: _cache[3] || (_cache[3] = (e) => patchSelected({ y: parseInt0(e.target.value) }))
							}, null, 8, ["model-value"])]),
							createElementVNode("div", _hoisted_24, [createVNode(unref(Label_default), { for: "gb-w" }, {
								default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode("Width", -1)])]),
								_: 1
							}), createVNode(unref(Input_default), {
								id: "gb-w",
								type: "number",
								min: "1",
								"model-value": selectedItem.value.w,
								"data-testid": "grid-builder-inspector-w",
								onInput: _cache[4] || (_cache[4] = (e) => patchSelected({ w: parseInt1(e.target.value) }))
							}, null, 8, ["model-value"])]),
							createElementVNode("div", _hoisted_25, [createVNode(unref(Label_default), { for: "gb-h" }, {
								default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode("Height", -1)])]),
								_: 1
							}), createVNode(unref(Input_default), {
								id: "gb-h",
								type: "number",
								min: "1",
								"model-value": selectedItem.value.h,
								"data-testid": "grid-builder-inspector-h",
								onInput: _cache[5] || (_cache[5] = (e) => patchSelected({ h: parseInt1(e.target.value) }))
							}, null, 8, ["model-value"])])
						])]),
						_: 1
					})]),
					_: 1
				}), createVNode(unref(Button_default), {
					variant: "destructive",
					size: "sm",
					class: "self-end",
					"data-testid": "grid-builder-remove",
					onClick: onRemove
				}, {
					default: withCtx(() => [createVNode(unref(Trash2), { class: "h-3.5 w-3.5" }), _cache[16] || (_cache[16] = createTextVNode(" Remove ", -1))]),
					_: 1
				})]))])
			], 10, _hoisted_1);
		};
	}
});
//#endregion
//#region src/components/compositions/elements/builder/GridBuilder.vue
var GridBuilder_exports = /* @__PURE__ */ __exportAll({ default: () => GridBuilder_default });
var GridBuilder_default = GridBuilder_vue_vue_type_script_setup_true_lang_default;
//#endregion
export { GridBuilder_exports as n, GridBuilder_default as t };

//# sourceMappingURL=GridBuilder-BkdsS6fB.js.map