teleporthq / teleport-code-generators

A collection of code generators for modern JavaScript applications
https://teleporthq.io
MIT License
1k stars 159 forks source link

(feat): add object attribute for the UIDLElement to pass objects as props for components #934

Open JayaKrishnaNamburu opened 2 weeks ago

JayaKrishnaNamburu commented 2 weeks ago

This PR is to test passing json objects as props for component nodes. A UIDL like below with object as attribute will generate a jsx that can pass this object to the component. And can be used inside the component. We can expand on the use-case more when needed.

{
  "type": "element",
  "content": {
    "elementType": "component",
    "semanticType": "Sample",
    "attrs": {
      "fields": {
        "thumbnail": {
          "src": "https://picsum.photos/300/200",
          "alt": "Custom"
        },
        "Title": "Custom Name",
        "Description": "This is a description that belongs to this component instance"
      }
    },
    "dependency": {
      "type": "local"
    }
  }
}
<Sample
  fields={{
    thumbnail: {
      src: 'https://picsum.photos/300/200',
      alt: 'Custom',
    },
    Title: 'Custom Name',
    Description:
      'This is a description that belongs to this component instance',
  }}
></Sample>
JayaKrishnaNamburu commented 2 weeks ago

Here i a example. We have three nodes inside a component.

UIDL for binding the prop to node

{
  "type": "element",
  "content": {
    "elementType": "container",
    "children": [
      {
        "type": "dynamic",
        "content": {
          "referenceType": "prop",
          "id": "fields.Title"
        }
      },
      {
        "type": "dynamic",
        "content": {
          "referenceType": "prop",
          "id": "company.name"
        }
      },
      {
        "type": "dynamic",
        "content": {
          "referenceType": "prop",
          "id": "company.location"
        }
      }
    ]
  }
}

And we have defaultValues defined in the component prop definitions like

UIDL for defining defaultValue

{
"fields": {
  "type": "object",
  "defaultValue": {
    "Title": "Here is a custom title in prop definitions."
  }
},
"company": {
  "type": "object",
  "defaultValue": {
    "name": "teleporHQ",
    "location": "Romania"
  }
}

Passing props for overwriting the object value

If you want to overwrite the values in the component instead of defaults. You can pass the objects using

{
    "type": "element",
    "content": {
        "elementType": "component",
        "dependency": {
            "type": "local"
        },
        "attrs": {
          "fields": {
            "type": "object",
            "content": {
              "Title": "Custom Name",
             }
          }
        },
        "referencedStyles": {},
        "abilities": {},
        "children": [],
        "semanticType": "Component"
    }
}

This generates code in the following language syntaxes as

React

const AppComponent = (props) => {
  return (
    <div className="component-container1">
      <div>
        {props.fields.Title}
        {props.company.name}
        {props.company.location}
      </div>
    </div>
  )
}

AppComponent.defaultProps = {
  fields: {
    Title: 'Here is a custom title in prop definitions.',
  },
  company: {
    name: 'teleporHQ',
    location: 'Romania',
  },
}

<AppComponent
  fields={{
    Title: 'Custom Name',
  }}
></AppComponent>

Vue

<template>
  <div class="component-container1">
    <div>{{ fields.Title }}{{ company.name }}{{ company.location }}</div>
  </div>
</template>

<script>
export default {
  name: 'AppComponent',
  props: {
    fields: {
      type: Object,
      default: () => ({
        Title: 'Here is a custom title in prop definitions.',
      }),
    },
    company: {
      type: Object,
      default: () => ({
        name: 'teleporHQ',
        location: 'Romania',
      }),
    },
  },
}
</script>

<template>
  <div class="home-container">
    <app-component :fields="fields"></app-component>
  </div>
</template>

<script>
import AppComponent from '../components/component'

export default {
  name: 'Home',
  components: {
    AppComponent,
  },
  data() {
    return {
      fields: {
        Title: 'Custom Name',
      },
    }
  },
  metaInfo: {
    title: 'New Project3',
    meta: [
      {
        property: 'og:title',
        content: 'New Project3',
      },
    ],
  },
}
</script>

HTML

<body>
  <link rel="stylesheet" href="../style.css" />
  <div>
    <link href="./component.css" rel="stylesheet" />
    <div class="component-container1">
      <div>Here is a custom title in prop definitions. teleporHQ Romania</div>
    </div>
  </div>
</body>

<app-component-wrapper class="app-component-wrapper">
  <!--AppComponent component-->
  <div class="app-component-container1">
    <div>Custom Name teleporHQ Romania</div>
  </div>
</app-component-wrapper>