Skip to content

Commit ce758f8

Browse files
committed
image picker to use value & groups config API
1 parent e28c7c7 commit ce758f8

File tree

13 files changed

+97
-48
lines changed

13 files changed

+97
-48
lines changed

src-ts/lib/form/form-definition.model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FormButton, FormGroup } from '.'
1+
import { FormButton, FormGroup, FormGroupOptions } from '.'
22

33
export type FormAction = 'save' | 'submit' | undefined
44

@@ -10,6 +10,7 @@ export interface FormButtons {
1010
export interface FormDefinition {
1111
readonly buttons: FormButtons
1212
readonly groups?: Array<FormGroup>
13+
readonly groupsOptions?: FormGroupOptions
1314
readonly shortName?: string
1415
readonly subtitle?: string
1516
readonly successMessage?: string

src-ts/lib/form/form-functions/form.functions.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export async function onSubmitAsync<T>(
6868
formValue: T,
6969
save: (value: T) => Promise<void>,
7070
onSuccess?: () => void,
71+
customValidateForm?: (formElements: HTMLFormControlsCollection, event: ValidationEvent, inputs: ReadonlyArray<FormInputModel>) => boolean
7172
): Promise<void> {
7273

7374
event.preventDefault()
@@ -84,7 +85,7 @@ export async function onSubmitAsync<T>(
8485
// want to have it look like the submit succeeded
8586
const formValues: HTMLFormControlsCollection = (event.target as HTMLFormElement).elements
8687
if (action === 'submit') {
87-
const isValid: boolean = validateForm(formValues, action, inputs)
88+
const isValid: boolean = (customValidateForm || validateForm)(formValues, action, inputs)
8889
if (!isValid) {
8990
return Promise.reject()
9091
}
@@ -119,16 +120,19 @@ function handleFieldEvent<T>(input: HTMLInputElement | HTMLTextAreaElement, inpu
119120

120121
const inputDef: FormInputModel = getInputModel(inputs, input.name)
121122

123+
const inputEl: HTMLInputElement = input as HTMLInputElement
124+
122125
if (event === 'change') {
123126
inputDef.dirty = input.value !== originalValue
124127
}
125128
inputDef.touched = true
126129

127130
// set the def value
128131
if (input.type === 'checkbox') {
129-
const checkbox: HTMLInputElement = input as HTMLInputElement
130-
inputDef.value = checkbox.checked
131-
inputDef.checked = checkbox.checked
132+
inputDef.value = inputEl.checked
133+
inputDef.checked = inputEl.checked
134+
} else if (input.type === 'file') {
135+
inputDef.value = inputEl.files || undefined
132136
} else {
133137
inputDef.value = input.value
134138
}
@@ -181,7 +185,9 @@ function validateField(formInputDef: FormInputModel, formElements: HTMLFormContr
181185
})
182186
}
183187

184-
export function validateForm(formElements: HTMLFormControlsCollection, event: 'blur' | 'change' | 'submit' | 'initial', inputs: ReadonlyArray<FormInputModel>): boolean {
188+
export type ValidationEvent = 'blur' | 'change' | 'submit' | 'initial'
189+
190+
export function validateForm(formElements: HTMLFormControlsCollection, event: ValidationEvent, inputs: ReadonlyArray<FormInputModel>): boolean {
185191
const errors: ReadonlyArray<FormInputModel> = inputs?.filter(formInputDef => {
186192
formInputDef.dirty = formInputDef.dirty || event === 'submit'
187193
validateField(formInputDef, formElements, event)

src-ts/lib/form/form-group.model.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { CSSProperties } from 'react'
2+
13
import { FormInputModel } from './form-input.model'
24

35
export interface FormGroup {
@@ -6,3 +8,8 @@ export interface FormGroup {
68
readonly instructions?: string
79
readonly title?: string
810
}
11+
12+
export interface FormGroupOptions {
13+
groupWrapStyles?: CSSProperties
14+
renderGroupDividers?: boolean
15+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
@import "../../styles/includes";
2+
13
.form-groups {
24
display: grid;
35
grid-template-columns: 1fr;
46
justify-content: center;
7+
8+
@include ltemd {
9+
grid-template-columns: 1fr !important;
10+
}
511
}

src-ts/lib/form/form-groups/FormGroups.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ChangeEvent, FocusEvent } from 'react'
22

3+
import { PageDivider } from '../../page-divider'
34
import { FormDefinition } from '../form-definition.model'
45
import { FormGroup } from '../form-group.model'
56
import { FormInputModel } from '../form-input.model'
@@ -33,6 +34,8 @@ const FormGroups: (props: FormGroupsProps) => JSX.Element = (props: FormGroupsPr
3334
const tabIndex: number = getTabIndex(input, index)
3435

3536
let inputElement: JSX.Element
37+
38+
/* tslint:disable:cyclomatic-complexity */
3639
switch (input.type) {
3740

3841
case 'rating':
@@ -90,6 +93,8 @@ const FormGroups: (props: FormGroupsProps) => JSX.Element = (props: FormGroupsPr
9093
inputElement = (
9194
<InputImagePicker
9295
{...input}
96+
onChange={onChange}
97+
value={input.value}
9398
/>
9499
)
95100
break
@@ -126,15 +131,21 @@ const FormGroups: (props: FormGroupsProps) => JSX.Element = (props: FormGroupsPr
126131
group={element}
127132
renderFormInput={renderInputField}
128133
totalGroupCount={formDef.groups?.length || 0}
134+
renderDividers={props.formDef.groupsOptions?.renderGroupDividers}
129135
/>
130136
)
131137
})
132138
|| []
133139

134140
return (
135-
<div className={styles['form-groups']}>
136-
{formGroups}
137-
</div>
141+
<>
142+
<div className={styles['form-groups']} style={props.formDef.groupsOptions?.groupWrapStyles}>
143+
{formGroups}
144+
</div>
145+
{
146+
props.formDef.groupsOptions?.renderGroupDividers === false && <PageDivider />
147+
}
148+
</>
138149
)
139150
}
140151

src-ts/lib/form/form-groups/form-group-item/FormGroupItem.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import styles from './FormGroupItem.module.scss'
99

1010
interface FormGroupItemProps {
1111
group: FormGroup
12+
renderDividers?: boolean
1213
renderFormInput: (input: FormInputModel, index: number) => JSX.Element | undefined
1314
totalGroupCount: number
1415
}
@@ -19,10 +20,11 @@ interface ItemRowProps {
1920
hasMultipleGroups: boolean,
2021
instructions?: string | undefined,
2122
isMultiFieldGroup: boolean,
23+
renderDividers?: boolean
2224
title?: string,
2325
}
2426

25-
const TwoColumnItem: React.FC<ItemRowProps> = ({ element, formInputs, hasMultipleGroups, instructions, isMultiFieldGroup, title }: ItemRowProps) => {
27+
const TwoColumnItem: React.FC<ItemRowProps> = ({ element, formInputs, hasMultipleGroups, instructions, isMultiFieldGroup, title, renderDividers }: ItemRowProps) => {
2628
return (
2729
<>
2830
<div className={cn(styles['form-group-item'], !isMultiFieldGroup && styles['single-field'])}>
@@ -41,7 +43,9 @@ const TwoColumnItem: React.FC<ItemRowProps> = ({ element, formInputs, hasMultipl
4143
{formInputs}
4244
</div>
4345
</div>
44-
<PageDivider styleNames={[!hasMultipleGroups ? 'spacingSmall' : '']} />
46+
{
47+
renderDividers !== false && <PageDivider styleNames={[!hasMultipleGroups ? 'spacingSmall' : '']} />
48+
}
4549
</>
4650
)
4751
}
@@ -67,7 +71,7 @@ const SingleColumnItem: React.FC<ItemRowProps> = ({ formInputs, hasMultipleGroup
6771
)
6872
}
6973

70-
const FormGroupItem: React.FC<FormGroupItemProps> = ({ group, renderFormInput, totalGroupCount }: FormGroupItemProps) => {
74+
const FormGroupItem: React.FC<FormGroupItemProps> = ({ group, renderDividers, renderFormInput, totalGroupCount }: FormGroupItemProps) => {
7175
const { instructions, title, inputs, element }: FormGroup = group
7276

7377
const formInputs: Array<JSX.Element | undefined> = inputs?.map((field: FormInputModel, index: number) => renderFormInput(field as FormInputModel, index)) || []
@@ -77,7 +81,7 @@ const FormGroupItem: React.FC<FormGroupItemProps> = ({ group, renderFormInput, t
7781

7882
return isCardSet ?
7983
<SingleColumnItem hasMultipleGroups={hasMultipleGroups} instructions={instructions} isMultiFieldGroup={isMultiFieldGroup} formInputs={formInputs} title={title} /> :
80-
<TwoColumnItem hasMultipleGroups={hasMultipleGroups} element={element} instructions={instructions} isMultiFieldGroup={isMultiFieldGroup} formInputs={formInputs} title={title} />
84+
<TwoColumnItem hasMultipleGroups={hasMultipleGroups} element={element} instructions={instructions} isMultiFieldGroup={isMultiFieldGroup} formInputs={formInputs} title={title} renderDividers={renderDividers} />
8185
}
8286

8387
export default FormGroupItem

src-ts/lib/form/form-groups/form-input/input-image-picker/InputImagePicker.module.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
width: 132px;
1111
height: 132px;
1212
position: relative;
13+
margin-bottom: $space-xl;
1314

1415
@include ltemd {
1516
width: 100%;

src-ts/lib/form/form-groups/form-input/input-image-picker/InputImagePicker.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import { createRef, Dispatch, FC, RefObject, SetStateAction, useEffect, useState } from 'react'
1+
import { ChangeEvent, createRef, Dispatch, FC, RefObject, SetStateAction, useEffect, useState } from 'react'
22

33
import { Button, IconOutline } from '../../../../../lib'
4+
import { InputValue } from '../../../form-input.model'
45

56
import styles from './InputImagePicker.module.scss'
67

78
interface InputImagePickerProps {
89
readonly accept?: string
910
readonly name: string
11+
readonly onChange: (event: ChangeEvent<HTMLInputElement>) => void
1012
readonly size?: number
13+
readonly value?: InputValue
1114
}
1215

1316
const InputImagePicker: FC<InputImagePickerProps> = (props: InputImagePickerProps) => {
@@ -48,7 +51,10 @@ const InputImagePicker: FC<InputImagePickerProps> = (props: InputImagePickerProp
4851
accept={props.accept || '*'}
4952
className={styles.filePickerInput}
5053
ref={fileInputRef}
51-
onChange={event => setFiles(event.target.files)}
54+
onChange={event => {
55+
setFiles(event.target.files)
56+
props.onChange(event)
57+
}}
5258
size={props.size || Infinity}
5359
/>
5460
{

src-ts/lib/form/form-groups/form-input/input-text/InputText.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cn from 'classnames'
22
import { FC, FocusEvent } from 'react'
33

4+
import { InputValue } from '../../../form-input.model'
45
import { FormInputAutocompleteOption } from '../form-input-autcomplete-option.enum'
56
import { InputWrapper } from '../input-wrapper'
67

@@ -25,7 +26,7 @@ export interface InputTextProps {
2526
readonly spellCheck?: boolean
2627
readonly tabIndex: number
2728
readonly type: InputTextTypes
28-
readonly value?: string | number | boolean
29+
readonly value?: InputValue
2930
}
3031

3132
const InputText: FC<InputTextProps> = (props: InputTextProps) => {

src-ts/lib/form/form-input.model.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export interface FormCard {
1717
title: string
1818
}
1919

20+
export type InputValue = string | boolean | FileList | undefined
21+
2022
export interface FormInputModel {
2123
readonly accept?: string
2224
readonly autocomplete?: FormInputAutocompleteOption
@@ -44,5 +46,5 @@ export interface FormInputModel {
4446
touched?: boolean
4547
readonly type: 'card-set' | 'checkbox' | 'password' | 'radio' | 'rating' | 'text' | 'textarea' | 'image-picker'
4648
readonly validators?: ReadonlyArray<ValidatorFn>
47-
value?: string | boolean
49+
value?: InputValue
4850
}

0 commit comments

Comments
 (0)