Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions packages/optimizely-cms-sdk/src/react/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ function FallbackColumn({ node, children }: StructureContainerProps) {
);
}

function FallbackGridComponent({ node, children }: StructureContainerProps) {
const { pa } = getPreviewUtils(node);
return <div {...pa(node)}>{children}</div>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is the fallback, should it have any default styling?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. What should be the default styling?. I am not even sure if the default element should be a div...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this component wrapping? Each component/element in a row? If so, why are we not rendering these attributes on the OptimizelyComponent component (or the first HTML element in this component, like asChild)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be a nice solution.

The problem is that we pass to <OptimizelyComponent /> the object in the component field ([A] in the code snippet below) but the key used for rendering preview attributes is one level up ([B]).

{
  "nodeType": "section",
  "__typename": "CompositionStructureNode",
  "key": "daac8080-ca93-45d8-9b8b-248efdf6ca24",
  "nodes": [
    {
      "nodeType": "row",
      "__typename": "CompositionStructureNode",
      "key": "f64672f1-e0f9-4d2b-995c-d65e1eb60329",
      "nodes": [
        {
          "nodeType": "column",
          "__typename": "CompositionStructureNode",
          "key": "a5e224d8-935a-4eb4-8507-3c5c2449755b",
          "nodes": [
            {
              "nodeType": "component",
              "__typename": "CompositionComponentNode",
              "key": "43038afe-7abe-4e67-90df-8c68dc19292a", // [B]
              "component": {
                // [A]       
                "__typename": "test_c1", 
                "p1": "hello hello"      
              }
            }
          ]
        },
      ]
    }
  ]
}

So, we need to pass key with the opti object to <OptimizelyComponent />

// Where do we include the `key`?
// - As part of `opti`? (something like `opti.__key`?)
// - As a separate property `key`? (`key` doesn't work because is a special keyword in React)
function MyComponent({ opti }) {
  const {pa} = getPreviewAttributes(opti);

  return (
    <div ...pa(opti)>
    </div>
  )
}

// This will not work because "key" is not passed down in React
function MyComponent({ opti, key }) {
  const {pa} = getPreviewAttributes(opti);

  return (
    <div ...pa(opti)>
    </div>
  )
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My experience is that frontend developers are very annoyed with unnecessary wrappers that may cause their designs to break. Maybe we can make the OptimizelyComponent accept a component node, so we can pass the whole node? I think we should explore an alternative solution to this in a separate story.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I aagree. I will then close this PR for now and explore an alternative

}

function FallbackComponent({ children }: { children: ReactNode }) {
return isDev() ? (
<div
Expand All @@ -234,45 +239,37 @@ type OptimizelyGridSectionProps = {
nodes: ExperienceNode[];
row?: StructureContainer;
column?: StructureContainer;
component?: StructureContainer;
displaySettings?: DisplaySettingsType[];
};

const fallbacks: Record<string, StructureContainer> = {
row: FallbackRow,
column: FallbackColumn,
component: FallbackGridComponent,
};

export function OptimizelyGridSection({
nodes,
row,
column,
component,
}: OptimizelyGridSectionProps) {
const locallyDefined: Record<string, StructureContainer | undefined> = {
row,
column,
component,
};

return nodes.map((node, i) => {
const tag = getDisplayTemplateTag(node.displayTemplateKey);
const parsedDisplaySettings = parseDisplaySettings(node.displaySettings);

if (isComponentNode(node)) {
return (
<OptimizelyComponent
opti={{
...node.component,
__tag: tag,
}}
key={node.key}
displaySettings={parsedDisplaySettings}
/>
);
}

const { nodeType } = node;
const globalNames: Record<string, string> = {
row: '_Row',
column: '_Column',
component: '_Component',
};

// Pick the component in the following order:
Expand All @@ -286,6 +283,21 @@ export function OptimizelyGridSection({
fallbacks[nodeType] ??
React.Fragment;

if (isComponentNode(node)) {
return (
<Component node={node} index={i} key={node.key}>
<OptimizelyComponent
opti={{
...node.component,
__tag: tag,
}}
key={node.key}
displaySettings={parsedDisplaySettings}
/>
</Component>
);
}

return (
<Component
node={node}
Expand All @@ -296,6 +308,7 @@ export function OptimizelyGridSection({
<OptimizelyGridSection
row={row}
column={column}
component={component}
nodes={node.nodes ?? []}
/>
</Component>
Expand Down