prevwong / craft.js

🚀 A React Framework for building extensible drag and drop page editors
https://craft.js.org
MIT License
7.63k stars 744 forks source link

Nested div tag styling by changing the settings of the component (does not work) #489

Open TarekFaysal opened 1 year ago

TarekFaysal commented 1 year ago

Issue I am trying to change the styling of a component based on the settings. It works great when I apply the settings in the top level element. But If the component has sub element, it seems not to change any of it's style.

To Reproduce Here's an example code of the component:

import { Element, useNode } from '@craftjs/core';
import React from 'react';

import { AppBarSettings } from '../../../component-settings/AppBarSettings';
import { Icon } from '../elementary-components/Icon';

export const Left = ({ children }) => {
  const {
    connectors: { connect },
  } = useNode();
  return (
    <div ref={connect} className="flex flex-row justify-start space-x-2">
      {children}
    </div>
  );
};

Left.craft = {
  rules: {
    // Only accept Icon
    canMoveIn: (incomingNodes) =>
      incomingNodes.every((incomingNode) => incomingNode.data.type === Icon),
  },
};

export type AppBarProps = {
  height: number;
  backgroundColor: string;
  isLeftIconEnabled: boolean;
};
export const AppBar = ({
  backgroundColor,
  height,
  isLeftIconEnabled,
}: Partial<AppBarProps>) => {
  const {
    connectors: { connect, drag },
  } = useNode();

  return (
    <div
      className="flex flex-row items-center p-2"
      ref={(ref) => connect(drag(ref!))}
      style={{
        height: `${height}px`,
        width: '100%',
        backgroundColor: `${backgroundColor}`,
        // if I use 'isLeftIconEnabled' here to change any style, it works just fine
      }}
    >
      <div className="w-2/12">
        <Element id="left" is={Left} canvas>
          <div
            style={{
              display: isLeftIconEnabled ? 'block' : 'none',
              // if I use 'isLeftIconEnabled' here to change any style, it does not work
            }}
          >
            <Icon />
          </div>
        </Element>
      </div>
    </div>
  );
};

AppBar.craft = {
  props: {
    height: 60,
    backgroundColor: '#F4C430',
    isLeftIconEnabled: true,
  },
  related: {
    // AppBarSettings has the form to change height, background color, IsLeftIconEnabled properties
    settings: AppBarSettings,
  },
};

My environment

Software Version(s)
craft.js 0.2.0-beta.8
React 18.2.0
TypeScript 4.8.4
Browser Chrome
Yarn 122.19
Operating System Windows 10
prevwong commented 1 year ago

When you create a linked node like what you have in your component:

 <Element id="left" is={Left} canvas>
     <div
         style={{
              display: isLeftIconEnabled ? 'block' : 'none',
              // if I use 'isLeftIconEnabled' here to change any style, it does not work
         }}
       >
        <Icon />
      </div>
</Element>

What happens is Craft looks for an existing linked node with the id left, and if it doesn't exist, it then creates the necessary Nodes for the linked node and its children (in this case the child div) node.

But once the nodes has been created, Craft will not recreate the nodes again and the only way to update the linked node and its children is via Craft's APIs:

const AppBar = () => {
  const { id } = useNode();
  const { actions, query, linkedNodes } = useEditor();

  useEffect(() => {
    const linkedNode = query.node(id).get().linkedNodes['left'];

    if ( !linkedNode ) { return; }

     // make some changes
    actions.setProp(linkedNode.id, props => {...});
  }, [actions, query]);
}