const require_chunk = require("./chunk-9hOWP6kD.cjs");
const require_registries = require("./registries-DgzzKX8_.cjs");
let react = require("react");
let react_jsx_runtime = require("react/jsx-runtime");
let lucide_react = require("lucide-react");
//#region ../widgets/src/contexts/PortalUrlVariablesContext.tsx
/**
* Values used to substitute `{{token}}` placeholders in widget-configured URLs.
*
* **Production runtime substitution happens server-side** in the Portal Tenant
* BFF via `UrlResolver` (mirroring `MobileTabWidget#resolve_link_urls`).
* The portal client receives URLs already resolved, so the default `{}` value
* is the right one for the live `AppShell` — substitution becomes a no-op
* because there are no `{{...}}` tokens left to match.
*
* **Admin builder preview** mounts the provider with `PREVIEW_URL_VARIABLES`
* so admins see realistic sample values for any `{{username}}` /
* `{{replicated_url}}` tokens they've configured, without the builder needing
* to fetch real user data or hit the BFF resolver.
*/
const PortalUrlVariablesContext = (0, react.createContext)({});
const PortalUrlVariablesProvider = PortalUrlVariablesContext.Provider;
function usePortalUrlVariables() {
	return (0, react.useContext)(PortalUrlVariablesContext);
}
//#endregion
//#region ../core/src/url-templating.ts
/**
* URL variable substitution for portal widgets.
*
* Mirrors the mobile app's Quick Links template-tag syntax so URLs configured
* by admins in the portal builder can include placeholders like
* `{{username || /profile}}` that resolve to user-specific values at render
* time.
*
* Supported syntax:
*   - `{{token}}` — replace with the value at `values[token]`. If no value is
*     provided, the literal placeholder is left in place.
*   - `{{token || fallback_path}}` — replace with the value if present and
*     non-empty, otherwise replace with `fallback_path` (everything after `||`).
*
* Leading/trailing whitespace inside the braces is permitted:
*   `{{ username || /profile }}` is equivalent to `{{username || /profile}}`.
*/
const TOKEN_PATTERN = /\{\{\s*([^}|\s]+)\s*(?:\|\|\s*([^}]*?))?\s*\}\}/g;
function substituteUrlVariables(url, values) {
	return url.replace(TOKEN_PATTERN, (match, rawToken, rawFallback) => {
		const value = values[rawToken.trim()];
		if (value != null && value !== "") return value;
		if (rawFallback !== void 0) return rawFallback.trim();
		return match;
	});
}
//#endregion
//#region ../widgets/src/widgets/QuickLinksWidget.tsx
var QuickLinksWidget_exports = /* @__PURE__ */ require_chunk.__exportAll({
	QuickLinksWidget: () => QuickLinksWidget,
	quickLinksWidgetPropertySchema: () => quickLinksWidgetPropertySchema
});
const ICON_MAP = {
	User: lucide_react.User,
	Share2: lucide_react.Share2,
	ShoppingBag: lucide_react.ShoppingBag,
	Video: lucide_react.Video,
	Mail: lucide_react.Mail,
	MessageCircle: lucide_react.MessageCircle,
	Globe: lucide_react.Globe,
	Calendar: lucide_react.Calendar,
	Bell: lucide_react.Bell,
	Heart: lucide_react.Heart,
	Star: lucide_react.Star,
	Zap: lucide_react.Zap,
	Gift: lucide_react.Gift,
	Phone: lucide_react.Phone,
	MapPin: lucide_react.MapPin,
	Play: lucide_react.Play,
	Package: lucide_react.Package,
	ExternalLink: lucide_react.ExternalLink,
	Bookmark: lucide_react.BookmarkIcon,
	Trophy: lucide_react.Trophy,
	Sparkles: lucide_react.Sparkles,
	Link: lucide_react.Link
};
const ICON_OPTIONS = [
	{
		label: "Link (default)",
		value: "Link"
	},
	{
		label: "User / Profile",
		value: "User"
	},
	{
		label: "Share",
		value: "Share2"
	},
	{
		label: "Shopping Bag",
		value: "ShoppingBag"
	},
	{
		label: "Video",
		value: "Video"
	},
	{
		label: "Mail",
		value: "Mail"
	},
	{
		label: "Message",
		value: "MessageCircle"
	},
	{
		label: "Globe",
		value: "Globe"
	},
	{
		label: "Calendar",
		value: "Calendar"
	},
	{
		label: "Bell / Notifications",
		value: "Bell"
	},
	{
		label: "Heart",
		value: "Heart"
	},
	{
		label: "Star",
		value: "Star"
	},
	{
		label: "Zap / Lightning",
		value: "Zap"
	},
	{
		label: "Gift",
		value: "Gift"
	},
	{
		label: "Phone",
		value: "Phone"
	},
	{
		label: "Map Pin",
		value: "MapPin"
	},
	{
		label: "Play",
		value: "Play"
	},
	{
		label: "Package",
		value: "Package"
	},
	{
		label: "External Link",
		value: "ExternalLink"
	},
	{
		label: "Bookmark",
		value: "Bookmark"
	},
	{
		label: "Trophy",
		value: "Trophy"
	},
	{
		label: "Sparkles",
		value: "Sparkles"
	}
];
const capitalize = (s) => s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
const getIcon = (name) => {
	if (!name) return lucide_react.Link;
	return ICON_MAP[name] ?? ICON_MAP[capitalize(name)] ?? lucide_react.Link;
};
const isColorOption = (value) => [
	"background",
	"foreground",
	"primary",
	"secondary",
	"accent",
	"muted",
	"destructive"
].includes(value);
const FALLBACK_COLOR_CYCLE = [
	"primary",
	"accent",
	"secondary",
	"destructive"
];
const parseLegacyLinks = (raw) => {
	return (Array.isArray(raw) ? raw : raw.split(/\r?\n/).filter(Boolean)).map((line, index) => {
		const parts = line.split("|").map((s) => s.trim());
		const label = parts[0] ?? "";
		if (!label) return null;
		const url = parts[1] ?? "#";
		const iconName = parts[2] && parts[2].length > 0 ? parts[2] : "Link";
		const colorCandidate = parts[3];
		const iconColor = colorCandidate && isColorOption(colorCandidate) ? colorCandidate : FALLBACK_COLOR_CYCLE[index % FALLBACK_COLOR_CYCLE.length] ?? "primary";
		return {
			id: `link-${index}`,
			label,
			url,
			iconName,
			iconColor
		};
	}).filter((x) => x !== null);
};
const MAX_LINKS = 8;
const resolveLinks = (slots, legacy) => {
	return slots.map((slot, index) => {
		const legacyEntry = legacy[index];
		if (slot.label !== void 0 || slot.url !== void 0 || slot.icon !== void 0 || slot.color !== void 0) {
			if (!(index === 0 || slot.enabled)) return null;
			const label = (slot.label ?? legacyEntry?.label ?? "").trim();
			if (!label) return null;
			const url = slot.url && slot.url.length > 0 ? slot.url : legacyEntry?.url ?? "#";
			const iconName = slot.icon && slot.icon.length > 0 ? slot.icon : legacyEntry?.iconName ?? "Link";
			const iconColor = slot.color ?? legacyEntry?.iconColor ?? FALLBACK_COLOR_CYCLE[index % FALLBACK_COLOR_CYCLE.length] ?? "primary";
			return {
				id: `link-${index}`,
				label,
				url,
				iconName,
				iconColor
			};
		}
		return legacyEntry ?? null;
	}).filter((x) => x !== null);
};
function LinkRow({ link, textColor, borderRadius, openInNewTab, showChevron, iconRadius, layout, isLast, urlVariables }) {
	const Icon = getIcon(link.iconName);
	const wrapperBase = `group relative flex items-center gap-3 py-3 transition-all duration-200`;
	const wrapperCardClasses = `rounded-${borderRadius} px-3 bg-${textColor}/5 hover:bg-${textColor}/10 hover:-translate-y-0.5`;
	const wrapperListClasses = `px-0 hover:bg-${textColor}/5 rounded-md`;
	const wrapperClasses = layout === "cards" ? `${wrapperBase} ${wrapperCardClasses}` : `${wrapperBase} ${wrapperListClasses}`;
	const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
		/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
			"aria-hidden": "true",
			className: `relative flex size-10 shrink-0 items-center justify-center rounded-${iconRadius} text-${link.iconColor}-foreground`,
			style: {
				background: `linear-gradient(135deg, color-mix(in oklch, var(--color-${link.iconColor}) 75%, white 25%) 0%, var(--color-${link.iconColor}) 100%)`,
				boxShadow: `
            inset 0 1px 0 rgba(255,255,255,0.25),
            inset 0 -1px 0 rgba(0,0,0,0.1),
            0 1px 2px color-mix(in oklch, var(--color-${link.iconColor}) 30%, transparent)
          `
			},
			children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
				className: "size-5",
				strokeWidth: 2.25
			})
		}),
		/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
			className: `min-w-0 flex-1 truncate text-[15px] font-bold tracking-[-0.01em] text-${textColor}`,
			children: link.label
		}),
		showChevron && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
			"aria-hidden": "true",
			className: `size-4 shrink-0 text-${textColor}/35 transition-transform duration-200 group-hover:translate-x-0.5 group-hover:text-${textColor}/60`
		})
	] });
	const separator = layout === "list" && !isLast ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
		"aria-hidden": "true",
		className: "ml-[52px]",
		style: { borderBottom: `1px solid color-mix(in oklch, var(--color-${textColor}) 8%, transparent)` }
	}) : null;
	const resolvedUrl = link.url && link.url !== "#" ? substituteUrlVariables(link.url, urlVariables) : link.url;
	const href = resolvedUrl && resolvedUrl !== "#" ? resolvedUrl : void 0;
	if (href) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
		href,
		target: openInNewTab ? "_blank" : void 0,
		rel: openInNewTab ? "noopener noreferrer" : void 0,
		className: wrapperClasses,
		children: content
	}), separator] });
	return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
		className: wrapperClasses,
		children: content
	}), separator] });
}
function QuickLinksWidget({ titleEnabled = true, title = "Quick Links", titleFontSize = "md", titleColor = "foreground", link1Label, link1Url, link1Icon, link1Color, link2Enabled = true, link2Label, link2Url, link2Icon, link2Color, link3Enabled = true, link3Label, link3Url, link3Icon, link3Color, link4Enabled = true, link4Label, link4Url, link4Icon, link4Color, link5Enabled = false, link5Label, link5Url, link5Icon, link5Color, link6Enabled = false, link6Label, link6Url, link6Icon, link6Color, link7Enabled = false, link7Label, link7Url, link7Icon, link7Color, link8Enabled = false, link8Label, link8Url, link8Icon, link8Color, links, layout = "cards", iconRadius = "lg", showChevron = true, openInNewTab = false, background = {
	type: "solid",
	color: "background"
}, textColor = "foreground", padding = 4, borderRadius = "md", borderWidth = "none", borderColor = "muted", className, ...props }) {
	const backgroundColor = background.color || "background";
	const backgroundImage = (background.resource?.image_url || background.resource?.imageUrl) && background.type === "image" ? `url(${background.resource.image_url || background.resource.imageUrl})` : "none";
	const parsed = resolveLinks([
		{
			enabled: true,
			label: link1Label,
			url: link1Url,
			icon: link1Icon,
			color: link1Color
		},
		{
			enabled: link2Enabled,
			label: link2Label,
			url: link2Url,
			icon: link2Icon,
			color: link2Color
		},
		{
			enabled: link3Enabled,
			label: link3Label,
			url: link3Url,
			icon: link3Icon,
			color: link3Color
		},
		{
			enabled: link4Enabled,
			label: link4Label,
			url: link4Url,
			icon: link4Icon,
			color: link4Color
		},
		{
			enabled: link5Enabled,
			label: link5Label,
			url: link5Url,
			icon: link5Icon,
			color: link5Color
		},
		{
			enabled: link6Enabled,
			label: link6Label,
			url: link6Url,
			icon: link6Icon,
			color: link6Color
		},
		{
			enabled: link7Enabled,
			label: link7Label,
			url: link7Url,
			icon: link7Icon,
			color: link7Color
		},
		{
			enabled: link8Enabled,
			label: link8Label,
			url: link8Url,
			icon: link8Icon,
			color: link8Color
		}
	], links ? parseLegacyLinks(links) : []);
	const urlVariables = usePortalUrlVariables();
	return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
		className: `@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} ${require_registries.borderWidthClasses[borderWidth]} ${borderWidth !== "none" ? require_registries.borderColorClasses[borderColor] : ""} ${className ?? ""}`,
		style: { backgroundImage },
		...props,
		children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
			className: `p-${padding} flex flex-col gap-3`,
			children: [titleEnabled && title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
				className: `text-${titleFontSize} leading-tight font-bold tracking-[-0.01em] text-${titleColor}`,
				children: title
			}), parsed.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
				className: `text-[13px] text-${textColor}/55`,
				children: "No links configured."
			}) : layout === "cards" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
				className: "flex flex-col gap-2",
				children: parsed.map((link, idx) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkRow, {
					link,
					textColor,
					borderRadius,
					openInNewTab,
					showChevron,
					iconRadius,
					layout: "cards",
					isLast: idx === parsed.length - 1,
					urlVariables
				}, link.id))
			}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
				className: `flex flex-col overflow-hidden rounded-${borderRadius} bg-${textColor}/5`,
				children: parsed.map((link, idx) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkRow, {
					link,
					textColor,
					borderRadius,
					openInNewTab,
					showChevron,
					iconRadius,
					layout: "list",
					isLast: idx === parsed.length - 1,
					urlVariables
				}, link.id))
			})]
		})
	});
}
const URL_TOKEN_SUGGESTIONS = [
	{
		label: "username",
		value: "username || /signup"
	},
	{
		label: "replicated_url",
		value: "replicated_url"
	},
	{
		label: "external_id",
		value: "external_id || /signup"
	}
];
const SLOT_DEFAULTS = {
	1: {
		label: "Profile",
		icon: "User",
		color: "primary"
	},
	2: {
		label: "Social",
		icon: "Share2",
		color: "accent"
	},
	3: {
		label: "Product Links",
		icon: "ShoppingBag",
		color: "secondary"
	},
	4: {
		label: "Video",
		icon: "Video",
		color: "destructive"
	}
};
function buildLinkSlotFields(slot) {
	const group = `Link ${slot}`;
	const isFirst = slot === 1;
	const defaults = SLOT_DEFAULTS[slot];
	const enabledDefault = slot >= 2 && slot <= 4;
	const requires = isFirst ? void 0 : `link${slot}Enabled`;
	const fields = [];
	if (!isFirst) fields.push({
		key: `link${slot}Enabled`,
		label: `Show Link ${slot}`,
		type: "boolean",
		description: `Display link slot ${slot}`,
		defaultValue: enabledDefault,
		group
	});
	fields.push({
		key: `link${slot}Label`,
		label: "Label",
		type: "text",
		description: "Text shown on the link",
		defaultValue: defaults?.label ?? "",
		group,
		...requires ? { requiresKeyToBeTrue: requires } : {}
	});
	fields.push({
		key: `link${slot}Url`,
		label: "URL",
		type: "text",
		description: "Where the link points (use '#' for a placeholder). Click a chip below to insert a user variable (e.g. `{{username}}`, `{{replicated_url}}`, `{{external_id}}`); append `|| /fallback` to set a fallback path.",
		defaultValue: "#",
		tokenSuggestions: URL_TOKEN_SUGGESTIONS,
		group,
		...requires ? { requiresKeyToBeTrue: requires } : {}
	});
	fields.push({
		key: `link${slot}Icon`,
		label: "Icon",
		type: "select",
		description: "Icon displayed in the colored badge",
		options: ICON_OPTIONS,
		defaultValue: defaults?.icon ?? "Link",
		group,
		...requires ? { requiresKeyToBeTrue: requires } : {}
	});
	fields.push({
		key: `link${slot}Color`,
		label: "Badge Color",
		type: "colorSelect",
		description: "Color of the icon badge",
		defaultValue: defaults?.color ?? FALLBACK_COLOR_CYCLE[(slot - 1) % FALLBACK_COLOR_CYCLE.length] ?? "primary",
		group,
		...requires ? { requiresKeyToBeTrue: requires } : {}
	});
	return fields;
}
const linkSlotFields = Array.from({ length: MAX_LINKS }, (_, i) => buildLinkSlotFields(i + 1)).flat();
const quickLinksWidgetPropertySchema = {
	widgetType: "QuickLinksWidget",
	displayName: "Quick Links",
	fields: [
		{
			key: "titleEnabled",
			label: "Show Title",
			type: "boolean",
			description: "Small heading shown above the link list",
			defaultValue: true,
			group: "Title"
		},
		{
			key: "title",
			label: "Title",
			type: "text",
			description: "Heading shown above the links",
			defaultValue: "Quick Links",
			group: "Title",
			requiresKeyToBeTrue: "titleEnabled"
		},
		require_registries.getFontSizeField({
			key: "titleFontSize",
			label: "Title Font Size",
			description: "Font size for the widget title",
			defaultValue: "md",
			group: "Title",
			requiresKeyToBeTrue: "titleEnabled"
		}),
		require_registries.getColorField({
			key: "titleColor",
			label: "Title Color",
			description: "Color for the widget title",
			defaultValue: "foreground",
			group: "Title",
			requiresKeyToBeTrue: "titleEnabled"
		}),
		...linkSlotFields,
		{
			key: "layout",
			label: "Layout",
			type: "buttonGroup",
			description: "Cards: separated tiles. List: grouped rows with dividers.",
			defaultValue: "cards",
			options: [{
				label: "Cards",
				value: "cards"
			}, {
				label: "List",
				value: "list"
			}],
			group: "Layout"
		},
		require_registries.getBorderRadiusField({
			key: "iconRadius",
			label: "Icon Corner Radius",
			description: "Corner radius for the colored icon badge",
			defaultValue: "lg",
			group: "Layout"
		}),
		{
			key: "showChevron",
			label: "Show Chevron",
			type: "boolean",
			description: "Right-aligned chevron indicating each row is a link",
			defaultValue: true,
			group: "Layout"
		},
		{
			key: "openInNewTab",
			label: "Open in New Tab",
			type: "boolean",
			description: "Open links in a new tab instead of the same window",
			defaultValue: false,
			group: "Layout"
		},
		{
			type: "background",
			key: "background",
			label: "Background",
			description: "Background for the widget container",
			defaultValue: "background",
			group: "Design"
		},
		require_registries.getColorField({
			key: "textColor",
			label: "Text Color",
			description: "Label + chevron color, and the base for row backgrounds (via opacity)",
			defaultValue: "foreground",
			group: "Design"
		}),
		{
			key: "separator",
			type: "separator",
			label: "Separator",
			group: "Design"
		},
		require_registries.getPaddingField({
			key: "padding",
			label: "Padding",
			description: "Padding around the widget",
			defaultValue: 4,
			group: "Design"
		}),
		require_registries.getBorderRadiusField({
			key: "borderRadius",
			label: "Border Radius",
			description: "Widget border radius (also drives row corners in cards layout)",
			defaultValue: "md",
			group: "Design"
		}),
		require_registries.getBorderWidthField({
			key: "borderWidth",
			label: "Border Width",
			description: "Widget border width",
			defaultValue: "none",
			group: "Design"
		}),
		require_registries.getBorderColorField({
			key: "borderColor",
			label: "Border Color",
			description: "Widget border color",
			defaultValue: "muted",
			group: "Design"
		})
	]
};
//#endregion
Object.defineProperty(exports, "PortalUrlVariablesProvider", {
	enumerable: true,
	get: function() {
		return PortalUrlVariablesProvider;
	}
});
Object.defineProperty(exports, "QuickLinksWidget", {
	enumerable: true,
	get: function() {
		return QuickLinksWidget;
	}
});
Object.defineProperty(exports, "QuickLinksWidget_exports", {
	enumerable: true,
	get: function() {
		return QuickLinksWidget_exports;
	}
});
Object.defineProperty(exports, "quickLinksWidgetPropertySchema", {
	enumerable: true,
	get: function() {
		return quickLinksWidgetPropertySchema;
	}
});

//# sourceMappingURL=QuickLinksWidget-DpsH0cSD.cjs.map