Skip to content

Commit

Permalink
Merge pull request #20 from bangank36/feat/introduce-navigator-layout
Browse files Browse the repository at this point in the history
WP-Builder: Feat/introduce-navigator-layout
  • Loading branch information
bangank36 authored Jul 6, 2023
2 parents fc194db + da7947e commit 8c55874
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 67 deletions.
102 changes: 35 additions & 67 deletions src/js/component/form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,86 +9,53 @@ import MultilineTextControl, { multilineTextControlTester } from "../renderers/M
import ColorPaletteTextControl, { colorPaletteControlTester } from "../renderers/ColorPaletteControl";
import BooleanToggleControl, { booleanToggleControlTester } from "../renderers/BooleanToggleControl";
import BooleanCheckboxControl, { booleanCheckboxControlTester } from "../renderers/BooleanCheckboxControl";
import GutenbergNavigatorlLayoutRenderer, { gutenbergNavigatorLayoutTester } from "../renderers/NavigatorLayout";

const schema = {
type: "object",
properties: {
textControl: {
type: "string",
label: "Text Control Label",
description: "Text Control displays a 'string' Control"
},
multilineTextControl: {
type: "string",
label: "Muliline Text Control Label",
description: "Multiline Text Control displays a 'string' Control supports multiline"
},
colorPaletteControl: {
type: "string",
label: "Color Palette Control Label",
description: "Color Picker with predefine palette"
},
booleanToggleControl: {
type: "boolean",
label: "Boolean Toggle Control Label",
description: "Boolean Control with Toggle Renderer"
address: {
type: 'object',
properties: {
street_address: { type: 'string' },
city: { type: 'string' },
state: { type: 'string' },
user: {
type: 'object',
properties: {
name: { type: 'string' },
mail: { type: 'string' },
}
}
}
},
booleanCheckboxControl: {
type: "boolean",
label: "Boolean Checkbox Control Label",
description: "Boolean Control with Checkbox Renderer"
business: {
type: 'object',
properties: {
job: { type: 'string' }
}
}
},
};

const uischema = {
type: "VerticalLayout",
type: "NavigatorLayout",
elements: [
{
type: "Control",
scope: "#/properties/textControl",
},
{
type: "Control",
scope: "#/properties/multilineTextControl",
options: {
multi: true,
},
},
{
type: "Control",
scope: "#/properties/colorPaletteControl",
options: {
format: 'color',
colors:[
{
color: '#f00',
name: 'Red'
},
{
color: '#fff',
name: 'White'
},
{
color: '#00f',
name: 'Blue'
}
]
},
},
{
type: "Control",
scope: "#/properties/booleanToggleControl",
options: {
toggle: true
}
},
{
type: "Control",
scope: "#/properties/booleanCheckboxControl",
type: 'VerticalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/address',
},
{
type: 'Control',
scope: '#/properties/business',
}
],
}
],
};
}

const initialData = {};

Expand All @@ -100,7 +67,8 @@ const renderers = [
{ tester: multilineTextControlTester, renderer: MultilineTextControl },
{ tester: colorPaletteControlTester, renderer: ColorPaletteTextControl },
{ tester: booleanToggleControlTester, renderer: BooleanToggleControl},
{ tester: booleanCheckboxControlTester, renderer: BooleanCheckboxControl}
{ tester: booleanCheckboxControlTester, renderer: BooleanCheckboxControl},
{ tester: gutenbergNavigatorLayoutTester, renderer: GutenbergNavigatorlLayoutRenderer}
];

export default function App() {
Expand Down
115 changes: 115 additions & 0 deletions src/js/renderers/NavigatorLayout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from "react"
import { rankWith, uiTypeIs } from "@jsonforms/core"
import { MaterialLayoutRenderer } from "./NavigatorRenderer"
import {
JsonFormsDispatch,
withJsonFormsLayoutProps
} from "@jsonforms/react"

import {
__experimentalNavigatorProvider as NavigatorProvider,
__experimentalNavigatorScreen as NavigatorScreen,
__experimentalNavigatorButton as NavigatorButton,
__experimentalNavigatorToParentButton as NavigatorToParentButton,
} from '@wordpress/components';

/**
* Default tester for a vertical layout.
* @type {RankedTester}
*/
export const gutenbergNavigatorLayoutTester = rankWith(
2,
uiTypeIs("NavigatorLayout")
)

export const GutenbergNavigatorlLayoutRenderer = ({
uischema,
schema,
path,
enabled,
visible,
renderers,
cells
}) => {
// nit: move this method into seperate file
/*
* Recursive method to get all the `object` type property and return them as { path, key }
* Note: so far the method skips the root node, and only looking inside the `properties` prop
*/
const getObjectProperties = (obj, parentPath = '') => {
const result = [];

for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const path = parentPath ? `${parentPath}/${key}` : `/${key}`;
// Convert the slash-string into dot-string, eg: /address/user - address.user
const dotPath = path.replace(/^\//, '').replace(/\//g, '.');
const prop = obj[key];

if (prop.type === 'object') {
result.push({ path, key, dotPath });
result.push(...getObjectProperties(prop.properties, path));
}
}
}

return result;
};

const navigatableProps = getObjectProperties(schema.properties);

// The navigatorLayout should be the root layout
const navigatorLayout = uischema

const childProps = {
elements: navigatorLayout.elements,
schema,
path,
enabled,
direction: "column",
visible
}

return (
<>
{/* <MaterialLayoutRenderer
{...childProps}
renderers={renderers}
cells={cells}
/> */}
<NavigatorProvider initialPath="/">
<NavigatorScreen path="/">
<p>This is the home screen.</p>
{navigatableProps.filter((({dotPath}) => dotPath.split(".").length < 2 )).map(({path, key, dotPath}, index) => (
<NavigatorButton path={`${path}`}>
<p>Go to <strong>{key}</strong> screen. {dotPath}</p>
</NavigatorButton>
))}
</NavigatorScreen>

{navigatableProps.map(({path, key, dotPath}, index) => (
<NavigatorScreen path={`${path}`}>
<p>This is the <strong>{key}</strong> screen. {dotPath}</p>
<NavigatorToParentButton>
Go back
</NavigatorToParentButton>
<NavigatorButton path="/">
<p>Go to home</p>
</NavigatorButton>
<JsonFormsDispatch
uischema={navigatorLayout.elements[0].elements[index]}
schema={schema}
path={dotPath}
enabled={enabled}
renderers={renderers}
cells={cells}
/>
</NavigatorScreen>
))}

</NavigatorProvider>
</>
)
}

export default withJsonFormsLayoutProps(GutenbergNavigatorlLayoutRenderer)
74 changes: 74 additions & 0 deletions src/js/renderers/NavigatorRenderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import isEmpty from "lodash/isEmpty"
import React from "react"
import { getAjv } from "@jsonforms/core"
import { JsonFormsDispatch, useJsonForms } from "@jsonforms/react"
import { Grid, Hidden } from "@mui/material"

export const renderLayoutElements = (
elements,
schema,
path,
enabled,
renderers,
cells
) => {
return elements.map((child, index) => (
<Grid item key={`${path}-${index}`} xs>
<JsonFormsDispatch
uischema={child}
schema={schema}
path={path}
enabled={enabled}
renderers={renderers}
cells={cells}
/>
</Grid>
))
}

const MaterialLayoutRendererComponent = ({
visible,
elements,
schema,
path,
enabled,
direction,
renderers,
cells
}) => {
if (isEmpty(elements)) {
return null
} else {
return (
<Hidden xsUp={!visible}>
<Grid
container
direction={direction}
spacing={direction === "row" ? 2 : 0}
>
{renderLayoutElements(
elements,
schema,
path,
enabled,
renderers,
cells
)}
</Grid>
</Hidden>
)
}
}
export const MaterialLayoutRenderer = React.memo(
MaterialLayoutRendererComponent
)

// TODO fix @typescript-eslint/ban-types
// eslint-disable-next-line @typescript-eslint/ban-types
export const withAjvProps = Component =>
function WithAjvProps(props) {
const ctx = useJsonForms()
const ajv = getAjv({ jsonforms: { ...ctx } })

return <Component {...props} ajv={ajv} />
}

0 comments on commit 8c55874

Please sign in to comment.