Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strange Behavior with External Components in RekaJS #59

Open
K1NZ54 opened this issue Jul 21, 2023 · 4 comments
Open

Strange Behavior with External Components in RekaJS #59

K1NZ54 opened this issue Jul 21, 2023 · 4 comments

Comments

@K1NZ54
Copy link

K1NZ54 commented Jul 21, 2023

Hello everyone,

I'm currently experiencing a peculiar behavior with External Components in RekaJS and since there's no clear examples available, I thought it might be better to explain what I'm doing to see if I am doing something wrong.

I've created a component called TestExternal.tsx:

import React, { useState, useRef } from 'react';

export const TestExternal = React.forwardRef<
  HTMLDivElement,
  { children: React.ReactNode }
>((props, ref) => {
  return (
    <div style={{ width: '100%', flex: 1, height: '100%' }}>
      {props.children}
    </div>
  );
});

Then I added it in Editor.tsx so that I could use it:

t.externalComponent({
  name: 'TestExternal',
  render: (props: { children: React.ReactNode }) => {
    return <TestExternal>{props.children}</TestExternal>;
  },
})

Finally, I used the component like this:

component App() {
  val text = "Bye";
  val counter = 0;
} => (
  <$TestExternal>
    <section className={"w-full h-full"}>.....</$TestExternal>
)

So far, everything is straightforward and it displays correctly. However, when I attempt to edit the children, everything is selected as can be seen in the screenshot below :
image

The only slot of the feature that I can select is as shown below :
image

Can anyone shed light on why this behavior is occurring? Thank you for your assistance

@K1NZ54
Copy link
Author

K1NZ54 commented Jul 21, 2023

In the process of drafting this message, I also tried creating a slot:

component App() {
  val text = "Bye";
  val counter = 0;
} => (
  <$TestExternal>
    <Screen><section className={"w-full h-full"}> ..... </Screen></$TestExternal>
)

component Screen() => (
  <slot/>
)

This partially solves the problem as I can now edit the text, but not the components such as Features.

image

Is there a solution for this as well? Any guidance would be appreciated. Thank you.

@prevwong
Copy link
Owner

Hi, thanks for reporting this issue.

I think this is more of a bug with the site example rather than with Reka itself. The site example didn't really account for external components with slots, hence I probably missed this. I can take a look at it, but it's not a high priority in this repo since I'm currently working on the Craft.js integration with Reka which will provide better support for handling things like this.

If you're interested in fixing this bug on the site example, this is the file responsible for handling which elements are being selected: https://github.com/prevwong/reka.js/blob/main/site/components/frame/Renderer/Renderer.tsx

@K1NZ54
Copy link
Author

K1NZ54 commented Jul 26, 2023

Hi,

Thank you for your swift response. I completely understand the priorities, and like you, I suspect that there might be an issue with the rendering.

However, I also believe that there could be an issue within RekaJS itself, specifically the way it treats ‘children’ - it doesn’t seem to consider ‘children’ as a slot. To me, this doesn’t seem like an issue on the rendering side, but rather something that occurs within the core functionality of RekaJS.

Do you have any suggestions on how I could potentially address this issue? Your guidance would be greatly appreciated.

Thank you.

@prevwong
Copy link
Owner

Do you have an example of what do you mean by Reka doesn't treat children as slot? Reka passes the resulting view of the children template differently depending on the type of the component.

Let's say we have the following component template that we want to evaluate:

{
  type: "ComponentTemplate", 
  component: { name: "Button" },
  children: [...]
}

If Button is a RekaComponent (ie: a component built with the AST), then Reka will evaluate the children template above and store it in a way that's accessible via the slot template inside the Button component.

const slot = this.template.children.flatMap((child) =>
this.evaluator.computeTemplate(child, {
...this.ctx,
path: [...this.ctx.path, child.id],
owner: this.ctx.owner,
})
);
this.env.set(ComponentSlotBindingKey, {
value: slot,
readonly: true,
});

Otherwise, if it's an external component (ie: React), then Reka will evaluate the children template above and store it directly as part of the external component's View; then it's the Renderer's job to ensure that view get's passed correctly to the corresponding React component.

const children = this.template.children.flatMap((child) =>
this.evaluator.computeTemplate(child, {
...this.ctx,
path: [...this.ctx.path, child.id],
owner: this.ctx.owner,
componentStack: [...this.ctx.componentStack, component],
})
);
return [
t.externalComponentView({
frame: this.evaluator.frame.id,
component,
key: this.key,
template: this.template,
children: children || [],

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants