@bravostudioai/react 0.1.35 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","sources":["../../src/codegen/parser.ts"],"sourcesContent":["import {\n ComponentInfo,\n SliderInfo,\n InputGroupInfo,\n FormInfo,\n SelectInputInfo,\n ActionButtonInfo,\n} from \"./types\";\nimport { qualifyPropNames } from \"./propQualification\";\n\n/**\n * Sanitizes a component name into a valid camelCase prop name\n *\n * Removes special characters, handles spaces, and converts to camelCase.\n *\n * @param name - Raw component name from Figma/design tool\n * @returns Valid JavaScript property name\n *\n * @example\n * sanitizePropName(\"My Component!\") // \"myComponent\"\n * sanitizePropName(\"user-name\") // \"userName\"\n */\nexport function sanitizePropName(name: string): string {\n // Convert to camelCase and remove invalid characters\n const cleaned = name\n .replace(/[^a-zA-Z0-9\\s]/g, \"\") // Remove special chars\n .trim();\n\n if (!cleaned) return \"item\";\n\n return cleaned\n .split(/\\s+/)\n .map((word, index) => {\n if (!word) return \"\";\n // Handle all-uppercase words (like \"SHOP\", \"NOW\") by lowercasing them first\n const normalizedWord =\n word === word.toUpperCase() && word.length > 1\n ? word.toLowerCase()\n : word;\n const firstChar = normalizedWord.charAt(0);\n const rest = normalizedWord.slice(1);\n if (index === 0) {\n return firstChar.toLowerCase() + rest;\n }\n return firstChar.toUpperCase() + rest;\n })\n .join(\"\")\n .replace(/^[0-9]/, \"_$&\"); // Prefix numbers with underscore\n}\n\nexport function generateQualifiedPropName(\n componentName: string,\n parentPath: string[]\n): string {\n // Start with the component's own name\n const baseName = sanitizePropName(componentName);\n\n // If no parent path, just return the base name\n if (parentPath.length === 0) {\n return baseName;\n }\n\n // Filter out empty parts and reverse so we build from root to leaf\n const validParentParts = parentPath\n .filter((part) => part && part.trim())\n .reverse();\n\n if (validParentParts.length === 0) {\n return baseName;\n }\n\n // Build qualified name: parent1Parent2ComponentName\n // Each parent part is sanitized individually, then combined\n const sanitizedParentParts = validParentParts.map((part) =>\n sanitizePropName(part)\n );\n\n // Join parent parts (all start uppercase) with base name (starts lowercase)\n const parentPrefix = sanitizedParentParts\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n\n return parentPrefix + baseName;\n}\n\n/**\n * Finds the minimal distinguishing path suffix for a component when compared to others.\n * Returns the shortest suffix (from root side, working towards leaf) that makes this path unique.\n *\n * The algorithm finds where paths first diverge from the root, then takes the minimal\n * distinguishing part from that divergence point towards the leaf.\n */\nexport function findMinimalDistinguishingPath(\n thisPath: string[],\n otherPaths: string[][]\n): string[] {\n if (otherPaths.length === 0) {\n // No other paths to compare, return empty (no qualification needed)\n return [];\n }\n\n // Find the longest common prefix (from root side)\n let commonPrefixLength = 0;\n const maxCommonLength = Math.min(\n thisPath.length,\n ...otherPaths.map((p) => p.length)\n );\n\n for (let i = 0; i < maxCommonLength; i++) {\n const thisPart = thisPath[i];\n // Check if all other paths have the same part at this position\n const allMatch = otherPaths.every((otherPath) => {\n return otherPath[i] === thisPart;\n });\n\n if (allMatch) {\n commonPrefixLength++;\n } else {\n break;\n }\n }\n\n // The distinguishing part starts after the common prefix\n const distinguishingSuffix = thisPath.slice(commonPrefixLength);\n\n // Now find the minimal suffix that's unique\n // Try progressively shorter suffixes (from root side) until we find one that's unique\n for (\n let suffixLength = 1;\n suffixLength <= distinguishingSuffix.length;\n suffixLength++\n ) {\n const thisSuffix = distinguishingSuffix.slice(0, suffixLength);\n\n // Check if this suffix is unique when combined with the common prefix\n const isUnique = otherPaths.every((otherPath) => {\n // If other path is shorter than common prefix + suffix, it can't match\n if (otherPath.length < commonPrefixLength + suffixLength) {\n return true; // Different length means unique\n }\n // Check if the suffix matches at the divergence point\n const otherSuffix = otherPath.slice(\n commonPrefixLength,\n commonPrefixLength + suffixLength\n );\n return !arraysEqual(thisSuffix, otherSuffix);\n });\n\n if (isUnique) {\n // Found minimal distinguishing suffix\n return thisSuffix;\n }\n }\n\n // If we get here, paths are identical (shouldn't happen, but handle it)\n return distinguishingSuffix;\n}\n\n/**\n * Helper to compare two arrays for equality\n */\nexport function arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => val === b[idx]);\n}\n\nexport function getComponentPropType(\n componentType: string,\n _componentName: string\n): string {\n if (componentType === \"component:image\") {\n return \"string\"; // imageUrl\n }\n if (componentType === \"component:text\") {\n return \"string\"; // text\n }\n if (componentType?.startsWith(\"component:input-\")) {\n // Input types generally return strings\n if (componentType === \"component:input-image\") {\n return \"string\"; // image URL\n }\n return \"string\"; // text inputs, email, password, etc.\n }\n // Default to any for unknown types\n return \"any\";\n}\n\nexport function getComponentPropName(componentType: string): string {\n if (componentType === \"component:image\") {\n return \"imageUrl\";\n }\n if (componentType === \"component:text\") {\n return \"text\";\n }\n return \"value\";\n}\n\nexport function findSlidersAndDataBindings(pageData: any): SliderInfo[] {\n const sliders: SliderInfo[] = [];\n\n function traverse(node: any, path: string[] = []): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is a slider container\n if (node.type === \"container:slider\") {\n const slider: SliderInfo = {\n id: node.id,\n name: node.name || \"Slider\",\n arrayContainer: null,\n };\n\n // Recursively look for containers with encore:data:array tag inside the slider\n let arrayContainer: any = null;\n\n const findArrayContainer = (containerNode: any): void => {\n if (arrayContainer) return; // Already found one\n\n if (!containerNode || typeof containerNode !== \"object\") return;\n\n // Check if this node is the array container\n if (\n Array.isArray(containerNode.tags) &&\n (containerNode.tags.includes(\"encore:data:array\") ||\n containerNode.tags.includes(\"bravo:data:array\"))\n ) {\n arrayContainer = containerNode;\n return;\n }\n\n // Recursively search children\n if (containerNode.body && Array.isArray(containerNode.body)) {\n containerNode.body.forEach(findArrayContainer);\n }\n if (\n containerNode.containers &&\n Array.isArray(containerNode.containers)\n ) {\n containerNode.containers.forEach(findArrayContainer);\n }\n if (\n containerNode.components &&\n Array.isArray(containerNode.components)\n ) {\n containerNode.components.forEach(findArrayContainer);\n }\n };\n\n // Start search from the slider node itself (checking its children)\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach(findArrayContainer);\n }\n // Also check components if they exist directly\n if (\n !arrayContainer &&\n node.components &&\n Array.isArray(node.components)\n ) {\n node.components.forEach(findArrayContainer);\n }\n\n if (arrayContainer) {\n const container = arrayContainer;\n let components: ComponentInfo[] = [];\n\n // Find all components with encore:data tag, and also image components\n const imageComponents: any[] = [];\n\n const findDataComponents = (\n comp: any,\n parentPath: string[] = []\n ): void => {\n if (!comp || typeof comp !== \"object\") return;\n\n // Track image components separately (they might not have encore:data tag)\n if (comp.type === \"component:image\") {\n imageComponents.push(comp);\n }\n\n if (\n Array.isArray(comp.tags) &&\n (comp.tags.includes(\"encore:data\") ||\n comp.tags.includes(\"bravo:data\"))\n ) {\n const basePropName = sanitizePropName(comp.name || \"item\");\n const propType = getComponentPropType(comp.type, comp.name);\n // const propKey = getComponentPropName(comp.type);\n\n components.push({\n id: comp.id,\n name: comp.name || \"Unnamed\",\n type: comp.type,\n tags: comp.tags || [],\n propName: basePropName, // Will be qualified later if needed\n propType,\n // Store parent path for later qualification\n _parentPath: [...parentPath],\n } as ComponentInfo & { _parentPath: string[] });\n }\n\n // Build parent path: include this node's name if it's a container/component with a name\n // Skip generic \"Frame\" names - they're usually not meaningful for distinction\n const currentParentPath = [...parentPath];\n if (\n comp.name &&\n (comp.type?.startsWith(\"container:\") ||\n comp.type?.startsWith(\"component:\"))\n ) {\n const name = comp.name.trim();\n // Filter out generic \"Frame\" names (case-insensitive, with or without numbers/spaces)\n // But keep meaningful names like \"TripSlideFrame\" that contain other words\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(comp.name);\n }\n }\n\n // Recursively search children\n if (comp.body && Array.isArray(comp.body)) {\n comp.body.forEach((child: any) =>\n findDataComponents(child, currentParentPath)\n );\n }\n if (comp.containers && Array.isArray(comp.containers)) {\n comp.containers.forEach((child: any) =>\n findDataComponents(child, currentParentPath)\n );\n }\n if (comp.components && Array.isArray(comp.components)) {\n comp.components.forEach((child: any) =>\n findDataComponents(child, currentParentPath)\n );\n }\n };\n\n if (container.components && Array.isArray(container.components)) {\n container.components.forEach((comp: any) =>\n findDataComponents(comp, [])\n );\n }\n\n // After finding all components, if we have image components but no image with encore:data,\n // add the first image component\n const hasImageWithData = components.some(\n (c) => c.type === \"component:image\"\n );\n if (!hasImageWithData && imageComponents.length > 0) {\n const imageComp = imageComponents[0];\n // For image components, use \"imageUrl\" as the prop name\n // Clean the name first, then if it contains \"image\", just use \"imageUrl\"\n const rawName = (imageComp.name || \"image\").toLowerCase();\n const basePropName = rawName.includes(\"image\")\n ? \"imageUrl\"\n : sanitizePropName(imageComp.name || \"image\");\n components.push({\n id: imageComp.id,\n name: imageComp.name || \"Image\",\n type: imageComp.type,\n tags: imageComp.tags || [],\n propName: basePropName, // Will be qualified later if needed\n propType: \"string\", // imageUrl is always string\n _parentPath: [],\n } as ComponentInfo & { _parentPath: string[] });\n }\n\n // Qualify duplicate prop names using minimal distinguishing paths\n qualifyPropNames(components);\n\n // If we have an image component, remove color components with similar names\n // (they're usually placeholders/backgrounds)\n if (imageComponents.length > 0) {\n const imageComp = imageComponents[0];\n const imageName = (imageComp.name || \"\").toLowerCase();\n components = components.filter((comp) => {\n // Keep image components\n if (comp.type === \"component:image\") return true;\n // Remove color components that seem to be placeholders for images\n if (comp.type === \"component:color\") {\n const compName = (comp.name || \"\").toLowerCase();\n // If color component name is similar to image name, it's likely a placeholder\n if (imageName.includes(compName) || compName.includes(\"image\")) {\n return false;\n }\n }\n return true;\n });\n }\n\n slider.arrayContainer = {\n id: container.id,\n name: container.name || \"Item\",\n propName: sanitizePropName(container.name || \"items\"),\n components,\n };\n }\n\n sliders.push(slider);\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) => traverse(child, [...path, \"body\"]));\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, [...path, \"containers\"])\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, [...path, \"components\"])\n );\n }\n }\n\n // Start traversal from page data\n // Try multiple possible locations for the body\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n return sliders;\n}\n\n/**\n * Finds standalone data-bound components (not in sliders)\n *\n * Locates components tagged with encore:data (but not encore:data:array)\n * for standalone data binding at the page level.\n *\n * @param pageData - Page definition from Encore service\n * @returns Array of component metadata\n */\nexport function findStandaloneComponents(pageData: any): ComponentInfo[] {\n const components: ComponentInfo[] = [];\n const sliderIds = new Set<string>();\n\n // First, collect all slider IDs to exclude their children\n function collectSliderIds(node: any): void {\n if (!node || typeof node !== \"object\") return;\n\n if (node.type === \"container:slider\") {\n sliderIds.add(node.id);\n }\n\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach(collectSliderIds);\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach(collectSliderIds);\n }\n }\n\n // Traverse to find standalone components with bravo:data tags\n // Track parent component names for qualification\n function traverse(\n node: any,\n parentId?: string,\n parentPath: string[] = []\n ): void {\n if (!node || typeof node !== \"object\") return;\n\n // Skip if we're inside a slider\n if (parentId && sliderIds.has(parentId)) return;\n\n // Check if this component has bravo:data tag\n if (\n Array.isArray(node.tags) &&\n (node.tags.includes(\"encore:data\") || node.tags.includes(\"bravo:data\")) &&\n (node.type === \"component:text\" || node.type === \"component:image\")\n ) {\n const basePropName = sanitizePropName(node.name || \"item\");\n const propType = getComponentPropType(node.type, node.name);\n\n components.push({\n id: node.id,\n name: node.name || \"Unnamed\",\n type: node.type,\n tags: node.tags || [],\n propName: basePropName, // Will be qualified later if needed\n propType,\n // Store parent path for later qualification\n _parentPath: [...parentPath],\n } as ComponentInfo & { _parentPath: string[] });\n }\n\n // Build parent path: include this node's name if it's a container/component with a name\n // Skip generic \"Frame\" names - they're usually not meaningful for distinction\n const currentParentPath = [...parentPath];\n if (\n node.name &&\n (node.type?.startsWith(\"container:\") ||\n node.type?.startsWith(\"component:\"))\n ) {\n const name = node.name.trim();\n // Filter out generic \"Frame\" names (case-insensitive, with or without numbers/spaces)\n // But keep meaningful names like \"TripSlideFrame\" that contain other words\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(node.name);\n }\n }\n\n // Recursively traverse children\n const currentId = node.id;\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) =>\n traverse(child, currentId, currentParentPath)\n );\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, currentId, currentParentPath)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, currentId, currentParentPath)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach(collectSliderIds);\n body.forEach((node: any) => traverse(node));\n }\n\n // Qualify duplicate prop names using minimal distinguishing paths\n qualifyPropNames(components);\n\n return components;\n}\n\n/**\n * Finds input groups (radio button-like components) in the page\n *\n * Locates stateful sets tagged with encore:input-group for coordinated\n * selection behavior.\n *\n * @param pageData - Page definition from Encore service\n * @returns Array of input group metadata\n */\nexport function findInputGroups(pageData: any): InputGroupInfo[] {\n const groupsMap = new Map<string, InputGroupInfo>();\n\n function traverse(node: any): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is an input-stateful-set with input-group tag\n if (\n node.type === \"component:input-stateful-set\" &&\n Array.isArray(node.tags)\n ) {\n const inputGroupTag = node.tags.find((tag: string) =>\n tag.startsWith(\"input-group:\")\n );\n if (inputGroupTag) {\n const parts = inputGroupTag.split(\":\");\n if (parts.length >= 3) {\n const groupType = parts[1];\n const groupName = parts[2];\n\n if (!groupsMap.has(groupName)) {\n groupsMap.set(groupName, {\n groupName,\n groupType,\n elements: [],\n });\n }\n\n const group = groupsMap.get(groupName)!;\n group.elements.push({\n id: node.id,\n name: node.name || \"Unnamed\",\n });\n }\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach(traverse);\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach(traverse);\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach(traverse);\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n return Array.from(groupsMap.values());\n}\n\n/**\n * Finds forms and their input fields in the page\n *\n * Locates containers tagged with encore:form and extracts all input\n * components within them for form submission handling.\n *\n * @param pageData - Page definition from Encore service\n * @returns Array of form metadata with input fields\n */\nexport function findForms(pageData: any): FormInfo[] {\n const forms: FormInfo[] = [];\n\n function traverse(node: any, parentContainer?: any): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is a container that might be a form\n const isContainer =\n node.type?.startsWith(\"container:\") || node.type === \"container:default\";\n const isNamedForm =\n node.name?.toLowerCase().includes(\"form\") ||\n (Array.isArray(node.tags) && node.tags.includes(\"form\"));\n\n // Check if this container or any child has a submit action\n let hasSubmitAction = false;\n let submitButtonId: string | undefined;\n\n function checkForSubmitAction(n: any): void {\n if (!n || typeof n !== \"object\") return;\n\n // Check if this node has a submit action\n if (\n Array.isArray(n.tags) &&\n (n.tags.includes(\"action:submit\") || n.tags.includes(\"submit\"))\n ) {\n hasSubmitAction = true;\n submitButtonId = n.id;\n return;\n }\n\n // Check actions\n if (n.actions?.tap?.action === \"submit\") {\n hasSubmitAction = true;\n submitButtonId = n.id;\n return;\n }\n\n // Recursively check children\n if (n.components && Array.isArray(n.components)) {\n n.components.forEach(checkForSubmitAction);\n }\n if (n.body && Array.isArray(n.body)) {\n n.body.forEach(checkForSubmitAction);\n }\n }\n\n // If this looks like a form container, check for submit actions\n if (isContainer && (isNamedForm || parentContainer === undefined)) {\n checkForSubmitAction(node);\n }\n\n // If we found a form container (has submit action or is named \"form\")\n if (isContainer && (hasSubmitAction || isNamedForm)) {\n const inputs: FormInfo[\"inputs\"] = [];\n\n // Find all input components within this container\n const findInputs = (n: any, parentPath: string[] = []): void => {\n if (!n || typeof n !== \"object\") return;\n\n // Check if this is an input component\n if (\n n.type?.startsWith(\"component:input-\") ||\n n.type === \"component:input-text\" ||\n n.type === \"component:input-image\" ||\n n.type === \"component:input-email\" ||\n n.type === \"component:input-password\" ||\n n.type === \"component:input-select\"\n ) {\n const basePropName = sanitizePropName(n.name || \"Unnamed input\");\n inputs.push({\n id: n.id,\n name: n.name || \"Unnamed input\",\n type: n.type,\n propName: basePropName, // Will be qualified later if needed\n _parentPath: [...parentPath], // Store parent path for qualification\n });\n }\n\n // Build parent path: include this node's name if it's a container/component with a name\n // Skip generic \"Frame\" names - they're usually not meaningful for distinction\n const currentParentPath = [...parentPath];\n if (\n n.name &&\n (n.type?.startsWith(\"container:\") || n.type?.startsWith(\"component:\"))\n ) {\n const name = n.name.trim();\n // Filter out generic \"Frame\" names (case-insensitive, with or without numbers/spaces)\n // But keep meaningful names like \"TripSlideFrame\" that contain other words\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(n.name);\n }\n }\n\n // Recursively search children\n if (n.components && Array.isArray(n.components)) {\n n.components.forEach((child: any) =>\n findInputs(child, currentParentPath)\n );\n }\n if (n.body && Array.isArray(n.body)) {\n n.body.forEach((child: any) => findInputs(child, currentParentPath));\n }\n };\n\n findInputs(node, []);\n\n // Only add form if it has inputs\n if (inputs.length > 0) {\n forms.push({\n formId: node.id,\n formName: node.name || \"Form\",\n submitButtonId,\n inputs,\n });\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) =>\n traverse(child, isContainer ? node : parentContainer)\n );\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, isContainer ? node : parentContainer)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, isContainer ? node : parentContainer)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n return forms;\n}\n\n/**\n * Finds standalone select input components (input-select) that are NOT inside forms.\n * These should be exposed as controlled inputs with value and onChange props.\n */\nexport function findStandaloneSelectInputs(\n pageData: any,\n forms: FormInfo[]\n): SelectInputInfo[] {\n const selectInputs: SelectInputInfo[] = [];\n\n // Collect all input IDs that are already in forms\n const formInputIds = new Set<string>();\n forms.forEach((form) => {\n form.inputs.forEach((input) => {\n formInputIds.add(input.id);\n });\n });\n\n // Traverse to find input-select components not in forms\n function traverse(node: any, parentPath: string[] = []): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is an input-select component\n if (node.type === \"component:input-select\" && !formInputIds.has(node.id)) {\n const basePropName = sanitizePropName(node.name || \"selectInput\");\n selectInputs.push({\n id: node.id,\n name: node.name || \"Select Input\",\n propName: basePropName,\n _parentPath: [...parentPath],\n });\n }\n\n // Build parent path for qualification\n const currentParentPath = [...parentPath];\n if (\n node.name &&\n (node.type?.startsWith(\"container:\") ||\n node.type?.startsWith(\"component:\"))\n ) {\n const name = node.name.trim();\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(node.name);\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) => traverse(child, currentParentPath));\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n // Qualify duplicate prop names\n qualifySelectInputs(selectInputs);\n\n return selectInputs;\n}\n\n/**\n * Qualifies select input prop names to ensure uniqueness.\n */\nfunction qualifySelectInputs(selectInputs: SelectInputInfo[]): void {\n qualifyPropNames(selectInputs);\n}\n\n/**\n * Finds action buttons - components that have action tags (action:remote, action:link, etc.)\n * or have actions defined. These should be exposed with onClick handlers.\n */\nexport function findActionButtons(pageData: any): ActionButtonInfo[] {\n const buttons: ActionButtonInfo[] = [];\n\n function traverse(node: any, parentPath: string[] = []): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this component has an action tag or actions defined\n const hasActionTag =\n Array.isArray(node.tags) &&\n node.tags.some((tag: string) => tag.startsWith(\"action:\"));\n const hasActions = node.actions && typeof node.actions === \"object\";\n\n if (hasActionTag || hasActions) {\n // Determine the action type\n let actionType = \"tap\";\n if (Array.isArray(node.tags)) {\n const actionTag = node.tags.find((tag: string) =>\n tag.startsWith(\"action:\")\n );\n if (actionTag) {\n actionType = actionTag.replace(\"action:\", \"\");\n }\n }\n if (node.actions?.tap?.action) {\n actionType = node.actions.tap.action;\n }\n\n const basePropName = sanitizePropName(node.name || \"button\");\n buttons.push({\n id: node.id,\n name: node.name || \"Button\",\n propName: basePropName,\n actionType,\n _parentPath: [...parentPath],\n });\n }\n\n // Build parent path for qualification\n const currentParentPath = [...parentPath];\n if (\n node.name &&\n (node.type?.startsWith(\"container:\") ||\n node.type?.startsWith(\"component:\"))\n ) {\n const name = node.name.trim();\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(node.name);\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) => traverse(child, currentParentPath));\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n // Qualify duplicate prop names\n qualifyActionButtons(buttons);\n\n return buttons;\n}\n\n/**\n * Qualifies action button prop names to ensure uniqueness.\n */\nfunction qualifyActionButtons(buttons: ActionButtonInfo[]): void {\n qualifyPropNames(buttons);\n}\n\n/**\n * Qualifies form input prop names to ensure uniqueness within each form.\n * Only qualifies where necessary, using minimal distinguishing paths.\n */\nexport function qualifyFormInputs(forms: FormInfo[]): void {\n forms.forEach((form) => {\n qualifyPropNames(form.inputs);\n });\n}\n"],"names":["sanitizePropName","name","cleaned","word","index","normalizedWord","firstChar","rest","generateQualifiedPropName","componentName","parentPath","baseName","validParentParts","part","findMinimalDistinguishingPath","thisPath","otherPaths","commonPrefixLength","maxCommonLength","p","i","thisPart","otherPath","distinguishingSuffix","suffixLength","thisSuffix","otherSuffix","arraysEqual","a","b","val","idx","getComponentPropType","componentType","_componentName","getComponentPropName","findSlidersAndDataBindings","pageData","sliders","traverse","node","path","slider","arrayContainer","findArrayContainer","containerNode","container","components","imageComponents","findDataComponents","comp","basePropName","propType","currentParentPath","isGenericFrame","child","c","imageComp","qualifyPropNames","imageName","compName","body","findStandaloneComponents","sliderIds","collectSliderIds","parentId","currentId","findInputGroups","groupsMap","inputGroupTag","tag","parts","groupType","groupName","findForms","forms","parentContainer","isContainer","isNamedForm","hasSubmitAction","submitButtonId","checkForSubmitAction","inputs","findInputs","n","findStandaloneSelectInputs","selectInputs","formInputIds","form","input","qualifySelectInputs","findActionButtons","buttons","hasActionTag","hasActions","actionType","actionTag","qualifyActionButtons","qualifyFormInputs"],"mappings":"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"}
1
+ {"version":3,"file":"parser.js","sources":["../../src/codegen/parser.ts"],"sourcesContent":["import {\n ComponentInfo,\n SliderInfo,\n InputGroupInfo,\n FormInfo,\n SelectInputInfo,\n ActionButtonInfo,\n} from \"./types\";\nimport { qualifyPropNames } from \"./propQualification\";\n\n/**\n * Sanitizes a component name into a valid camelCase prop name\n *\n * Removes special characters, handles spaces, and converts to camelCase.\n *\n * @param name - Raw component name from Figma/design tool\n * @returns Valid JavaScript property name\n *\n * @example\n * sanitizePropName(\"My Component!\") // \"myComponent\"\n * sanitizePropName(\"user-name\") // \"userName\"\n */\nexport function sanitizePropName(name: string): string {\n // Convert to camelCase and remove invalid characters\n const cleaned = name\n .replace(/[^a-zA-Z0-9\\s]/g, \"\") // Remove special chars\n .trim();\n\n if (!cleaned) return \"item\";\n\n return cleaned\n .split(/\\s+/)\n .map((word, index) => {\n if (!word) return \"\";\n // Handle all-uppercase words (like \"SHOP\", \"NOW\") by lowercasing them first\n const normalizedWord =\n word === word.toUpperCase() && word.length > 1\n ? word.toLowerCase()\n : word;\n const firstChar = normalizedWord.charAt(0);\n const rest = normalizedWord.slice(1);\n if (index === 0) {\n return firstChar.toLowerCase() + rest;\n }\n return firstChar.toUpperCase() + rest;\n })\n .join(\"\")\n .replace(/^[0-9]/, \"_$&\"); // Prefix numbers with underscore\n}\n\nexport function generateQualifiedPropName(\n componentName: string,\n parentPath: string[]\n): string {\n // Start with the component's own name\n const baseName = sanitizePropName(componentName);\n\n // If no parent path, just return the base name\n if (parentPath.length === 0) {\n return baseName;\n }\n\n // Filter out empty parts and reverse so we build from root to leaf\n const validParentParts = parentPath\n .filter((part) => part && part.trim())\n .reverse();\n\n if (validParentParts.length === 0) {\n return baseName;\n }\n\n // Build qualified name: parent1Parent2ComponentName\n // Each parent part is sanitized individually, then combined\n const sanitizedParentParts = validParentParts.map((part) =>\n sanitizePropName(part)\n );\n\n // Join parent parts (all start uppercase) with base name (starts lowercase)\n const parentPrefix = sanitizedParentParts\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\"\");\n\n return parentPrefix + baseName;\n}\n\n/**\n * Finds the minimal distinguishing path suffix for a component when compared to others.\n * Returns the shortest suffix (from root side, working towards leaf) that makes this path unique.\n *\n * The algorithm finds where paths first diverge from the root, then takes the minimal\n * distinguishing part from that divergence point towards the leaf.\n */\nexport function findMinimalDistinguishingPath(\n thisPath: string[],\n otherPaths: string[][]\n): string[] {\n if (otherPaths.length === 0) {\n // No other paths to compare, return empty (no qualification needed)\n return [];\n }\n\n // Find the longest common prefix (from root side)\n let commonPrefixLength = 0;\n const maxCommonLength = Math.min(\n thisPath.length,\n ...otherPaths.map((p) => p.length)\n );\n\n for (let i = 0; i < maxCommonLength; i++) {\n const thisPart = thisPath[i];\n // Check if all other paths have the same part at this position\n const allMatch = otherPaths.every((otherPath) => {\n return otherPath[i] === thisPart;\n });\n\n if (allMatch) {\n commonPrefixLength++;\n } else {\n break;\n }\n }\n\n // The distinguishing part starts after the common prefix\n const distinguishingSuffix = thisPath.slice(commonPrefixLength);\n\n // Now find the minimal suffix that's unique\n // Try progressively shorter suffixes (from root side) until we find one that's unique\n for (\n let suffixLength = 1;\n suffixLength <= distinguishingSuffix.length;\n suffixLength++\n ) {\n const thisSuffix = distinguishingSuffix.slice(0, suffixLength);\n\n // Check if this suffix is unique when combined with the common prefix\n const isUnique = otherPaths.every((otherPath) => {\n // If other path is shorter than common prefix + suffix, it can't match\n if (otherPath.length < commonPrefixLength + suffixLength) {\n return true; // Different length means unique\n }\n // Check if the suffix matches at the divergence point\n const otherSuffix = otherPath.slice(\n commonPrefixLength,\n commonPrefixLength + suffixLength\n );\n return !arraysEqual(thisSuffix, otherSuffix);\n });\n\n if (isUnique) {\n // Found minimal distinguishing suffix\n return thisSuffix;\n }\n }\n\n // If we get here, paths are identical (shouldn't happen, but handle it)\n return distinguishingSuffix;\n}\n\n/**\n * Helper to compare two arrays for equality\n */\nexport function arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false;\n return a.every((val, idx) => val === b[idx]);\n}\n\nexport function getComponentPropType(\n componentType: string,\n _componentName: string\n): string {\n if (componentType === \"component:image\") {\n return \"string\"; // imageUrl\n }\n if (componentType === \"component:text\") {\n return \"string\"; // text\n }\n if (componentType?.startsWith(\"component:input-\")) {\n // Input types generally return strings\n if (componentType === \"component:input-image\") {\n return \"string\"; // image URL\n }\n return \"string\"; // text inputs, email, password, etc.\n }\n if (\n componentType === \"component:webview\" ||\n componentType === \"component:web-view\"\n ) {\n return \"string\"; // url\n }\n if (componentType === \"component:video\") {\n return \"string\"; // videoUrl\n }\n if (componentType === \"component:video\") {\n return \"string\"; // videoUrl\n }\n if (componentType === \"component:embed\") {\n return \"React.ReactNode\";\n }\n // Default to any for unknown types\n return \"any\";\n}\n\nexport function getComponentPropName(componentType: string): string {\n if (componentType === \"component:image\") {\n return \"imageUrl\";\n }\n if (componentType === \"component:text\") {\n return \"text\";\n }\n if (\n componentType === \"component:webview\" ||\n componentType === \"component:web-view\"\n ) {\n return \"url\";\n }\n if (componentType === \"component:video\") {\n return \"videoUrl\";\n }\n return \"value\";\n}\n\nexport function findSlidersAndDataBindings(pageData: any): SliderInfo[] {\n const sliders: SliderInfo[] = [];\n\n function traverse(node: any, path: string[] = []): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is a slider container\n if (node.type === \"container:slider\") {\n const slider: SliderInfo = {\n id: node.id,\n name: node.name || \"Slider\",\n arrayContainer: null,\n };\n\n // Recursively look for containers with encore:data:array tag inside the slider\n let arrayContainer: any = null;\n\n const findArrayContainer = (containerNode: any): void => {\n if (arrayContainer) return; // Already found one\n\n if (!containerNode || typeof containerNode !== \"object\") return;\n\n // Check if this node is the array container\n if (\n Array.isArray(containerNode.tags) &&\n (containerNode.tags.includes(\"encore:data:array\") ||\n containerNode.tags.includes(\"bravo:data:array\"))\n ) {\n arrayContainer = containerNode;\n return;\n }\n\n // Recursively search children\n if (containerNode.body && Array.isArray(containerNode.body)) {\n containerNode.body.forEach(findArrayContainer);\n }\n if (\n containerNode.containers &&\n Array.isArray(containerNode.containers)\n ) {\n containerNode.containers.forEach(findArrayContainer);\n }\n if (\n containerNode.components &&\n Array.isArray(containerNode.components)\n ) {\n containerNode.components.forEach(findArrayContainer);\n }\n };\n\n // Start search from the slider node itself (checking its children)\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach(findArrayContainer);\n }\n // Also check components if they exist directly\n if (\n !arrayContainer &&\n node.components &&\n Array.isArray(node.components)\n ) {\n node.components.forEach(findArrayContainer);\n }\n\n if (arrayContainer) {\n const container = arrayContainer;\n let components: ComponentInfo[] = [];\n\n // Find all components with encore:data tag, and also image components\n const imageComponents: any[] = [];\n\n const findDataComponents = (\n comp: any,\n parentPath: string[] = []\n ): void => {\n if (!comp || typeof comp !== \"object\") return;\n\n // Track image components separately (they might not have encore:data tag)\n if (comp.type === \"component:image\") {\n imageComponents.push(comp);\n }\n\n if (\n Array.isArray(comp.tags) &&\n (comp.tags.includes(\"encore:data\") ||\n comp.tags.includes(\"bravo:data\"))\n ) {\n const basePropName = sanitizePropName(comp.name || \"item\");\n const propType = getComponentPropType(comp.type, comp.name);\n // const propKey = getComponentPropName(comp.type);\n\n components.push({\n id: comp.id,\n name: comp.name || \"Unnamed\",\n type: comp.type,\n tags: comp.tags || [],\n propName: basePropName, // Will be qualified later if needed\n propType,\n // Store parent path for later qualification\n _parentPath: [...parentPath],\n } as ComponentInfo & { _parentPath: string[] });\n }\n\n // Build parent path: include this node's name if it's a container/component with a name\n // Skip generic \"Frame\" names - they're usually not meaningful for distinction\n const currentParentPath = [...parentPath];\n if (\n comp.name &&\n (comp.type?.startsWith(\"container:\") ||\n comp.type?.startsWith(\"component:\"))\n ) {\n const name = comp.name.trim();\n // Filter out generic \"Frame\" names (case-insensitive, with or without numbers/spaces)\n // But keep meaningful names like \"TripSlideFrame\" that contain other words\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(comp.name);\n }\n }\n\n // Recursively search children\n if (comp.body && Array.isArray(comp.body)) {\n comp.body.forEach((child: any) =>\n findDataComponents(child, currentParentPath)\n );\n }\n if (comp.containers && Array.isArray(comp.containers)) {\n comp.containers.forEach((child: any) =>\n findDataComponents(child, currentParentPath)\n );\n }\n if (comp.components && Array.isArray(comp.components)) {\n comp.components.forEach((child: any) =>\n findDataComponents(child, currentParentPath)\n );\n }\n };\n\n if (container.components && Array.isArray(container.components)) {\n container.components.forEach((comp: any) =>\n findDataComponents(comp, [])\n );\n }\n\n // After finding all components, if we have image components but no image with encore:data,\n // add the first image component\n const hasImageWithData = components.some(\n (c) => c.type === \"component:image\"\n );\n if (!hasImageWithData && imageComponents.length > 0) {\n const imageComp = imageComponents[0];\n // For image components, use \"imageUrl\" as the prop name\n // Clean the name first, then if it contains \"image\", just use \"imageUrl\"\n const rawName = (imageComp.name || \"image\").toLowerCase();\n const basePropName = rawName.includes(\"image\")\n ? \"imageUrl\"\n : sanitizePropName(imageComp.name || \"image\");\n components.push({\n id: imageComp.id,\n name: imageComp.name || \"Image\",\n type: imageComp.type,\n tags: imageComp.tags || [],\n propName: basePropName, // Will be qualified later if needed\n propType: \"string\", // imageUrl is always string\n _parentPath: [],\n } as ComponentInfo & { _parentPath: string[] });\n }\n\n // Qualify duplicate prop names using minimal distinguishing paths\n qualifyPropNames(components);\n\n // If we have an image component, remove color components with similar names\n // (they're usually placeholders/backgrounds)\n if (imageComponents.length > 0) {\n const imageComp = imageComponents[0];\n const imageName = (imageComp.name || \"\").toLowerCase();\n components = components.filter((comp) => {\n // Keep image components\n if (comp.type === \"component:image\") return true;\n // Remove color components that seem to be placeholders for images\n if (comp.type === \"component:color\") {\n const compName = (comp.name || \"\").toLowerCase();\n // If color component name is similar to image name, it's likely a placeholder\n if (imageName.includes(compName) || compName.includes(\"image\")) {\n return false;\n }\n }\n return true;\n });\n }\n\n slider.arrayContainer = {\n id: container.id,\n name: container.name || \"Item\",\n propName: sanitizePropName(container.name || \"items\"),\n components,\n };\n }\n\n sliders.push(slider);\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) => traverse(child, [...path, \"body\"]));\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, [...path, \"containers\"])\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, [...path, \"components\"])\n );\n }\n }\n\n // Start traversal from page data\n // Try multiple possible locations for the body\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n return sliders;\n}\n\n/**\n * Finds standalone data-bound components (not in sliders)\n *\n * Locates components tagged with encore:data (but not encore:data:array)\n * for standalone data binding at the page level.\n *\n * @param pageData - Page definition from Encore service\n * @returns Array of component metadata\n */\nexport function findStandaloneComponents(pageData: any): ComponentInfo[] {\n const components: ComponentInfo[] = [];\n const sliderIds = new Set<string>();\n\n // First, collect all slider IDs to exclude their children\n function collectSliderIds(node: any): void {\n if (!node || typeof node !== \"object\") return;\n\n if (node.type === \"container:slider\") {\n sliderIds.add(node.id);\n }\n\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach(collectSliderIds);\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach(collectSliderIds);\n }\n }\n\n // Traverse to find standalone components with bravo:data tags\n // Track parent component names for qualification\n function traverse(\n node: any,\n parentId?: string,\n parentPath: string[] = []\n ): void {\n if (!node || typeof node !== \"object\") return;\n\n // Skip if we're inside a slider\n if (parentId && sliderIds.has(parentId)) return;\n\n // Check if this component has bravo:data tag OR is an embed component\n const hasDataTag =\n Array.isArray(node.tags) &&\n (node.tags.includes(\"encore:data\") || node.tags.includes(\"bravo:data\"));\n\n if (\n node.type === \"component:embed\" ||\n node.type === \"component:webview\" ||\n node.type === \"component:web-view\" ||\n node.type === \"component:video\" ||\n (hasDataTag &&\n (node.type === \"component:text\" || node.type === \"component:image\"))\n ) {\n const basePropName = sanitizePropName(node.name || \"item\");\n const propType = getComponentPropType(node.type, node.name);\n\n components.push({\n id: node.id,\n name: node.name || \"Unnamed\",\n type: node.type,\n tags: node.tags || [],\n propName: basePropName, // Will be qualified later if needed\n propType,\n // Store parent path for later qualification\n _parentPath: [...parentPath],\n } as ComponentInfo & { _parentPath: string[] });\n }\n\n // Build parent path: include this node's name if it's a container/component with a name\n // Skip generic \"Frame\" names - they're usually not meaningful for distinction\n const currentParentPath = [...parentPath];\n if (\n node.name &&\n (node.type?.startsWith(\"container:\") ||\n node.type?.startsWith(\"component:\"))\n ) {\n const name = node.name.trim();\n // Filter out generic \"Frame\" names (case-insensitive, with or without numbers/spaces)\n // But keep meaningful names like \"TripSlideFrame\" that contain other words\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(node.name);\n }\n }\n\n // Recursively traverse children\n const currentId = node.id;\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) =>\n traverse(child, currentId, currentParentPath)\n );\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, currentId, currentParentPath)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, currentId, currentParentPath)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach(collectSliderIds);\n body.forEach((node: any) => traverse(node));\n }\n\n // Qualify duplicate prop names using minimal distinguishing paths\n qualifyPropNames(components);\n\n return components;\n}\n\n/**\n * Finds input groups (radio button-like components) in the page\n *\n * Locates stateful sets tagged with encore:input-group for coordinated\n * selection behavior.\n *\n * @param pageData - Page definition from Encore service\n * @returns Array of input group metadata\n */\nexport function findInputGroups(pageData: any): InputGroupInfo[] {\n const groupsMap = new Map<string, InputGroupInfo>();\n\n function traverse(node: any): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is an input-stateful-set with input-group tag\n if (\n node.type === \"component:input-stateful-set\" &&\n Array.isArray(node.tags)\n ) {\n const inputGroupTag = node.tags.find((tag: string) =>\n tag.startsWith(\"input-group:\")\n );\n if (inputGroupTag) {\n const parts = inputGroupTag.split(\":\");\n if (parts.length >= 3) {\n const groupType = parts[1];\n const groupName = parts[2];\n\n if (!groupsMap.has(groupName)) {\n groupsMap.set(groupName, {\n groupName,\n groupType,\n elements: [],\n });\n }\n\n const group = groupsMap.get(groupName)!;\n group.elements.push({\n id: node.id,\n name: node.name || \"Unnamed\",\n });\n }\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach(traverse);\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach(traverse);\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach(traverse);\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n return Array.from(groupsMap.values());\n}\n\n/**\n * Finds forms and their input fields in the page\n *\n * Locates containers tagged with encore:form and extracts all input\n * components within them for form submission handling.\n *\n * @param pageData - Page definition from Encore service\n * @returns Array of form metadata with input fields\n */\nexport function findForms(pageData: any): FormInfo[] {\n const forms: FormInfo[] = [];\n\n function traverse(node: any, parentContainer?: any): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is a container that might be a form\n const isContainer =\n node.type?.startsWith(\"container:\") || node.type === \"container:default\";\n const isNamedForm =\n node.name?.toLowerCase().includes(\"form\") ||\n (Array.isArray(node.tags) && node.tags.includes(\"form\"));\n\n // Check if this container or any child has a submit action\n let hasSubmitAction = false;\n let submitButtonId: string | undefined;\n\n function checkForSubmitAction(n: any): void {\n if (!n || typeof n !== \"object\") return;\n\n // Check if this node has a submit action\n if (\n Array.isArray(n.tags) &&\n (n.tags.includes(\"action:submit\") || n.tags.includes(\"submit\"))\n ) {\n hasSubmitAction = true;\n submitButtonId = n.id;\n return;\n }\n\n // Check actions\n if (n.actions?.tap?.action === \"submit\") {\n hasSubmitAction = true;\n submitButtonId = n.id;\n return;\n }\n\n // Recursively check children\n if (n.components && Array.isArray(n.components)) {\n n.components.forEach(checkForSubmitAction);\n }\n if (n.body && Array.isArray(n.body)) {\n n.body.forEach(checkForSubmitAction);\n }\n }\n\n // If this looks like a form container, check for submit actions\n if (isContainer && (isNamedForm || parentContainer === undefined)) {\n checkForSubmitAction(node);\n }\n\n // If we found a form container (has submit action or is named \"form\")\n if (isContainer && (hasSubmitAction || isNamedForm)) {\n const inputs: FormInfo[\"inputs\"] = [];\n\n // Find all input components within this container\n const findInputs = (n: any, parentPath: string[] = []): void => {\n if (!n || typeof n !== \"object\") return;\n\n // Check if this is an input component\n if (\n n.type?.startsWith(\"component:input-\") ||\n n.type === \"component:input-text\" ||\n n.type === \"component:input-image\" ||\n n.type === \"component:input-email\" ||\n n.type === \"component:input-password\" ||\n n.type === \"component:input-select\"\n ) {\n const basePropName = sanitizePropName(n.name || \"Unnamed input\");\n inputs.push({\n id: n.id,\n name: n.name || \"Unnamed input\",\n type: n.type,\n propName: basePropName, // Will be qualified later if needed\n _parentPath: [...parentPath], // Store parent path for qualification\n });\n }\n\n // Build parent path: include this node's name if it's a container/component with a name\n // Skip generic \"Frame\" names - they're usually not meaningful for distinction\n const currentParentPath = [...parentPath];\n if (\n n.name &&\n (n.type?.startsWith(\"container:\") || n.type?.startsWith(\"component:\"))\n ) {\n const name = n.name.trim();\n // Filter out generic \"Frame\" names (case-insensitive, with or without numbers/spaces)\n // But keep meaningful names like \"TripSlideFrame\" that contain other words\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(n.name);\n }\n }\n\n // Recursively search children\n if (n.components && Array.isArray(n.components)) {\n n.components.forEach((child: any) =>\n findInputs(child, currentParentPath)\n );\n }\n if (n.body && Array.isArray(n.body)) {\n n.body.forEach((child: any) => findInputs(child, currentParentPath));\n }\n };\n\n findInputs(node, []);\n\n // Only add form if it has inputs\n if (inputs.length > 0) {\n forms.push({\n formId: node.id,\n formName: node.name || \"Form\",\n submitButtonId,\n inputs,\n });\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) =>\n traverse(child, isContainer ? node : parentContainer)\n );\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, isContainer ? node : parentContainer)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, isContainer ? node : parentContainer)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n return forms;\n}\n\n/**\n * Finds standalone select input components (input-select) that are NOT inside forms.\n * These should be exposed as controlled inputs with value and onChange props.\n */\nexport function findStandaloneSelectInputs(\n pageData: any,\n forms: FormInfo[]\n): SelectInputInfo[] {\n const selectInputs: SelectInputInfo[] = [];\n\n // Collect all input IDs that are already in forms\n const formInputIds = new Set<string>();\n forms.forEach((form) => {\n form.inputs.forEach((input) => {\n formInputIds.add(input.id);\n });\n });\n\n // Traverse to find input-select components not in forms\n function traverse(node: any, parentPath: string[] = []): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check if this is an input-select component\n if (node.type === \"component:input-select\" && !formInputIds.has(node.id)) {\n const basePropName = sanitizePropName(node.name || \"selectInput\");\n selectInputs.push({\n id: node.id,\n name: node.name || \"Select Input\",\n propName: basePropName,\n _parentPath: [...parentPath],\n });\n }\n\n // Build parent path for qualification\n const currentParentPath = [...parentPath];\n if (\n node.name &&\n (node.type?.startsWith(\"container:\") ||\n node.type?.startsWith(\"component:\"))\n ) {\n const name = node.name.trim();\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(node.name);\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) => traverse(child, currentParentPath));\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n // Qualify duplicate prop names\n qualifySelectInputs(selectInputs);\n\n return selectInputs;\n}\n\n/**\n * Qualifies select input prop names to ensure uniqueness.\n */\nfunction qualifySelectInputs(selectInputs: SelectInputInfo[]): void {\n qualifyPropNames(selectInputs);\n}\n\n/**\n * Finds action buttons - components that have action tags (action:remote, action:link, etc.)\n * or have actions defined. These should be exposed with onClick handlers.\n */\nexport function findActionButtons(pageData: any): ActionButtonInfo[] {\n const buttons: ActionButtonInfo[] = [];\n\n console.log(\n \"[DEBUG] local encore-lib findActionButtons running via alias. Check node.actions support.\"\n );\n\n function traverse(node: any, parentPath: string[] = []): void {\n if (!node || typeof node !== \"object\") return;\n\n // Log nodes with potentially interesting properties for debugging\n if (\n node.id === \"01KF5PAFFVFSKY6QJZXQTC99P5\" ||\n (node.tags && node.tags.some((t: string) => t.includes(\"action\")))\n ) {\n console.log(`[DEBUG] traverse node ${node.name} (${node.id})`, {\n type: node.type,\n tags: node.tags,\n hasActions: !!node.actions,\n actionsKeys: node.actions ? Object.keys(node.actions) : [],\n });\n }\n\n // Check if this component has an action tag or actions defined\n const hasActionTag =\n Array.isArray(node.tags) &&\n node.tags.some((tag: string) => tag.startsWith(\"action:\"));\n const hasActions = node.actions && typeof node.actions === \"object\";\n\n if (hasActionTag || hasActions) {\n // Determine the action type\n let actionType = \"tap\";\n if (Array.isArray(node.tags)) {\n const actionTag = node.tags.find((tag: string) =>\n tag.startsWith(\"action:\")\n );\n if (actionTag) {\n actionType = actionTag.replace(\"action:\", \"\");\n }\n }\n if (node.actions?.tap?.action) {\n actionType = node.actions.tap.action;\n }\n\n console.log(`[DEBUG] Found action button: ${node.name} (${node.id})`, {\n actionType,\n hasActionTag,\n hasActions,\n });\n\n const basePropName = sanitizePropName(node.name || \"button\");\n buttons.push({\n id: node.id,\n name: node.name || \"Button\",\n propName: basePropName,\n actionType,\n _parentPath: [...parentPath],\n });\n }\n\n // Build parent path for qualification\n const currentParentPath = [...parentPath];\n if (\n node.name &&\n (node.type?.startsWith(\"container:\") ||\n node.type?.startsWith(\"component:\"))\n ) {\n const name = node.name.trim();\n const isGenericFrame =\n /^frame\\s*\\d*$/i.test(name) || name.toUpperCase() === \"FRAME\";\n if (name && !isGenericFrame) {\n currentParentPath.push(node.name);\n }\n }\n\n // Recursively traverse children\n if (node.body && Array.isArray(node.body)) {\n node.body.forEach((child: any) => traverse(child, currentParentPath));\n }\n if (node.containers && Array.isArray(node.containers)) {\n node.containers.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n if (node.components && Array.isArray(node.components)) {\n node.components.forEach((child: any) =>\n traverse(child, currentParentPath)\n );\n }\n }\n\n // Start traversal from page data\n const body =\n pageData.data?.body || pageData.body || (pageData as any).data?.body || [];\n\n if (Array.isArray(body) && body.length > 0) {\n body.forEach((node: any) => traverse(node));\n }\n\n // Qualify duplicate prop names\n qualifyActionButtons(buttons);\n\n return buttons;\n}\n\n/**\n * Qualifies action button prop names to ensure uniqueness.\n */\nfunction qualifyActionButtons(buttons: ActionButtonInfo[]): void {\n qualifyPropNames(buttons);\n}\n\n/**\n * Qualifies form input prop names to ensure uniqueness within each form.\n * Only qualifies where necessary, using minimal distinguishing paths.\n */\nexport function qualifyFormInputs(forms: FormInfo[]): void {\n forms.forEach((form) => {\n qualifyPropNames(form.inputs);\n });\n}\n"],"names":["sanitizePropName","name","cleaned","word","index","normalizedWord","firstChar","rest","generateQualifiedPropName","componentName","parentPath","baseName","validParentParts","part","findMinimalDistinguishingPath","thisPath","otherPaths","commonPrefixLength","maxCommonLength","p","i","thisPart","otherPath","distinguishingSuffix","suffixLength","thisSuffix","otherSuffix","arraysEqual","a","b","val","idx","getComponentPropType","componentType","_componentName","getComponentPropName","findSlidersAndDataBindings","pageData","sliders","traverse","node","path","slider","arrayContainer","findArrayContainer","containerNode","container","components","imageComponents","findDataComponents","comp","basePropName","propType","currentParentPath","isGenericFrame","child","c","imageComp","qualifyPropNames","imageName","compName","body","findStandaloneComponents","sliderIds","collectSliderIds","parentId","hasDataTag","currentId","findInputGroups","groupsMap","inputGroupTag","tag","parts","groupType","groupName","findForms","forms","parentContainer","isContainer","isNamedForm","hasSubmitAction","submitButtonId","checkForSubmitAction","n","inputs","findInputs","findStandaloneSelectInputs","selectInputs","formInputIds","form","input","qualifySelectInputs","findActionButtons","buttons","t","hasActionTag","hasActions","actionType","actionTag","qualifyActionButtons","qualifyFormInputs"],"mappings":"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"}
@@ -1,19 +1,19 @@
1
1
  import { jsx as n } from "react/jsx-runtime";
2
- import K from "../node_modules/swr/dist/index/index.js";
3
- import T from "../lib/fetcher.js";
2
+ import T from "../node_modules/swr/dist/index/index.js";
3
+ import _ from "../lib/fetcher.js";
4
4
  import i from "../stores/useEncoreState.js";
5
- import { useRef as _, useEffect as c, useState as H, useCallback as st, useMemo as nt, Suspense as ct } from "react";
5
+ import { useRef as H, useEffect as c, useState as Y, useCallback as nt, useMemo as ct, Suspense as at } from "react";
6
6
  import { setLocalModeOverride as A, isLocalMode as B } from "../lib/localMode.js";
7
- import at from "./DynamicComponent.js";
8
- import { useEncoreRouter as it } from "../contexts/EncoreRouterContext.js";
9
- import { usePusherUpdates as lt } from "../hooks/usePusherUpdates.js";
10
- import { useFontLoader as dt } from "../hooks/useFontLoader.js";
11
- import { useRepeatingContainers as ut } from "../hooks/useRepeatingContainers.js";
12
- import { EncoreContextProviders as ft } from "./EncoreContextProviders.js";
13
- import { patchPageData as mt } from "../lib/dataPatching.js";
7
+ import it from "./DynamicComponent.js";
8
+ import { useEncoreRouter as lt } from "../contexts/EncoreRouterContext.js";
9
+ import { usePusherUpdates as dt } from "../hooks/usePusherUpdates.js";
10
+ import { useFontLoader as ut } from "../hooks/useFontLoader.js";
11
+ import { useRepeatingContainers as ft } from "../hooks/useRepeatingContainers.js";
12
+ import { EncoreContextProviders as mt } from "./EncoreContextProviders.js";
13
+ import { patchPageData as ht } from "../lib/dataPatching.js";
14
14
  import { logger as f } from "../lib/logger.js";
15
- const ht = ({ to: e, children: o, style: D, ...b }) => {
16
- const { navigate: l } = it();
15
+ const pt = ({ to: e, children: o, style: D, ...b }) => {
16
+ const { navigate: l } = lt();
17
17
  return /* @__PURE__ */ n(
18
18
  "a",
19
19
  {
@@ -26,29 +26,30 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
26
26
  children: o
27
27
  }
28
28
  );
29
- }, pt = (e) => e.setApp, yt = (e) => e.setAppId, gt = (e) => e.setPageId, vt = (e) => e.assetsById, Ut = ({
29
+ }, yt = (e) => e.setApp, gt = (e) => e.setAppId, vt = (e) => e.setPageId, bt = (e) => e.assetsById, Ft = ({
30
30
  appId: e,
31
31
  pageId: o,
32
32
  componentId: D,
33
33
  fallback: b,
34
34
  onSizeChange: l,
35
35
  onContentSizeChange: m,
36
- onAction: Y,
36
+ onAction: q,
37
37
  data: w,
38
38
  source: d,
39
- repeatingContainerControls: q,
39
+ repeatingContainerControls: G,
40
40
  inputGroups: L,
41
41
  baseURL: S,
42
42
  appDefinition: h,
43
43
  pageDefinition: R,
44
44
  componentCode: O,
45
- mode: P
45
+ mode: P,
46
+ embeds: C
46
47
  }) => {
47
48
  f.debug("EncoreApp render", { appId: e, pageId: o, mode: P }), S && i.getState().baseURL !== S && i.getState().setBaseURL(S), d && A(d === "local" ? "local" : "remote");
48
- const G = !1, C = i(pt), M = i(yt), E = i(gt), p = i(vt), U = _(null), F = _(null);
49
+ const J = !1, M = i(yt), E = i(gt), U = i(vt), p = i(bt), F = H(null), j = H(null);
49
50
  c(() => {
50
51
  if (!m) return;
51
- const t = F.current;
52
+ const t = j.current;
52
53
  if (!t) return;
53
54
  const r = () => {
54
55
  m({
@@ -60,29 +61,29 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
60
61
  });
61
62
  return r(), s.observe(t), () => s.disconnect();
62
63
  }, [m]);
63
- const [J, Q] = H(0), X = st(() => {
64
- Q((t) => typeof t == "number" ? t + 1 : Date.now());
64
+ const [Q, X] = Y(0), Z = nt(() => {
65
+ X((t) => typeof t == "number" ? t + 1 : Date.now());
65
66
  }, []);
66
- lt({
67
+ dt({
67
68
  appId: e,
68
69
  pageId: o || void 0,
69
70
  enabled: !B() && !h,
70
- onUpdate: X
71
+ onUpdate: Z
71
72
  });
72
- const j = d === "local" || B(), y = P === "production", u = P === "optimistic", W = !y && !u, N = !y && e ? `/devices/apps/${e}${j ? "?useLocal=1" : ""}` : null, Z = K(N, T, {
73
- suspense: W && !!N,
73
+ const W = d === "local" || B(), y = P === "production", u = P === "optimistic", N = !y && !u, V = !y && e ? `/devices/apps/${e}${W ? "?useLocal=1" : ""}` : null, z = T(V, _, {
74
+ suspense: N && !!V,
74
75
  // Suspense only for Dynamic mode
75
76
  fallbackData: u && h ? h : void 0,
76
77
  revalidateOnMount: !0
77
78
  // Ensure we fetch fresh data in optimistic mode
78
- }), g = y && h ? { data: h } : Z;
79
+ }), g = y && h ? { data: h } : z;
79
80
  c(() => {
80
- C(g.data);
81
- }, [g.data, C]), dt(g?.data), c(() => {
82
- M(e);
83
- }, [e, M]), c(() => {
84
- o && E(o);
85
- }, [o, E]), c(() => {
81
+ M(g.data);
82
+ }, [g.data, M]), ut(g?.data), c(() => {
83
+ E(e);
84
+ }, [e, E]), c(() => {
85
+ o && U(o);
86
+ }, [o, U]), c(() => {
86
87
  Object.keys(p).length !== 0 && (async () => await Promise.allSettled(
87
88
  Object.keys(p).map((t) => p[t].url ? new Promise((r) => {
88
89
  const s = new Image();
@@ -90,13 +91,13 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
90
91
  }) : Promise.resolve())
91
92
  ))();
92
93
  }, [p]);
93
- const k = !y && e && o ? `/devices/apps/${e}/node/${o}${j ? "?useLocal=1" : ""}` : null;
94
+ const k = !y && e && o ? `/devices/apps/${e}/node/${o}${W ? "?useLocal=1" : ""}` : null;
94
95
  f.debug("Page data fetch", { pageUrl: k, mode: P });
95
- const z = K(k, T, {
96
- suspense: W && !!k,
96
+ const I = T(k, _, {
97
+ suspense: N && !!k,
97
98
  fallbackData: u && R ? R : void 0,
98
99
  revalidateOnMount: !0
99
- }), $ = y && R ? { data: R } : z, [I, V] = H(
100
+ }), $ = y && R ? { data: R } : I, [tt, K] = Y(
100
101
  O
101
102
  );
102
103
  c(() => {
@@ -104,25 +105,25 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
104
105
  try {
105
106
  const { CONST_COMPONENTS_CDN_URL: r } = await import("../packages/encore-lib/constants.js"), s = Math.round(Date.now() / 1e3), x = `${e}/draft/components/${o}`, v = `${r}/${x}.js?cacheBuster=${s}`, a = await fetch(v);
106
107
  if (a.ok) {
107
- const rt = await a.text();
108
- V(rt), f.debug("Refreshed optimistic component code");
108
+ const st = await a.text();
109
+ K(st), f.debug("Refreshed optimistic component code");
109
110
  }
110
111
  } catch (r) {
111
112
  f.warn("Failed to background refresh optimistic component", r);
112
113
  }
113
- })() : V(O);
114
+ })() : K(O);
114
115
  }, [O, u, e, o]);
115
- const tt = u ? I : O;
116
+ const et = u ? tt : O;
116
117
  f.debug("Page data loaded", {
117
118
  hasData: !!$?.data,
118
119
  dataType: typeof $?.data
119
120
  });
120
- const et = nt(() => {
121
+ const ot = ct(() => {
121
122
  let t = $.data?.clientData;
122
123
  return f.debug("Building context", {
123
124
  hasClientData: !!t,
124
125
  clientDataKeys: Object.keys(t || {}).length
125
- }), t && mt(t), {
126
+ }), t && ht(t), {
126
127
  nodeData: void 0,
127
128
  // Allow overriding specific values by element id.
128
129
  // For now, this is used to override TextComponent content when the node has the PROP:TEXT_VAR tag.
@@ -130,10 +131,12 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
130
131
  // Support for encore:data:array tags - provide array data by component ID
131
132
  arrayDataById: w,
132
133
  // Support for standalone component data binding (encore:data tags at root level)
133
- rootData: w
134
+ rootData: w,
135
+ // Support for embedded components
136
+ embedsById: C
134
137
  };
135
- }, [$.data?.clientData, w]), ot = ut(
136
- q
138
+ }, [$.data?.clientData, w, C]), rt = ft(
139
+ G
137
140
  );
138
141
  return c(() => {
139
142
  if (L) {
@@ -144,7 +147,7 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
144
147
  }
145
148
  }, [L]), c(() => {
146
149
  if (!l) return;
147
- const t = U.current;
150
+ const t = F.current;
148
151
  if (!t) return;
149
152
  const r = (v) => {
150
153
  const a = v.contentRect;
@@ -164,7 +167,7 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
164
167
  }, [d]), o ? /* @__PURE__ */ n(
165
168
  "div",
166
169
  {
167
- ref: U,
170
+ ref: F,
168
171
  style: {
169
172
  width: "100%",
170
173
  height: "100%",
@@ -174,27 +177,27 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
174
177
  children: /* @__PURE__ */ n(
175
178
  "div",
176
179
  {
177
- ref: F,
180
+ ref: j,
178
181
  style: {
179
182
  width: "100%",
180
183
  height: "100%",
181
184
  display: "flex",
182
185
  flexDirection: "column"
183
186
  },
184
- children: /* @__PURE__ */ n(ct, { fallback: b || /* @__PURE__ */ n("div", {}), children: /* @__PURE__ */ n(
185
- ft,
187
+ children: /* @__PURE__ */ n(at, { fallback: b || /* @__PURE__ */ n("div", {}), children: /* @__PURE__ */ n(
188
+ mt,
186
189
  {
187
190
  componentId: D,
188
- onAction: Y,
189
- repeatingContainerContextValue: ot,
190
- bindingContextValue: et,
191
+ onAction: q,
192
+ repeatingContainerContextValue: rt,
193
+ bindingContextValue: ot,
191
194
  children: /* @__PURE__ */ n(
192
- at,
195
+ it,
193
196
  {
194
197
  name: `${e}/draft/components/${o}`,
195
198
  fallback: b,
196
- reloadKey: J,
197
- componentCode: tt
199
+ reloadKey: Q,
200
+ componentCode: et
198
201
  }
199
202
  )
200
203
  }
@@ -208,9 +211,9 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
208
211
  (t) => t?.id
209
212
  )
210
213
  ) : g?.data?.app.pageIds || []).map((t) => /* @__PURE__ */ n(
211
- ht,
214
+ pt,
212
215
  {
213
- to: `/apps/${e}/pages/${t}?noRedirect=${G}`,
216
+ to: `/apps/${e}/pages/${t}?noRedirect=${J}`,
214
217
  style: {
215
218
  fontSize: 20,
216
219
  display: "block",
@@ -222,6 +225,6 @@ const ht = ({ to: e, children: o, style: D, ...b }) => {
222
225
  )) }) });
223
226
  };
224
227
  export {
225
- Ut as default
228
+ Ft as default
226
229
  };
227
230
  //# sourceMappingURL=EncoreApp.js.map