Giter Club home page Giter Club logo

jsonx's Introduction

JSONX

Coverage Status Build, Test & Coverage

Description

JSONX is a module that creates React Elements, JSX and HTML from JSON.

Declarative

The JSONX web module comes with batteries included so you can use JSONX in the browser without transpilers or any additional setup/configuration. The JSONX UMD is ideal for JAMstack Applications.

Embeddable

JSONX can also be used in existing react applications if you want to dynamically create elements with JSON. This works great for many scenarios when you want to manage your application views and components in a view management system or if you want to dynamically create React elements without using JSX.

Fully Featured

JSONX supports all of Reacts features including Functional (with Hooks), Class-based, Suspense and Lazy components. JSONX supports JSON objects that implement the JXM (JSONX Markup) Spec.

Installation

$ npm i jsonx

JSONX Manual


Basic Usage

import { * as jsonx } from 'jsonx';
const example_JXM_JSON = {
  component:'p',
  props:{ style:{ color:'blue' } },
  children:'hello world'
};

//Rendering React Components
jsonx.getReactElement(example_JXM_JSON); // => JSX Equivalent: <p style={{color:'blue'}}>hello world</p>

//Generating HTML strings
jsonx.outputHTML({ jsonx: example_JXM_JSON, }); // => '<p style="color:blue;">hello world</p>'

//Generating JSX strings
jsonx.outputJSX({ jsonx: example_JXM_JSON, }); // => '<p style={{color:blue,}}>hello world</p>'

//Rendering HTML Dom with React
jsonx.jsonxRender({ jsonx: example_JXM_JSON, querySelector:'#myApp', });
// <!DOCTYPE html>
//  <body>
//    <div id="myApp">
//      <p style="color:blue;">hello world</p>
//    </div>
// </body>

//you can also use the simplified syntax
const simpleJXM_JSON = {
  p:{
    props:{ style:{ color:'blue' } },
    children:'hello world'
  }
}

//or if you have an element with no props, simply use {type:children}
const superSimpleJXM = {
  ul:[
    {li:'first!'},
    {li:'second!'},
  ]
}

JXM JSON Spec

JSONX works by using JXM JSON to create react elements. JXM JSON Objects are valid JSON Objects that more or less mimics JSX in JSON notation with a couple of special properties. The properties for JSONX JSON are the arguments passed to React.createElement. The only required property is the component (which is passed as the type argument)

React.createElement(
  type,
  [props],
  [...children]
)

You can pass React component libraries for additional components, or you own custom components (see External and Custom Components and Using Advanced Props for more details).

Development

Note Make sure you have typescript installed

$ npm i -g typescript 

For generating documentation

$ npm run doc

Notes

Check out https://repetere.github.io/jsonx/ for the full jsonx Documentation

Testing

$ npm test

Contributing

Fork, write tests and create a pull request!

License


MIT

jsonx's People

Contributors

actions-user avatar dependabot[bot] avatar franz-fletcher avatar janbialostok avatar renovate-bot avatar semantic-release-bot avatar yawetse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

jsonx's Issues

Preview jsonx definition in a React App

What would you recommend to preview a jsonx definition in a React App?

Let's say my react app returns a Home functional component with some layout, and on this page I want to preview a jsonx definition of a functional component.

jsonxRender does the job in the browser, but how would I make my Home component to return the functional component from jsonx definition.

How do I evaluated props in JSONX

Hi ,

First of all this is a very impressive project and congratulations for that.

Here is what I am trying

const HelloWorld = ({name}: {name: string}) => <p>Hello {name}</p>

How can I have the "name" prop be passed and evalualated properly
If there is an example , please point me to it.

Thanks

Doc Links Broken

All of the links to the documentation files are broken in README.MD and return 404s

Fails on create-react-app (CRA) due to optional chaining syntax

Failed to compile.

./node_modules/jsonx/dist/index.umd.js 53630:28
Module parse failed: Unexpected token (53630:28)
File was processed with these loaders:
 * ./node_modules/react-scripts/node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|       }, {
|         FormComponent: FormComponent.bind(this)
>       }, componentMap, this?.reactComponents);
|       const reactComponents = boundedComponents.length ? getBoundedComponents.call(this, {
|         boundedComponents,

Any recommendations on how to resolve this?

Using asyncprops

My jsonx looks something like this...

const config = {
  component: "Card",
  children: [
    {
      component: "CardHeader",
      props: {
        title: "Test Header"
      }
    },
    {
      component: "CardContent",
      children: [
        {
          component: "AttributeTable",
          asyncprops: {
            data: ["attributes"]
          }
        }
      ]
    }
  ]
}

Above I have specified asyncprops on the AttributeTable component.

My traverseObject looks like this...

const data = {
  attributes: [
    {label: "test label 1", value: "test value 1"},
    {label: "test label 2", value: "test value 2"},
    {label: "test label 3", value: "test value 3"}
  ]
}

There is an "attributes" object which matches to the value specified in the asyncprops array.
The code looks like this...

const JSONXP = jsonx._jsonxProps.getJSONXProps({ jsonx: config, traverseObject: data });

When I inspect the result of JSONXP, it's just an empty object.

componentLibraries vs reactComponents

What is the difference between surrounding componentLibraries and reactComponents? In my application, the naming conventions range from:

<Button/>
<Layout.Full/>
<Layout.Center/>
<Select/>
<Select.Item/>
<Menu/>

These are all my own custom components.

Methods?

Nice library!

I was wondering how one would go about passing lifecycle methods within the JSON?

Thanks!

validateJSONX throws true for a valid jsonx

Thank you for this great library. I'm reporting a bug with validateJSONX.

const jsonx = require("jsonx");

test("validate a valid jsonx shouldn't throw error", () => {
  const sampleJSONX = {
    component: "div",
    props: {
      id: "generatedJSONX",
      className: "jsonx"
    },
    asyncprops: {
      test: ["ok", "cool"]
    },
    children: [
      {
        component: "p",
        props: {
          style: {
            color: "red",
            fontWeight: "bold"
          }
        },
        children: "hello world"
      }
    ]
  };
  const validateJSONX = jsonx._jsonxUtils.validateJSONX;

 //BUG:  the following line will throw with a boolean value true.
  validateJSONX(sampleJSONX);
});

this in __functionProps

First thanks for this library. It solves exactly the problem I have (configuring UI and storing the setting into DB)

I tried to use __functionProps and the this is something different then I would expect. I have jsonx like this:

{
    "component": "Fragment",
    "children": [
        {
            "component": "MyComponent",
            "resourceprops": { ... },
            "__functionProps": {
                "function": "func:this.functions.getValue"
            }
        }, 
        ....
    ]
}

my resourceObject:

{
    "someValues": {...},
    "functions": {
        "getValue": () => "getValue result"
    }
}

and I call

jsonx.getReactElement(jsonx, resourceObject);

When I call getValue function in MyComponent I get undefined result. Actually it is calling empty function generated here: https://github.com/repetere/jsonx/blob/master/src/props.js#L388

After some debugging I noticed that this in getFunctionFromProps is part of jsonx (the MyComponent child) and not the resourceObject.

What is the use case for calling function on props (this), that you will get in a component and you can call it there?
Is this intentional or a bug?
Am I doing something wrong?
Is it possible to call a function on resourceObject?

Thank you.

What about converting JSX to JSONX ?

It's really neat that this library allows React components to be rendered from JSON.

But what about going the other way? i.e. starting with JSX and converting that to JSONX syntax?

I have this idea where a user writes some JSX code (perhaps in web-based GUI), and then I'd like to serialize it to JSONX, so it can be stored in a database. Then I'd be able to send it via an API to some other app, where it can be translated back to JSX and rendered.

is that possible with this or any other library?

Cannot use library in nodejs environment

If I try import library in commonjs style (i set in packages.json type: "commonjs")

const jsonx = require('jsonx')

I got that error

internal/modules/cjs/loader.js:1092
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
      ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/dimensi/projects/parse-archives/node_modules/jsonx/dist/index.cjs.js
require() of ES modules is not supported.
require() of /Users/dimensi/projects/parse-archives/node_modules/jsonx/dist/index.cjs.js from /Users/dimensi/projects/parse-archives/render-jsx.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.cjs.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/dimensi/projects/parse-archives/node_modules/jsonx/package.json.

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:13)
    at Module.load (internal/modules/cjs/loader.js:940:32)
    at Function.Module._load (internal/modules/cjs/loader.js:781:14)
    at Module.require (internal/modules/cjs/loader.js:964:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/Users/dimensi/projects/parse-archives/render-jsx.js:2:15)
    at Module._compile (internal/modules/cjs/loader.js:1075:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1096:10)
    at Module.load (internal/modules/cjs/loader.js:940:32)
    at Function.Module._load (internal/modules/cjs/loader.js:781:14) {

If I try import library in esm style (I set type: 'module' in package.json). I got next

import jsonx from 'jsonx'
import jsonx from 'jsonx'
       ^^^^^
SyntaxError: The requested module 'jsonx' does not provide an export named 'default'
    at ModuleJob._instantiate (internal/modules/esm/module_job.js:98:21)
    at async ModuleJob.run (internal/modules/esm/module_job.js:137:5)
    at async Loader.import (internal/modules/esm/loader.js:165:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)

If I try import with as

import * as jsonx from 'jsonx
Object.defineProperty(exports, '__esModule', { value: true });
                      ^

ReferenceError: exports is not defined
    at file:///Users/dimensi/projects/parse-archives/node_modules/jsonx/dist/index.cjs.js:3:23
    at ModuleJob.run (internal/modules/esm/module_job.js:140:23)
    at async Loader.import (internal/modules/esm/loader.js:165:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)

I don't know how to import package in nodejs...

Also I try use parcel for import package and I got here another problem:

console.log(outputJSX({
  component:'p',
  props:{ style:{ color:'blue' } },
  children:'hello world'
})) -> <p style={[Object object]}>hello world</p>

Integrating with Redux

I am looking to connect my created RJX component to Redux. Is it even possible to do so using the following example?

import * as RJX from "rjx/dist/rjx.esm";

const data = {
  getInitialState:{},
  componentDidMount:{}
  ...
}

const Test = RJX._rjxComponents.getReactComponent(data);

Is it a case of connecting the component returned via RJX._rjxComponents.getReactComponent? I did give that a try, and did not get any joy from that.

import * as RJX from "rjx/dist/rjx.esm";

const data = {
  getInitialState:{},
  componentDidMount:{}
  ...
}

const Test = RJX._rjxComponents.getReactComponent(data);

const mapStateToProps = state => ({});
const mapDispatchToProps = dispatch => ({});

export default connect(mapStateToProps, mapDispatchToProps)(Test);

Make render index optional by default

Conclusion - https://medium.com/@adhithiravi/why-do-i-need-keys-in-react-lists-dbb522188bbb
Let’s recap the highlights from this post.

  1. Lists are performant heavy and need to be used carefully.
  2. Make sure every item in the list has a unique key.
  3. It is prefered to not use indexes as a key unless you know for sure that the list is a static list (no additions/re-ordering/removal to the list).
  4. Never use unstable keys like Math.random() to generate a key.
  5. React will run into performance degradation and unexpected behaviour if unstable keys are used

.

Usage with Create React App

This is an awesome library that pretty much solves an issue I am trying to solve.

The only issue I am having is getting this to play nicely with Create React App. Is that even possible?

Abstract library to accept alternative JXM providers

It's not a major change, but certainly a major paradigm pivot. It would be awesome to pivot this library from being strictly React specific, and allow the user to specify a JXM renderer themselves.

i.e., instead of using React.createElement, it would be cool if I could pass a function to JSONX that would be invoked whenever an element is created.

The implementation might look like simply abstracting all React.createElement calls to a jxmProvider(type, props, children), and probably making (...args) => React.createElement(...args) the default provider or something.

I put together something very similar to this utility for React, and this is a feature I was planning on adding, but I think it makes a lot of sense to go with something that already exists.

add ref

if (renderedCompProps.ref) {
      renderedCompProps.ref = getFunction({ propFunc: renderedCompProps.ref, });
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.