-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: provide custom form field tests
Closes #123
- Loading branch information
Niklas Kiefer
committed
Oct 5, 2023
1 parent
384dd76
commit c0c00e3
Showing
11 changed files
with
512 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { get, set } from 'min-dash'; | ||
|
||
import { | ||
NumberFieldEntry, | ||
isNumberFieldEntryEdited | ||
} from '@bpmn-io/properties-panel'; | ||
|
||
|
||
class CustomPropertiesProvider { | ||
constructor(propertiesPanel) { | ||
propertiesPanel.registerProvider(this, 500); | ||
} | ||
|
||
getGroups(field, editField) { | ||
return (groups) => { | ||
|
||
if (field.type !== 'range') { | ||
return groups; | ||
} | ||
|
||
const generalIdx = findGroupIdx(groups, 'general'); | ||
|
||
groups.splice(generalIdx + 1, 0, { | ||
id: 'range', | ||
label: 'Range', | ||
entries: RangeEntries(field, editField) | ||
}); | ||
|
||
return groups; | ||
}; | ||
} | ||
} | ||
|
||
CustomPropertiesProvider.$inject = [ 'propertiesPanel' ]; | ||
|
||
function RangeEntries(field, editField) { | ||
|
||
const onChange = (key) => { | ||
return (value) => { | ||
const range = get(field, [ 'range' ], {}); | ||
|
||
editField(field, [ 'range' ], set(range, [ key ], value)); | ||
}; | ||
}; | ||
|
||
const getValue = (key) => { | ||
return () => { | ||
return get(field, [ 'range', key ]); | ||
}; | ||
}; | ||
|
||
return [ | ||
{ | ||
id: 'range-min', | ||
component: Min, | ||
getValue, | ||
field, | ||
isEdited: isNumberFieldEntryEdited, | ||
onChange | ||
}, | ||
{ | ||
id: 'range-max', | ||
component: Max, | ||
getValue, | ||
field, | ||
isEdited: isNumberFieldEntryEdited, | ||
onChange | ||
}, | ||
{ | ||
id: 'range-step', | ||
component: Step, | ||
getValue, | ||
field, | ||
isEdited: isNumberFieldEntryEdited, | ||
onChange | ||
} | ||
]; | ||
|
||
} | ||
|
||
function Min(props) { | ||
const { | ||
field, | ||
getValue, | ||
id, | ||
onChange | ||
} = props; | ||
|
||
const debounce = (fn) => fn; | ||
|
||
return NumberFieldEntry({ | ||
debounce, | ||
element: field, | ||
getValue: getValue('min'), | ||
id, | ||
label: 'Minimum', | ||
setValue: onChange('min') | ||
}); | ||
} | ||
|
||
function Max(props) { | ||
const { | ||
field, | ||
getValue, | ||
id, | ||
onChange | ||
} = props; | ||
|
||
const debounce = (fn) => fn; | ||
|
||
return NumberFieldEntry({ | ||
debounce, | ||
element: field, | ||
getValue: getValue('max'), | ||
id, | ||
label: 'Maximum', | ||
setValue: onChange('max') | ||
}); | ||
} | ||
|
||
function Step(props) { | ||
const { | ||
field, | ||
getValue, | ||
id, | ||
onChange | ||
} = props; | ||
|
||
const debounce = (fn) => fn; | ||
|
||
return NumberFieldEntry({ | ||
debounce, | ||
element: field, | ||
getValue: getValue('step'), | ||
id, | ||
min: 0, | ||
label: 'Step', | ||
setValue: onChange('step') | ||
}); | ||
} | ||
|
||
|
||
export default { | ||
__init__: [ 'customPropertiesProvider' ], | ||
customPropertiesProvider: [ 'type', CustomPropertiesProvider ] | ||
}; | ||
|
||
// helper ////////////////////// | ||
|
||
function findGroupIdx(groups, id) { | ||
return groups.findIndex(g => g.id === id); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.range-group { | ||
display: flex; | ||
flex-direction: row; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
|
||
import { | ||
Errors, | ||
FormContext, | ||
Numberfield, | ||
Description, | ||
Label | ||
} from '@bpmn-io/form-js-viewer'; | ||
|
||
import { useContext } from 'preact/hooks'; | ||
|
||
import classNames from 'classnames'; | ||
|
||
import RangeIcon from './range.svg'; | ||
|
||
const rangeType = 'range'; | ||
|
||
function RangeRenderer(props) { | ||
|
||
const { | ||
disabled, | ||
errors = [], | ||
field, | ||
readonly, | ||
value | ||
} = props; | ||
|
||
const { | ||
description, | ||
range = {}, | ||
id, | ||
label | ||
} = field; | ||
|
||
const { | ||
min, | ||
max, | ||
step | ||
} = range; | ||
|
||
const { formId } = useContext(FormContext); | ||
|
||
const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`; | ||
|
||
const onChange = ({ target }) => { | ||
props.onChange({ | ||
field, | ||
value: Number(target.value) | ||
}); | ||
}; | ||
|
||
return <div class={ formFieldClasses(rangeType) }> | ||
<Label | ||
id={ prefixId(id, formId) } | ||
label={ label } /> | ||
<div class="range-group"> | ||
<input | ||
type="range" | ||
disabled={ disabled } | ||
id={ prefixId(id, formId) } | ||
max={ max } | ||
min={ min } | ||
onInput={ onChange } | ||
readOnly={ readonly } | ||
value={ value } | ||
step={ step } /> | ||
<div class="range-value">{ value }</div> | ||
</div> | ||
<Description description={ description } /> | ||
<Errors errors={ errors } id={ errorMessageId } /> | ||
</div>; | ||
} | ||
|
||
RangeRenderer.config = { | ||
...Numberfield.config, | ||
type: rangeType, | ||
keyed: true, | ||
label: 'Range', | ||
group: 'basic-input', | ||
propertiesPanelEntries: [ | ||
'key', | ||
'label', | ||
'description', | ||
'min', | ||
'max' | ||
], | ||
icon: RangeIcon | ||
}; | ||
|
||
class CustomFormFields { | ||
constructor(formFields) { | ||
formFields.register(rangeType, RangeRenderer); | ||
} | ||
} | ||
|
||
export default { | ||
__init__: [ 'customFormFields' ], | ||
customFormFields: [ 'type', CustomFormFields ] | ||
}; | ||
|
||
|
||
// helper ////////////////////// | ||
|
||
function formFieldClasses(type, { errors = [], disabled = false, readonly = false } = {}) { | ||
if (!type) { | ||
throw new Error('type required'); | ||
} | ||
|
||
return classNames('fjs-form-field', `fjs-form-field-${type}`, { | ||
'fjs-has-errors': errors.length > 0, | ||
'fjs-disabled': disabled, | ||
'fjs-readonly': readonly | ||
}); | ||
} | ||
|
||
function prefixId(id, formId) { | ||
if (formId) { | ||
return `fjs-form-${ formId }-${ id }`; | ||
} | ||
|
||
return `fjs-form-${ id }`; | ||
} |
Oops, something went wrong.