Skip to main content
Question

Issues with the figma.loadAllPagesAsync() and "documentAccess": "dynamic-page"

  • November 25, 2024
  • 1 reply
  • 193 views

Joshua_Cusick

I updated my manifest to "documentAccess": "dynamic-page" and am using Figma.loadAllPagesAsync() but the error I keep getting in my console is:
vendor-core-68cf3be3dda5691a.min.js.br:15 unhandled promise rejection: Error: in get_mainComponent: Cannot call with documentAccess: dynamic-page. Use node.getMainComponentAsync instead.

import { getSelectedInstances } from "../app/utils/getSelectedInstances"; // Adjust the path as necessary
import { getImageURL } from "../app/utils/getImageURL";
import { componentMap } from "../app/data"; // Adjust the path as necessary

// Clear console on reload
console.clear();

// Default plugin size
const pluginFrameSize = {
  width: 320,
  height: 500,
};

// Show plugin UI
figma.showUI(__html__, pluginFrameSize);

// Declare a global variable to store scanned components
let scannedComponents: {
  id: number; // Added id to the scanned component structure
  node: InstanceNode; // Change to InstanceNode
  newComponentKey: string;
  checked: boolean;
  oldImage?: string; // Optional: to hold old image URL if needed
  newImage?: string; // Optional: to hold new image URL if needed
  groupName: string; // Added groupName to the scanned component structure
}[] = [];

// Variable to hold the resetOverrides state
let resetOverrides = true; // Default value

// Initialize a counter for generating unique IDs
let componentIdCounter = 0;

// Function to initialize the plugin
async function initializePlugin() {
  console.clear();
  // Load all pages in the document
  await figma.loadAllPagesAsync(); // Ensure all pages are loaded

  // Now retrieve the resetOverrides value from clientStorage
  const storedResetOverrides = await figma.clientStorage.getAsync(
    "resetOverrides"
  );
  resetOverrides =
    storedResetOverrides !== undefined ? storedResetOverrides : false; // Default to false if not set
  console.log("Retrieved resetOverrides from storage:", resetOverrides);
}

// Function to post messages to the UI
function postMessageToUI(type: string, payload: any) {
  figma.ui.postMessage({ type, ...payload });
}

// Function to process variants for a component
async function processVariants(
  variant: any,
  nodes: InstanceNode[], // Change to InstanceNode[]
  groupName: string
) {
  const { newComponentKey, keywords } = variant; // Adjusted to pull from variant

  const newComponent = await figma.importComponentByKeyAsync(newComponentKey);

  if (newComponent) {
    for (const node of nodes) {
      if (node.type === "INSTANCE") {
        // Use getMainComponentAsync to access the main component
        const mainComponent = await node.getMainComponentAsync(); // Ensure this is async

        if (mainComponent) {
          const name = mainComponent.name;
          const allKeywordsPresent = keywords.every((keyword) =>
            name.includes(keyword)
          );

          if (allKeywordsPresent) {
            const oldImageSrc = await getImageURL(node);
            const newImageSrc = await getImageURL(newComponent);

            // Add component with old/new images and checked state to scannedComponents
            scannedComponents.push({
              id: componentIdCounter++, // Increment and assign a unique id
              oldImage: oldImageSrc,
              newImage: newImageSrc,
              node,
              newComponentKey,
              checked: true, // Default checked state
              groupName, // Store the groupName in each scanned component
            });
          }
        }
      }
    }
  }
}

// Function to scan components
async function scanComponents(state: string) {
  console.log("Scan state received:", state);
  scannedComponents = [];
  componentIdCounter = 0;

  // Load the current page explicitly
  await figma.currentPage.loadAsync(); // Ensure the current page is loaded

  const allNodes =
    state === "bySelection"
      ? getSelectedInstances(figma.currentPage.selection, componentMap)
      : figma.currentPage.findAll((n) => n.type === "INSTANCE");

  // Process each component in the componentMap
  for (const component of componentMap) {
    const { oldParentKey, variants } = component;

    // Create an array of oldParentKeys from componentMap
    const oldParentKeys = componentMap.map(
      (component) => component.oldParentKey
    );
    // Filter nodes that belong to the current component and are not children (i.e., have no parent)
    const nodes = allNodes.filter(
      (node): node is InstanceNode =>
        node.type === "INSTANCE" &&
        // Check if the main component key matches the old parent key
        (node.mainComponent?.key === oldParentKey ||
          node.mainComponent?.parent?.key === oldParentKey) &&
        // Ensure the parent is not an instance
        node.parent &&
        // Ensure the parent's keys do not match any keys in the parent array
        !oldParentKeys.includes(node.parent?.mainComponent?.key)
    );

    for (const variant of variants) {
      await processVariants(variant, nodes, component.groupName); // Pass groupName here
    }
  }

  // Sends message to update state in App
  postMessageToUI("COMPONENT_IMAGES", {
    componentImages: scannedComponents.map(
      ({ id, oldImage, newImage, checked, groupName }) => ({
        id, // Include the id
        oldImage,
        newImage,
        checked, // Include the checked state
        groupName, // Include groupName in the payload
      })
    ),
  });
  postMessageToUI("SCAN_COMPLETE", {});
}

// Function to swap components
async function swapComponents(checkedStates: boolean[]) {
  console.log("Swapping components...");

  const toSwapComponents = scannedComponents.filter(
    (_, index) => checkedStates[index]
  );

  for (const component of toSwapComponents) {
    const { node, newComponentKey } = component;
    const newComponent = await figma.importComponentByKeyAsync(newComponentKey);

    if (newComponent && node.type === "INSTANCE") {
      const instanceNode = node as InstanceNode;
      if (resetOverrides) {
        instanceNode.resetOverrides(); // Reset overrides if the flag is true
      }
      instanceNode.swapComponent(newComponent);
    } else {
      console.warn(`Node is not an instance: ${node.name}`);
    }
  }

  scannedComponents = scannedComponents.filter(
    (_, index) => !checkedStates[index]
  );

  postMessageToUI("UPDATE_SCANNED_COMPONENTS", {
    updatedComponents: scannedComponents.map((component) => ({
      id: component.id, // Include the id in the update
      oldImage: component.oldImage,
      newImage: component.newImage,
      checked: false,
    })),
  });

  const swappedIndexes = scannedComponents
    .map((_, index) => index)
    .filter((index) => checkedStates[index]);

  postMessageToUI("COMPONENTS_SWAPPED", { swappedIndexes });

  const swappedCount = toSwapComponents.length;
  figma.notify(
    swappedCount > 0
      ? `✨ ${swappedCount} component${swappedCount === 1 ? "" : "s"} swapped`
      : "No components swapped"
  );

  postMessageToUI("SWAP_COMPLETE", {});
}

// Function to update scanned components based on the new checked states
function updateScannedComponents(updatedComponents: any) {
  console.log("Updating scanned components with new checked states...");
  scannedComponents = updatedComponents.map(
    (component: any, index: number) => ({
      ...scannedComponents[index],
      checked: component.checked, // Update checked state
    })
  );
  console.log("Updated scanned components:", scannedComponents);
}

// Listen for messages from the UI
figma.ui.onmessage = async (msg) => {
  if (msg.type === "SCAN_COMPONENTS") {
    const state = msg.scanType;
    console.log("Message received from UI:", msg);
    await scanComponents(state);
  } else if (msg.type === "SWAP_COMPONENTS") {
    console.log("Swapping components...");
    await swapComponents(msg.checkedStates);
  } else if (msg.type === "UPDATE_SCANNED_COMPONENTS") {
    console.log("Received updated scanned components from UI...");
    updateScannedComponents(msg.updatedComponents);
  } else if (msg.type === "RESET_OVERRIDES") {
    resetOverrides = msg.value; // Capture the value correctly
    await figma.clientStorage.setAsync("resetOverrides", resetOverrides); // Store the value in client storage
    console.log("Reset overrides set to:", resetOverrides); // Log the new value
  } else if (msg.type === "GET_RESET_OVERRIDES") {
    // New message type
    figma.ui.postMessage({
      type: "RESET_OVERRIDES_STATUS",
      value: resetOverrides,
    }); // Send the current value back to the UI
  }
};

// Initialize the plugin
initializePlugin();
This topic has been closed for replies.

1 reply

tank666
  • 4873 replies
  • November 25, 2024

Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings