Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/gluecodes/gluecodes-glue-dom
Makes non-trivial UI components easy to read and maintain.
https://github.com/gluecodes/gluecodes-glue-dom
Last synced: 2 months ago
JSON representation
Makes non-trivial UI components easy to read and maintain.
- Host: GitHub
- URL: https://github.com/gluecodes/gluecodes-glue-dom
- Owner: gluecodes
- License: mit
- Created: 2018-04-08T14:42:50.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2023-01-07T06:26:48.000Z (about 2 years ago)
- Last Synced: 2024-05-01T09:47:43.281Z (8 months ago)
- Language: JavaScript
- Homepage: https://www.glue.codes
- Size: 1.21 MB
- Stars: 7
- Watchers: 3
- Forks: 1
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# @gluecodes/glueDom
Makes non-trivial UI components easy to read and maintain.
It has been made to abstract-away [SolidJS'](http://solidjs.com/) HyperScript to generate reactive code in [GlueCodes Studio](https://ide.glue.codes) on the fly.
- It can be transformed in maintainable and scalable manner.
- Gradual learning curve, no need to learn another templating syntax (directives etc.).
- Reads sequentially as HTML while remaining readable and maintainable.
- Isn't a mix of HTML and JavaScript drawing a clear border between view and logic.
- Allows formatting texts without writing nested inline tags.
- Makes writing dynamic texts easier with no need for checking whether variables are non-empty.## Table of Contents
- [Problem](#problem)
- [Syntax Comparison](#syntax-comparison)
- [JSX](#jsx)
- [HyperScript](#hyperscript)
- [GlueDOM](#gluedom)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Advanced Usage](#advanced-usage)
- [GlueDOM Syntax](#gluedom-syntax)
- [Rendering a Tag](#rendering-a-tag)
- [Inside Tag Callback](#inside-tag-callback)
- [Api](#api)
- [Contributing](#contributing)
- [License](#license)## Problem
The ideal syntax for rendering DOM should mimic HTML in a way it reads sequentially from top to bottom.
For single logical UI unit, there shouldn't be a need for local variable declarations or using partial functions.Consider the two most common ways of rendering DOM; JSX and HyperScript. They work well in simple demo scenarios with no nested conditional logic.
When the nested conditionals are required, you end up using a mix of logical expressions, ternary and spread operators.## Syntax Comparison
Consider the following example; Write a function which renders condition-based HTML.
There is `someCondition` prop which needs to be truthy to display a section which contains other nested conditionals.
`firstProgrammer` and `secondProgrammer` are both optional.### JSX
Since you can't use block statements, you're forced to use unreadable mix of logical and ternary operators.
```jsx
({
firstProgrammer,
secondProgrammer,
someCondition
}) => (
{someCondition
&& (firstProgrammer && secondProgrammer
?{firstProgrammer}, you're going to do pair-programming with {secondProgrammer}.
: (firstProgrammer && !secondProgrammer
?{firstProgrammer}, you'll code this task by yourself.
:Hey man! Can you tell us your name before we give you job to do?
))}
)
```### HyperScript
Similarly to JSX, yet to the mix of unreadable ternary operators you're forced to add spread operator.
```javascript
({
firstProgrammer,
secondProgrammer,
someCondition
}) => h('div', {}, [
...(someCondition ? [h('p', {}, [
...(firstProgrammer && secondProgrammer ? [
h('strong', {}, [
firstProgrammer
]),
`, you're going to do pair-programming with ${secondProgrammer}.`,
] : []),
...(firstProgrammer && !secondProgrammer ? [
h('strong', {}, [
firstProgrammer
]),
', you\'ll code this task by yourself.',
] : []),
...(!firstProgrammer && !secondProgrammer ? [
'Hey man! Can you tell us your name before we give you job to do?',
] : [])
])] : [])
])
```### GlueDOM
Here you can use block statements. When calling `text`, all its arguments are checked whether they are truthy and only if they are, they will be concatenated and rendered.
There is also a concept of formatters which are configured when initializing the top-most `tag`, and they can wrap texts inside a chosen tag and apply CSS classes on it.
In this case `bold` is configured to wrap props inside `` tag.
Nesting is possible by simply nesting objects e.g. `{ bold: { italic: 'some text' } }`.```javascript
({
firstProgrammer,
secondProgrammer,
someCondition
}) => (
tag('div', (props, { tag }) => {
if (someCondition) {
tag('p', (props, { text }) => {
text({ bold: firstProgrammer }, ', you\'re going to do pair-programming with ', secondProgrammer, '.')
if (!secondProgrammer) {
text({ bold: { italic: firstProgrammer } }, ', you\'ll code this task by yourself.')
}
if (!firstProgrammer && !secondProgrammer) {
text('Hey man! Can you tell us your name before we give you job to do?')
}
})
}
})
)
```## Installation
Run:
```bash
yarn add https://ide.glue.codes/repos/df67f7a82cbdc5efffcb31c519a48bf6/core/glueDom-1.0.1.tar.gz
```
Or:
```bash
npm i https://ide.glue.codes/repos/df67f7a82cbdc5efffcb31c519a48bf6/core/glueDom-1.0.1.tar.gz --save
```## Basic usage
`renderer.js`:
```javascript
import React from 'react'
import { createRenderer } from '@gluecodes/glueDom'export default createRenderer({
createDomElement: React.createElement
})
````component.js`:
```javascript
import tag from './renderer'export default () => tag('div', (props, { text }) => {
text('hello world!')
})
```## Advanced Usage
`renderer.js`:
```javascript
import React from 'react'
import { createRenderer } from '@gluecodes/glueDom'
import styles from './textFormatters.css'export default createRenderer({
createDomElement: React.createElement,
formatters: {
bold: () => ({
tag: 'strong',
props: { className: styles.bold }
}),
italic: () => ({
tag: 'span',
props: { className: styles.italic }
})
}
})
````component.js`:
```javascript
import tag from './renderer'export default ({
email,
firstName,
interests,
surname
}) => (
tag('p', (props, { text }) => {
text(
'You can format an email like this: "', { bold: { italic: email } },
'" and the whole sentence will appear only if email: ', email, ', firstName: ', firstName, ' and surname: ', surname, 'aren\'t empty. ',
'It can be especially useful when generating documents from ', { bold: 'dynamic' }, ' fields coming from backend.'
)
})
)
```
### GlueDOM Syntax### Rendering a tag
**Nesting**
```
tag(tagName, (props, { component, tag, text }) => {
props.className = 'outerMostTag'
tag(tagName, (props, { component, tag, text }) => {
props.className = 'innerTag'
tag(tagName, (props, { component, tag, text }) => {
props.className = 'innerMostTag'
...
})
})
})
```**Assigning props to an element containing child elements or text**
```
tag(tagName, (props, { text }) => {
props.className = 'someClass'
props.title = 'some tooltip'
...text('some text')
})
```**No child elements nor text**
```
tag(tagName, {
[props]
})
```**No child elements nor props**
```
tag(tagName)
```#### Inside Tag Callback
**Nested Tag**
```
tag(tagName, ...)
```**Components**
```
component(reusableUiPiece, props)
```**Text**
```
text(...[textChunk,])
```- `tagName` A string that specifies the type of element to be created
- `props` An object to assign element props/attributes
- `component` A function to render component
- `tag` A function to create an element
- `text` A function to create text
- `reusableUiPiece` A function returning reusable DOM
- `textChunk` Either a string or an object which uses text formatters. If any chunk is empty, the whole sentence won't be rendered## API
```javascript
createRenderer(config)
```- `createRenderer()` A function to create initial `tag()` function based on provided `config`
- `config` (optional) An object containing configuration
- `config.createDomElement` (optional) A function to create DOM element.
When specified, it should implement HyperScript-like interface/API
- `config.formatters` An object of functions. They may be used in `text()` to wrap given string into `tag` with `props` of `config.formatters[formatterName]() => ({ tag, props })`
- `formatterName` A string identifying a formatter which may be used in `text()` like `text({ [formatterName]: 'given string' })`
- `tag` A string that specifies the type of element to be used for text wrapping
- `props` An object of props to be set on the wrapping element## Contributing
Feel free to rise issues, open PRs or contact at [email protected] about any ideas/criticism.
## License
[MIT](https://github.com/gluecodes/gluecodes-glue-dom/blob/master/LICENSE.md)