Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
vsgoulart committed Jun 19, 2024
1 parent b0020c3 commit 2081c64
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"parserOptions": {
"ecmaVersion": 2019
"ecmaVersion": 2022
},
"extends": [
"plugin:bpmn-io/browser",
Expand Down
36 changes: 34 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions packages/form-js-viewer-core/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module">
import { foo } from './src/index.js';
import { renderForm } from './src/index.js';
import schema from './mock-schema.json';

console.log(foo());
renderForm({
container: document.getElementById('root'),
schema,
context: {
second_checkbox: true,
},
});
</script>
</body>
</html>
26 changes: 26 additions & 0 deletions packages/form-js-viewer-core/mock-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"components": [
{
"label": "Text field",
"type": "textfield",
"id": "field_1knwu16",
"key": "aTextField"
},
{
"label": "first_checkbox",
"type": "checkbox",
"id": "field_0zbcir4",
"key": "first_checkbox",
"conditional": {
"hide": "=second_checkbox"
}
},
{
"label": "second_checkbox",
"type": "checkbox",
"id": "field_06pzj62",
"key": "second_checkbox"
}
],
"type": "default"
}
10 changes: 9 additions & 1 deletion packages/form-js-viewer-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,13 @@
"sideEffects": false,
"files": [
"dist"
]
],
"dependencies": {
"feelin": "^3.1.0"
},
"devDependencies": {
"@preact/preset-vite": "^2.8.2",
"min-dash": "^4.2.1",
"preact": "^10.22.0"
}
}
116 changes: 116 additions & 0 deletions packages/form-js-viewer-core/src/form-js-viewer-core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { evaluate } from 'feelin';
import { get } from 'min-dash';

const EXPRESSION_PROPERTIES = ['key', 'conditional.hide'];

Check failure on line 4 in packages/form-js-viewer-core/src/form-js-viewer-core.js

View workflow job for this annotation

GitHub Actions / Build (ubuntu-20.04, 20)

'EXPRESSION_PROPERTIES' is assigned a value but never used. Allowed unused vars must match /^_/u

class Core {
initialContext = null;
context = null;
schema = null;
subscribers = new Map();

constructor(options = {}) {
const { context = {}, schema } = options;

if (!schema || !Array.isArray(schema?.components)) {
throw new Error('Invalid schema');
}

const parsedSchema = schema.components.reduce((acc, component) => {
const { id, value } = component;

return { ...acc, [id]: value };
}, {});

this.initialContext = context;
this.context = {
...context,
...parsedSchema,
};
this.schema = schema;
}

parseSchema(schema, context) {
const components = [];

schema.components.forEach((component) => {
const { type, key, ...rest } = component;
const hideProperty = get(component, ['conditional', 'hide']);

if (hideProperty !== undefined && evaluate(hideProperty.replace(/^=/, ''), context)) {
return;
}

if (type === 'textfield') {
components.push({
type,
key,
value: evaluate(key, context),
...rest,
});
}

if (type === 'checkbox') {
components.push({
type,
key,
value: evaluate(key, context),
...rest,
});
}
});

return components;
}

subscribe(fieldPath, callback) {
const field = get(this.schema.components, fieldPath);

if (!field) {
throw new Error(`Field ${fieldPath} not found`);
}

if (!this.subscribers.has(fieldPath)) {
this.subscribers.set(fieldPath, []);
}

this.subscribers.get(fieldPath).push(callback);
}

unsubscribe(fieldPath, callback) {
const field = get(this.schema.components, fieldPath);

if (!field) {
throw new Error(`Field ${fieldPath} not found`);
}

if (!this.subscribers.has(fieldPath)) {
return;
}

const subscribers = this.subscribers.get(fieldPath);

subscribers.splice(subscribers.indexOf(callback), 1);
}

change(fieldPath, value) {
const field = get(this.schema.components, fieldPath);

if (!field) {
throw new Error(`Field ${fieldPath} not found`);
}

field.value = value;

this.subscribers.forEach((subscribers, fieldPath) => {
if (fieldPath === [field.id].toString()) {
console.log('called', fieldPath);
subscribers.forEach((callback) => {
callback(field);
});
}
});
}
}

export { Core };
80 changes: 80 additions & 0 deletions packages/form-js-viewer-core/src/form-js-viewer-preact.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { createContext } from 'preact';
import { useContext, useEffect, useState } from 'preact/hooks';
import { Core } from './form-js-viewer-core';
import { get } from 'min-dash';

const FormContext = createContext(null);

function useField(fieldPath) {
const form = useContext(FormContext);
const [field, setField] = useState(get(form.schema.components, fieldPath));

if (!form || !field) {
throw new Error('Form not initialized');
}

useEffect(() => {
const subscriber = (field) => {
setField(field);
};

form.subscribe(fieldPath.toString(), subscriber);

return () => {
form.unsubscribe(fieldPath.toString(), subscriber);
};
}, [fieldPath, form]);

return field;
}

function Form(props = {}) {
const { context, schema } = props;

return (
<FormContext.Provider value={new Core({ context, schema })}>
<Components />
</FormContext.Provider>
);
}

function Components(props = {}) {
const form = useContext(FormContext);

return (
<>
{form.schema.components.map((component, index) => (
<Field fieldPath={[index]} />
))}
</>
);
}

function Field(props = {}) {
const field = useField(props.fieldPath);

if (field.type === 'textfield') {
return (
<Textfield
value={field.value}
onChange={(event) => {
field.change(props.fieldPath, event.target.value);
}}
/>
);
}

if (field.type === 'checkbox') {
return <input type="checkbox" checked={field.value} />;
}

return <>{field}</>;
}

function Textfield(props = {}) {
const { value } = props;

return <input value={value} />;
}

export { Form, useField };
16 changes: 16 additions & 0 deletions packages/form-js-viewer-core/src/form-js-viewer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { render } from 'preact';
import { Form } from './form-js-viewer-preact';

function renderForm(options = {}) {
const { container, context, schema } = options;

if (container === null) {
return;
}

console.log({ context, schema });

render(<Form schema={schema} context={context} />, container);
}

export { renderForm };
7 changes: 2 additions & 5 deletions packages/form-js-viewer-core/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
function foo() {
return 'foo';
}

export { foo };
export { Core } from './form-js-viewer-core';
export { renderForm } from './form-js-viewer';
10 changes: 10 additions & 0 deletions packages/form-js-viewer-core/vite.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { resolve } from 'path';
import { createRequire } from 'module';
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';

export default defineConfig({
plugins: [
preact({
babel: {
// Change cwd to load Preact Babel plugins
cwd: createRequire(import.meta.url).resolve('@preact/preset-vite'),
},
}),
],
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
Expand Down

0 comments on commit 2081c64

Please sign in to comment.