@bravostudioai/react 0.1.34 → 0.1.36
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.
- package/README.md +84 -35
- package/dist/codegen/generator.js +243 -234
- package/dist/codegen/generator.js.map +1 -1
- package/dist/codegen/parser.js +150 -149
- package/dist/codegen/parser.js.map +1 -1
- package/dist/components/EncoreApp.js +61 -58
- package/dist/components/EncoreApp.js.map +1 -1
- package/dist/components.js +512 -449
- package/dist/components.js.map +1 -1
- package/dist/contexts/EncoreBindingContext.js +9 -3
- package/dist/contexts/EncoreBindingContext.js.map +1 -1
- package/dist/src/codegen/generator.d.ts.map +1 -1
- package/dist/src/codegen/parser.d.ts.map +1 -1
- package/dist/src/components/EncoreApp.d.ts +3 -1
- package/dist/src/components/EncoreApp.d.ts.map +1 -1
- package/dist/src/components.d.ts.map +1 -1
- package/dist/src/contexts/EncoreBindingContext.d.ts +14 -2
- package/dist/src/contexts/EncoreBindingContext.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen/generator.ts +24 -2
- package/src/codegen/parser.ts +29 -4
- package/src/components/EncoreApp.tsx +6 -1
- package/src/components.tsx +131 -4
- package/src/contexts/EncoreBindingContext.ts +20 -3
- package/src/version.ts +1 -1
|
@@ -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 (componentType === \"component:webview\") {\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 (componentType === \"component:webview\") {\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 (hasDataTag &&\n (node.type === \"component:text\" ||\n node.type === \"component:image\" ||\n node.type === \"component:webview\" ||\n node.type === \"component:video\"))\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","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","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
|
|
3
|
-
import
|
|
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
|
|
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
|
|
8
|
-
import { useEncoreRouter as
|
|
9
|
-
import { usePusherUpdates as
|
|
10
|
-
import { useFontLoader as
|
|
11
|
-
import { useRepeatingContainers as
|
|
12
|
-
import { EncoreContextProviders as
|
|
13
|
-
import { patchPageData as
|
|
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
|
|
16
|
-
const { navigate: l } =
|
|
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
|
-
},
|
|
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:
|
|
36
|
+
onAction: q,
|
|
37
37
|
data: w,
|
|
38
38
|
source: d,
|
|
39
|
-
repeatingContainerControls:
|
|
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
|
|
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 =
|
|
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 [
|
|
64
|
-
|
|
64
|
+
const [Q, X] = Y(0), Z = nt(() => {
|
|
65
|
+
X((t) => typeof t == "number" ? t + 1 : Date.now());
|
|
65
66
|
}, []);
|
|
66
|
-
|
|
67
|
+
dt({
|
|
67
68
|
appId: e,
|
|
68
69
|
pageId: o || void 0,
|
|
69
70
|
enabled: !B() && !h,
|
|
70
|
-
onUpdate:
|
|
71
|
+
onUpdate: Z
|
|
71
72
|
});
|
|
72
|
-
const
|
|
73
|
-
suspense:
|
|
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 } :
|
|
79
|
+
}), g = y && h ? { data: h } : z;
|
|
79
80
|
c(() => {
|
|
80
|
-
|
|
81
|
-
}, [g.data,
|
|
82
|
-
|
|
83
|
-
}, [e,
|
|
84
|
-
o &&
|
|
85
|
-
}, [o,
|
|
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}${
|
|
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
|
|
96
|
-
suspense:
|
|
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 } :
|
|
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
|
|
108
|
-
|
|
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
|
-
})() :
|
|
114
|
+
})() : K(O);
|
|
114
115
|
}, [O, u, e, o]);
|
|
115
|
-
const
|
|
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
|
|
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 &&
|
|
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]),
|
|
136
|
-
|
|
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 =
|
|
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:
|
|
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:
|
|
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(
|
|
185
|
-
|
|
187
|
+
children: /* @__PURE__ */ n(at, { fallback: b || /* @__PURE__ */ n("div", {}), children: /* @__PURE__ */ n(
|
|
188
|
+
mt,
|
|
186
189
|
{
|
|
187
190
|
componentId: D,
|
|
188
|
-
onAction:
|
|
189
|
-
repeatingContainerContextValue:
|
|
190
|
-
bindingContextValue:
|
|
191
|
+
onAction: q,
|
|
192
|
+
repeatingContainerContextValue: rt,
|
|
193
|
+
bindingContextValue: ot,
|
|
191
194
|
children: /* @__PURE__ */ n(
|
|
192
|
-
|
|
195
|
+
it,
|
|
193
196
|
{
|
|
194
197
|
name: `${e}/draft/components/${o}`,
|
|
195
198
|
fallback: b,
|
|
196
|
-
reloadKey:
|
|
197
|
-
componentCode:
|
|
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
|
-
|
|
214
|
+
pt,
|
|
212
215
|
{
|
|
213
|
-
to: `/apps/${e}/pages/${t}?noRedirect=${
|
|
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
|
-
|
|
228
|
+
Ft as default
|
|
226
229
|
};
|
|
227
230
|
//# sourceMappingURL=EncoreApp.js.map
|