Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/yupiik/yupiik-preact

A simple preact libraries set targetting configured UI (from static files or even a backend).
https://github.com/yupiik/yupiik-preact

configuration javascript preact

Last synced: about 4 hours ago
JSON representation

A simple preact libraries set targetting configured UI (from static files or even a backend).

Awesome Lists containing this project

README

        

= @yupiik/preact

[abstract]
Simple library enabling to render `preact` components from a registry + config and some utilities around JSON-RPC as a hook.
Overall goal is to configure its UI.

IMPORTANT: this library is not yet deployed on npm so you will have to install it locally yourself for now.

== Dynamic component Usage (@yupiik/dynamic)

[source,js]
----
import { render } from 'preact';
import { Dynamic } from '@yupiik/dynamic';

const registry = {
component1: Component1,
component2: Component2,
component3: Component3,
}

render(
,
document.getElementById('app'));
----

=== FromConfiguratonHoc

`FromConfiguratonHoc` is a companion for `Dynamic` (a HoC actually on top of `Dynamic`) which is purely configuration oriented.
It handles callbacks, children etc from plain JSON.

==== Configuration

Configuration schema (properties of the component):

[source,js]
----
{
registry = undefined,
parentState = undefined,
parentDispatch = undefined,
options: {
name,
options: {
useReducerCallback: {
initialState = undefined,
reducerJsonLogic = false,
} = {},
useEffectCallback = [],
callbacks = {},
configuration = {},
} = {},
},
}
----

[options="header"]
|===
|Property|Description
|registry|component registry (key matching the component name)
| name | the component name in the registry
| useEffectCallback | the useEffect callbacks properties definition in JSON-Logic format, it can be an array or an object (behaves as an array of 1 element). Each element is a JSON-Logic expression.
| useReducerCallback | the useReducer callbacks. initialState is the state initial value and reducerJsonLogic the JSON-Logic implementation which takes the current state and action as parameters. JSONLogic take the state and dispatch functions as parameters.
| callbacks | the callbacks properties definition in JSON-Logic format, key is the callback name and value its JSON-Logic chain. The JSON-Logic can use variables `state`, `dispatch` and `event` (the callback event).
| configuration | properties to passthrough the underlying component.
| parentState | if no initialState is passed it will be used to overwrite it, enables to forward through children the state when children are compatible.
| parentDispatch | parent dispatch callback (to be able to modify parent state).
|===

=== Registry context usage

In most applications, you will mix `Dynamic` with custom components.
For that case it is worth injecting the registry as a context at a high level of the application:

[source,js]
----
import { render } from 'preact';
import { Dynamic, ComponentRegistryContext } from '@yupiik/preact';
import MyComponent from './my-component';

const registry = {
component1: Component1,
component2: Component2,
component3: Component3,
}

render(


,
document.getElementById('app'));
----

This simple snippet enables any nested component like `MyComponent` to reuse `Dynamic` without specifying the registry which allows to write reusable component more easily:

[source,js]
----
export const MyComponent = () => (

);
----

=== Note about the configuration

In a real application, you will often have a tree of `Dynamic`.

If your backend supports bulking (JSON-RPC is highly recommended but GraphQL or other protocols can support it), we recommend you to wrap `Dynamic` to enable to bulk the requests by stashing them and to issue a single HTTP request for the component tree.

It is mainly a matter of abstracting the communication with the backend for the components and having a toggle to know if all subcomponents got an initial render or not.

== ANT Design integration (@yupiik/antd-registry)

`@yupiik/antd-registry` provides a component registry which works with `Dynamic` or `FromConfiguratonHoc`.

== React component based libraries (Bootstrap, Feather, ...)

`react-bootstrap` can be integrated importing it (`import * as reactBootstrap`) and converting the import to a registry using `@yupiik/dynamic` `nestedRegistry` fonction.

Similarly `react-feather` which does not use nested components can be converted to a registry the same way but using `simpleRegistry` function is more efficient instead of `nestedRegistry`.

Using this method on `react-bootstrap`, you will get in in the registry, as of today, the following list of component:

* Accordion
* Accordion.Button
* Accordion.Collapse
* Accordion.Item
* Accordion.Header
* Accordion.Body
* AccordionButton
* AccordionCollapse
* AccordionContext
* AccordionContext.Consumer
* AccordionContext.Provider
* AccordionHeader
* AccordionItem
* Alert
* Alert.Link
* Alert.Heading
* AlertHeading
* AlertLink
* Anchor
* Badge
* Breadcrumb
* Breadcrumb.Item
* BreadcrumbItem
* Button
* ButtonGroup
* ButtonToolbar
* Card
* Card.Img
* Card.Title
* Card.Subtitle
* Card.Body
* Card.Link
* Card.Text
* Card.Header
* Card.Footer
* Card.ImgOverlay
* CardBody
* CardFooter
* CardGroup
* CardHeader
* CardImg
* CardImgOverlay
* CardLink
* CardSubtitle
* CardText
* CardTitle
* Carousel
* Carousel.Caption
* Carousel.Item
* CarouselCaption
* CarouselItem
* CloseButton
* Col
* Collapse
* Container
* Dropdown
* Dropdown.Toggle
* Dropdown.Menu
* Dropdown.Item
* Dropdown.ItemText
* Dropdown.Divider
* Dropdown.Header
* DropdownButton
* DropdownDivider
* DropdownHeader
* DropdownItem
* DropdownItemText
* DropdownMenu
* DropdownToggle
* Fade
* Figure
* Figure.Image
* Figure.Caption
* FigureCaption
* FigureImage
* FloatingLabel
* Form
* Form.Group
* Form.Control
* Form.Floating
* Form.Check
* Form.Switch
* Form.Label
* Form.Text
* Form.Range
* Form.Select
* Form.FloatingLabel
* FormCheck
* FormCheck.Input
* FormCheck.Label
* FormControl
* FormControl.Feedback
* FormFloating
* FormGroup
* FormLabel
* FormSelect
* FormText
* Image
* InputGroup
* InputGroup.Text
* InputGroup.Radio
* InputGroup.Checkbox
* ListGroup
* ListGroup.Item
* ListGroupItem
* Modal
* Modal.Body
* Modal.Header
* Modal.Title
* Modal.Footer
* Modal.Dialog
* ModalBody
* ModalDialog
* ModalFooter
* ModalHeader
* ModalTitle
* Nav
* Nav.Item
* Nav.Link
* NavDropdown
* NavDropdown.Item
* NavDropdown.ItemText
* NavDropdown.Divider
* NavDropdown.Header
* NavItem
* NavLink
* Navbar
* Navbar.Brand
* Navbar.Collapse
* Navbar.Offcanvas
* Navbar.Text
* Navbar.Toggle
* NavbarBrand
* NavbarCollapse
* NavbarOffcanvas
* NavbarText
* NavbarToggle
* Offcanvas
* Offcanvas.Body
* Offcanvas.Header
* Offcanvas.Title
* OffcanvasBody
* OffcanvasHeader
* OffcanvasTitle
* OffcanvasToggling
* Overlay
* OverlayTrigger
* PageItem
* Pagination
* Pagination.First
* Pagination.Prev
* Pagination.Ellipsis
* Pagination.Item
* Pagination.Next
* Pagination.Last
* Placeholder
* Placeholder.Button
* PlaceholderButton
* Popover
* Popover.Header
* Popover.Body
* PopoverBody
* PopoverHeader
* ProgressBar
* Ratio
* Row
* SSRProvider
* Spinner
* SplitButton
* Stack
* Tab
* Tab.Container
* Tab.Content
* Tab.Pane
* TabContainer
* TabContent
* TabPane
* Table
* Tabs
* ThemeProvider
* Toast
* Toast.Body
* Toast.Header
* ToastBody
* ToastContainer
* ToastHeader
* ToggleButton
* ToggleButtonGroup
* ToggleButtonGroup.Button
* Tooltip

== useJsonRpc hook (@yupiik/use-json-rpc)

=== Usage

[source,js]
----
import { render } from 'preact';
import { useJsonRpc } from '@yupiik/use-json-rpc';

export const MyComponent = ({}) => {
const [ loading, error, data ] = useJsonRpc({
payload: {
jsonrpc: '2.0',
method: 'my-server-method',
params: {},
},
// optional
endpoint: '/jsonrpc',
needsSecurity: true,
fetchOptions: {},
dependencies: [],
});

if (loading) {
return ();
}

if (error) {
return ();
}

if (!data) {
return (

No data.
);
}

return (

{JSON.stringify(data, null, 2)}
);
};
----

=== Configuration

`useJsonRpc` hook takes the following properties in its object parameter:

[options="header"]
|===
| Name | Default | Description
|payload| - | JSON-RPC request, can be an array or an object.
|endpoint|/jsonrpc|JSON-RPC endpoint to call
|needsSecurity|true|Should `Authorization` header be appended from `SecurityContext.access_token` value as a bearer token.
|fetchOptions|`{}`|Any `fetch` option merged with computed ones from other parameters.
|dependencies|`[endpoint,payload,providedData]`|`useEffect` dependencies, by default it uses the request but customizing it can enable to avoid rendering loops.
|fetch|`fetch`|The `fetch` function to use, default to global javascript one.
|providedData|-|The JSON-RPC data result (if provided, ie thruthy, it will be used and the server call will be bypassed).
|===

=== Use `SecurityContext` provider

When you keep `needsSecurity` to `true`, you must pass a `SecurityContext.Provider`:

[source,js]
----
import { SecurityContext } from '@yupiik/use-json-rpc';

export const MyComponent = () => (



);
----

TIP: it is often done at a high level of the application to be shared accross all components.

== Build

Project uses `lerna`.
To build all modules run:

[source,bash]
----
npm i
npm run build

# optionally to run tests
npm run test
----