Skip to content

Commit

Permalink
Form edit initial wysiwyg (#51)
Browse files Browse the repository at this point in the history
* Add clickable preview component to the form manager's edit page. Remaining work is to style it, so it's not possible to click on form elements, tab to them, or enter data.

* Preview UI has selectable patterns, to open the corresponding form element edit ui.

* In-progress work wiring up saving to the WSYIWYG ui
  • Loading branch information
danielnaab authored Feb 26, 2024
1 parent de8d2be commit e5d777c
Show file tree
Hide file tree
Showing 41 changed files with 550 additions and 325 deletions.
9 changes: 7 additions & 2 deletions apps/spotlight/src/components/AppFormManager.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React from 'react';

import { FormManager, defaultFormElementComponent } from '@atj/design';
import {
FormManager,
defaultFormElementComponents,
defaultFormElementEditComponents,
} from '@atj/design';

import { getAppContext } from '../context';

Expand All @@ -10,7 +14,8 @@ export default function () {
<FormManager
context={{
config: ctx.formConfig,
components: defaultFormElementComponent,
components: defaultFormElementComponents,
editComponents: defaultFormElementEditComponents,
}}
formService={ctx.formService}
baseUrl={ctx.baseUrl}
Expand Down
12 changes: 10 additions & 2 deletions apps/spotlight/src/components/AppFormRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from 'react';

import { FormRouter } from '@atj/design';
import { FormRouter, defaultFormElementComponents } from '@atj/design';
import { getAppContext } from '../context';

export default function AppFormRouter() {
const ctx = getAppContext();
return <FormRouter config={ctx.formConfig} formService={ctx.formService} />;
return (
<FormRouter
context={{
config: ctx.formConfig,
components: defaultFormElementComponents,
}}
formService={ctx.formService}
/>
);
}
4 changes: 2 additions & 2 deletions packages/design/src/Form/Form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';

import Form from '.';
import { createTestFormConfig, createTestSession } from '../test-form';
import { createTestFormContext, createTestSession } from '../test-form';

export default {
title: 'Form',
component: Form,
decorators: [(Story, args) => <Story {...args} />],
args: {
config: createTestFormConfig(),
context: createTestFormContext(),
session: createTestSession(),
},
tags: ['autodocs'],
Expand Down
14 changes: 0 additions & 14 deletions packages/design/src/Form/PromptSegment/FormSummary/index.tsx

This file was deleted.

23 changes: 0 additions & 23 deletions packages/design/src/Form/PromptSegment/index.tsx

This file was deleted.

99 changes: 38 additions & 61 deletions packages/design/src/Form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,26 @@ import {
type FormConfig,
type FormSession,
type Prompt,
type Pattern,
} from '@atj/forms';

import PromptSegment from './PromptSegment';
import ActionBar from './ActionBar';

export type FormUIContext = {
config: FormConfig;
components: ComponentForPattern;
};

export type ComponentForPattern<T extends Pattern = Pattern<unknown>> = Record<
string,
FormElementComponent<T>
>;

export type FormElementComponent<T extends Pattern = Pattern<unknown>> =
React.ComponentType<{
prompt: T;
}>;

const usePrompt = (
initialPrompt: Prompt,
config: FormConfig,
Expand Down Expand Up @@ -45,16 +60,22 @@ const usePrompt = (
};

export default function Form({
config,
context,
session,
onSubmit,
}: {
config: FormConfig;
context: FormUIContext;
session: FormSession;
onSubmit?: (data: Record<string, string>) => void;
}) {
const initialPrompt = createPrompt(config, session, { validate: false });
const { prompt, updatePrompt } = usePrompt(initialPrompt, config, session);
const initialPrompt = createPrompt(context.config, session, {
validate: false,
});
const { prompt, updatePrompt } = usePrompt(
initialPrompt,
context.config,
session
);

const formMethods = useForm<Record<string, string>>({});

Expand All @@ -65,10 +86,10 @@ export default function Form({
updatePrompt(allFormData);
}, [allFormData]);
*/

return (
<FormProvider {...formMethods}>
<form className="previewForm"
<form
className="previewForm"
onSubmit={formMethods.handleSubmit(async data => {
updatePrompt(data);
if (onSubmit) {
Expand All @@ -80,64 +101,20 @@ export default function Form({
})}
>
<fieldset className="usa-fieldset">
{prompt.parts.map((promptPart, index) => (
<PromptSegment key={index} promptPart={promptPart}></PromptSegment>
))}
{prompt.parts
.map((pattern, index) => {
if (pattern.type === 'text') {
console.log('skipping', pattern.type);
return null;
}
const Component = context.components[pattern.type];
return <Component key={index} prompt={pattern} />;
})
.filter(a => a)}
{/* Add submit button or other controls as needed */}
</fieldset>
<ActionBar actions={prompt.actions} />
</form>
</FormProvider>
);
}

/*
export const FormFieldsetUnwired = ({ fields }: { fields: Field[] }) => {
return (
<fieldset className="usa-fieldset">
<legend className="usa-legend usa-legend--large">
UD 105 - Unlawful Detainer Form
</legend>
{fields.map(field => {
// Use 'tag' for 'select' and 'textarea', 'type' for others
const fieldType =
field.tag === 'select' ||
field.tag === 'textarea' ||
field.tag === 'p' ||
field.tag === 'h2' ||
field.tag === 'h3' ||
field.tag === 'ul'
? field.tag
: field.type;
switch (fieldType) {
case 'text':
return <TextField key={field.id} field={field} />;
case 'boolean':
return <BooleanField key={field.id} field={field} />;
case 'checkbox':
return <CheckBoxField key={field.id} field={field} />;
case 'select':
return <SelectField key={field.id} field={field} />;
case 'radio':
return <RadioField key={field.id} field={field} />;
case 'date':
return <DateField key={field.id} field={field} />;
case 'textarea':
return <TextareaField key={field.id} field={field} />;
case 'p':
return <ParagraphBlock key={field.id} field={field} />;
case 'h2':
return <Header3Block key={field.id} field={field} />;
case 'h3':
return <Header3Block key={field.id} field={field} />;
case 'ul':
return <UnorderedList key={field.id} field={field} />;
default:
return null;
}
})}
</fieldset>
);
};
*/
17 changes: 11 additions & 6 deletions packages/design/src/FormManager/DocumentImporter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@ import { useNavigate } from 'react-router-dom';
import { addDocument, addDocumentFieldsToForm } from '@atj/documents';
import { type FormService } from '@atj/form-service';
import {
type FormConfig,
type DocumentFieldMap,
type FormDefinition,
createFormSession,
} from '@atj/forms';

import { onFileInputChangeGetFile } from '../FormList/PDFFileSelect/file-input';
import Form from '../../Form';
import { FormUIContext } from 'config';

const DocumentImporter = ({
baseUrl,
formId,
config,
context,
form,
formService,
}: {
baseUrl: string;
formId: string;
config: FormConfig;
context: FormUIContext;
form: FormDefinition;
formService: FormService;
}) => {
Expand Down Expand Up @@ -70,7 +71,11 @@ const DocumentImporter = ({
const PDFFileSelect = () => {
return (
<div className="usa-form-group">
<label className="usa-label" id="file-input-specific-hint" htmlFor="file-input-specific">
<label
className="usa-label"
id="file-input-specific-hint"
htmlFor="file-input-specific"
>
Select a single PDF file
</label>
<div className="usa-file-input">
Expand Down Expand Up @@ -153,8 +158,8 @@ const DocumentImporter = ({
return (
<>
<Form
config={config}
form={previewForm}
context={context}
session={createFormSession(previewForm)}
onSubmit={data => {
//handleFormSubmission(formId, data);
console.log(formId, data);
Expand Down
Empty file.
4 changes: 2 additions & 2 deletions packages/design/src/FormManager/FormEdit/FormEdit.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { createTestFormService } from '@atj/form-service';

import FormEdit from '.';
import { createTestForm, createTestFormContext } from '../../test-form';
import { createTestForm, createTestFormEditContext } from '../../test-form';

export default {
title: 'FormManager/FormEdit',
Expand All @@ -18,7 +18,7 @@ export default {
),
],
args: {
context: createTestFormContext(),
context: createTestFormEditContext(),
formId: 'test-form',
formService: createTestFormService({
'test-form': createTestForm(),
Expand Down
52 changes: 52 additions & 0 deletions packages/design/src/FormManager/FormEdit/FormElementEdit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';

import {
FormDefinition,
FormElement,
FormElementMap,
updateElement,
} from '@atj/forms';
import { FormEditUIContext } from '../../config';

export const FormElementEdit = ({
context,
initialForm,
formElement,
onChange,

Check failure on line 16 in packages/design/src/FormManager/FormEdit/FormElementEdit.tsx

View workflow job for this annotation

GitHub Actions / run-tests (ubuntu-latest, x86_64)

'onChange' is defined but never used
}: {
context: FormEditUIContext;
initialForm: FormDefinition;
formElement: FormElement;
onChange: (form: FormDefinition) => void;
}) => {
const methods = useForm<FormElementMap>({
defaultValues: {
[formElement.id]: formElement,
},
});
const SelectedEditComponent = context.editComponents[formElement.type];
return (
<FormProvider {...methods}>
<form
className="editForm"
onSubmit={methods.handleSubmit(formData => {
const updatedForm = updateElement(

Check failure on line 34 in packages/design/src/FormManager/FormEdit/FormElementEdit.tsx

View workflow job for this annotation

GitHub Actions / run-tests (ubuntu-latest, x86_64)

'updatedForm' is assigned a value but never used
context.config,
initialForm,
formElement.id,
formData
);
//onChange(updatedForm);
})}
>
<input className="usa-button" type="submit" value="Save" />
<SelectedEditComponent
context={context}
form={initialForm}
element={formElement}
/>
</form>
</FormProvider>
);
};
Loading

0 comments on commit e5d777c

Please sign in to comment.