All Projects → uqbar-project → njsx

uqbar-project / njsx

Licence: other
A customizable and declarative interface for creating React and React Native components without JSX syntax.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to njsx

lowcode
React Lowcode - prototype, develop and maintain internal apps easier
Stars: ✭ 32 (+10.34%)
Mutual labels:  builder, jsx, tsx
Jsx Lite
Write components once, run everywhere. Compiles to Vue, React, Solid, Angular, Svelte, and Liquid.
Stars: ✭ 1,015 (+3400%)
Mutual labels:  builder, jsx
typesafe-templates
Template engine that leverages JSX to generate JavaScript code from TypeScript code files rather than text templates.
Stars: ✭ 27 (-6.9%)
Mutual labels:  jsx, tsx
vuetify-tsx
Vuetify TSX is just a wrapper lib around vuetify components.
Stars: ✭ 20 (-31.03%)
Mutual labels:  jsx, tsx
Dependency Cruiser
Validate and visualize dependencies. Your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.
Stars: ✭ 2,326 (+7920.69%)
Mutual labels:  jsx, tsx
Inferno Most Fp Demo
A demo for the ReactJS Tampa Bay meetup showing how to build a React+Redux-like architecture from scratch using Inferno, Most.js, reactive programmning, and various functional programming tools & techniques
Stars: ✭ 45 (+55.17%)
Mutual labels:  functional, jsx
ios-scriptable-tsx
在 vscode 上使用 typescript 和 jsx 开发 ios 小组件的小框架.基于 Scriptable app.
Stars: ✭ 113 (+289.66%)
Mutual labels:  jsx, tsx
harshhhdev.github.io
Harsh Singh's personal blog and portfolio ⚡ built with Next.js
Stars: ✭ 23 (-20.69%)
Mutual labels:  jsx, tsx
vue3-jd-h5
🔥 Based on vue3.0.0, vant3.0.0, vue-router v4.0.0-0, vuex^4.0.0-0, vue-cli3, mockjs, imitating Jingdong Taobao, mobile H5 e-commerce platform! 基于vue3.0.0 ,vant3.0.0,vue-router v4.0.0-0, vuex^4.0.0-0,vue-cli3,mockjs,仿京东淘宝的,移动端H5电商平台!
Stars: ✭ 660 (+2175.86%)
Mutual labels:  jsx, tsx
element
Fast and simple custom elements.
Stars: ✭ 65 (+124.14%)
Mutual labels:  jsx, tsx
md-editor-v3
Markdown editor for vue3, developed in jsx and typescript, dark theme、beautify content by prettier、render articles directly、paste or clip the picture and upload it...
Stars: ✭ 326 (+1024.14%)
Mutual labels:  jsx, tsx
Esbuild
An extremely fast JavaScript and CSS bundler and minifier
Stars: ✭ 29,374 (+101189.66%)
Mutual labels:  jsx, tsx
vscode-ecsstractor
Extracting selectors from HTML / JSX / TSX and generate CSS file.
Stars: ✭ 45 (+55.17%)
Mutual labels:  jsx, tsx
vue-typescript-tsx
🤓vue typeScript jsx 工程示例
Stars: ✭ 32 (+10.34%)
Mutual labels:  jsx, tsx
core
Light weight feature rich UI Framework for JavaScript for Browser with Dependency Injection, Mocking and Unit Testing
Stars: ✭ 18 (-37.93%)
Mutual labels:  jsx, tsx
Pypika
PyPika is a python SQL query builder that exposes the full richness of the SQL language using a syntax that reflects the resulting query. PyPika excels at all sorts of SQL queries but is especially useful for data analysis.
Stars: ✭ 1,111 (+3731.03%)
Mutual labels:  builder, functional
swift-declarative-configuration
Declarative configuration for your objects
Stars: ✭ 46 (+58.62%)
Mutual labels:  builder, functional
vite-vue-admin
🎉🎉使用Vite + Vue3 + TypeScript + Element-plus + Mock开发的后台管理系统🎉🎉
Stars: ✭ 97 (+234.48%)
Mutual labels:  jsx, tsx
indent.js
Pure code indentation for jsx, tsx, ts, js, html, css, less, scss.
Stars: ✭ 55 (+89.66%)
Mutual labels:  jsx, tsx
slim-routing
Slim framework powered-up routing
Stars: ✭ 14 (-51.72%)
Mutual labels:  builder

No-JSX

Build Status npm version

A pure function based interface for creating React and React Native components without JSX tags.

If you love React but don't quite like the embeded HTML tags this library may be what you are looking for. Construct your components with code only in a clean, declarative way.

const myView = () =>
  div.app(
    div.header(
      img({src: logo, alt:'logo'}),
      h2('Welcome to NJSX')
    )
  )()

Table of Content


Installation

NJSX is available on npm, just pick between the React and React Native flavours and add it to your project's dependencies.

For React Projects:

npm install njsx-react --save

For React Native Projects:

npm install njsx-react-native --save

Usage

NJSX is super easy to use: It's all about Builder Functions.

You can use Builders to to cleanly instantiate React and React Native elements, or further refine your component configuration just by applying them.

Getting a Builder

Default Component Builders

NJSX provides Builder Functions for all the default React and React Native components. Just import whatever element you need from the react or react-native modules and you are ready to go:

// React project
import {div, p} from 'njsx-react'

// React Native project
import {View, Text} from 'njsx-react-native'

Third-Party Component Builders

NJSX is not just for default components! You can get a builder for any component just by wrapping it with the njsx adapter.

// This is NJSX core. Both njsx-react and njsx-react-native use it to define their builders.
import njsx from 'njsx'
import {SomeThirdPartyComponent} from 'someLibrary'

const SomeFunctionalComponent = (props) => ...
class SomeStatefulComponent extends React.Component {
  render() { ... }
}

// These are all valid Component Builders.
const someComponent = njsx(SomeComponent)            
const someFunctionalComponent = njsx(SomeFunctionalComponent)
const someStatefulComponent = njsx(SomeFunctionalComponent)

// You can even use a string as component type (although it's not recommended):
const aDivBuilder = njsx('div')

Creating Elements

Each NJSX builder, once applied with no arguments, will return a ReactElement just as if you had used the component inside a JSX tag:

import {div} from 'njsx-react'

// These two lines are equivalent.
<div></div>
div()

This means that JSX and NJSX elements are completely interchangeable. You can use components created from builders as children for JSX's tags, or refine a builder with tag shaped children, so you can try NJSX on any react based project and integrate it gradually.

Refining Builders

Of course, an empty element is not that useful, so how do you customize it?

When a Builder is applied with one or more arguments, these will be used to configure the building component. Refining a Builder this way returns another Builder, so you can keep refining your component any number of times.

import {p} from 'njsx-react'

p('some text')
p('some', ' ', 'text')
p('some')(' ')('text')
p(['some', ' ', 'text'])

// All these lines build the same:
<p>some text</p>

It's important to note that refining a builder causes no side effects or state changes at all. This means you can safely reuse Builders, or partially refine one and pass it forward.

Builder Arguments

Builders will get refined in a different way, depending on what arguments you apply them with:

  • Basic Objects are treated as Component Properties. Refining a builder with a second set of properties will result in the merge of both, favoring the later in case of repetition.

    img({src: path, onClick: cb})
    img({src: path}, {onClick: cb})
    img({src: thisWillBeLost, onClick: cb})({src: path})
    
    // All these lines build the same:
    <img src={path} onClick:{cb}></img>
  • Strings, Numbers, React Elements and even other Builders will become Component Children.

    div(
      div('the answer is ', 42)  // <- No need for building it.
    )
    
    // This line builds:
    <div><div>the answer is 42</div></div>

    Notice that, since Builders can be children too, most of the time you won't be needing to apply them with no arguments to instantiate elements.

  • null, undefined and Booleans will be ignored. This allows for a clean way to conditionally set properties and children using && and ||.

    div(null)
    div(undefined)
    div(false && "this won't show")
    
    //All these lines the same:
    <div/>
  • Arrays of any valid argument will be handled as a sequence of refinements.

    const guards = ['Nobby', 'Colon', 'Carrot']
    
    ul(guards.map(guard => li(guard)))
    ul(guards.map(li))
    
    //All these lines the same:
    <ul>{guards.map(guard => <li>{guard}</li>)}</ul>
  • Finally, you can also pass a Refinement Function, which should take the previous Component Properties (including the children field) and return the next one.

    const myRefinement = (src, text) => (prev) =>
      {...prev, {src, children: text} }
    img(myRefinement(foo, bar))
    
    // This line builds:
    <img src={foo}>bar</img>

To wrap it all, any unsuported argument application will raise a TypeError.

Dynamic Selectors

You can also refine a Builder by accessing any keyword as if it was a property. A common use for this is to treat the keyword as a className, so you can add classes to components by just naming them:

p.highlighted.small("Nice!")
p['highlighted']['small']("Nice!")
p['highlighted small']("Nice!")
p("Nice!").highlighted['.small']

//All these lines build the same:
<p className="highlighted small">Nice!</p>

Treating these selectors as class names is the default behavior of NJSX, but you can change it to whatever you want by changing the NJSXConfig. dynamicSelectorHandler setting:

import { NJSXConfig } from 'njsx'

// You can set any function that receives the key and returns a valid argument.
NJSXConfig.dynamicSelectorHandler = (key: string) => key

div.foo.bar
// This would yield
<div>foobar</div>


// That means you could also return a refining function!
NJSXConfig.dynamicSelectorHandler = (id: string) => (prev) =>
  {...prev, id}

div.baz
// This would yield
<div id="baz"/>


// You can also disable the whole thing by setting it to undefined.
NJSXConfig.dynamicSelectorHandler = undefined

Notice that this feature can only be used on environments that support ES6's Proxy so, sadly, it's not available on React-Native projects.

Argument Transformation

You don't like the way arguments are being handled? No problem! You can customize the way NJSX's Builders interpret arguments to fine tune it to your needs.

The NJSXConfig object can be used to specify Argument Transformations, which are just functions that take each argument and return whatever you want that argument to be. These functions are automatically called each time a Builder is applied.

import { NJSXConfig } from 'njsx'
import {p} from 'njsx-react'

const translations = {
  "this should be translated": "ook"
}

NJSXConfig.argumentTransformations.push( arg =>
  typeof arg === 'string' && arg.startsWith('!')
    ? translations[arg]
    : arg
)

p("!this should be translated")

// This build:
<p>ook</p>

Please take into account that all transformations are reduced on every argument, so don't overdo it and mind the order.

NJSX comes with some of these transformations set up by default:

  • In React projects, Strings starting with a dot will be interpreted as a classNames:

    div('.foo .bar')(
      'Some content'
    )
    
    // This builds:
    <div className="foo bar">Some content</div>
  • In React-Native projects, StyleSheet arguments are interpreted as styles (Just import StyleSheet from njsx-react-native instead of react-native).

    import {StyleSheet, View, Text} from 'njsx-react-native'
    
    // Same StyleSheet interface
    StyleSheet.create({
      container: { /* ...your regular react-native styles... */ }
      description: { /* ...your regular react-native styles... */ }
    })
    
    View(styles.container)(
      Text(style.description)("These are styled!")
    )

If you rather all your arguments to just be interpreted as they are, you can disable this feature by setting the NJSXConfig.argumentTransformations to an empty array.

Point-free

Think point-free composition in your render function is a pipe dream? Think again, you can use njsx to compose components in a point-free style to help with the readability of deeply nested react components:

<Provider store={store}>
  <PersistGate loading={null} persistor={persistor}>
    <BrowserRouter>
      <Route path="/" component={App} />
    </BrowserRouter>
  </PersistGate>
</Provider>

Becomes:

import { compose } from 'rambda'

compose(
  Provider({ store }),
  PersistGate({ loading: null, persistor }),
  BrowserRouter,
  Route
)({ path: '/', component: App })()

Please note that compose and pipe functions vary in implementation and not all will work with njsx, for example, lodash/fp seems to have issues at the moment, while rambda is working without issue.

Working with older versions

If you are working with an older release this documentation might not be of any use to you. We follow the semantic versioning standard so any difference on the Major version will probably imply some incompatibilities. Please refer to your version's branch README file.

Contributions

Please report any bugs, requests or ideas on the issues section of this repository and we will try to see to it as soon as possible. Pull requests are always welcome! Just try to keep them small and clean.

License

This code is open source software licensed under the ISC License by The Uqbar Foundation. Feel free to use it accordingly.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].