Skip to content

Commit f876c02

Browse files
abdul99ahadbarmac
authored andcommitted
feat(components/feel): added onblur to handle post input
- onblur updates the value async - trims the whitespaces if exists - applied to feel-textfield and feel-textarea Closes #404 Related to #309 Integration tests: bpmn-io/bpmn-js-properties-panel#1118
1 parent 0692619 commit f876c02

File tree

2 files changed

+167
-7
lines changed

2 files changed

+167
-7
lines changed

src/components/entries/FEEL/Feel.js

+25-7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function FeelTextfieldComponent(props) {
4545
label,
4646
hostLanguage,
4747
onInput,
48+
onBlur,
4849
onError,
4950
placeholder,
5051
feel,
@@ -83,6 +84,9 @@ function FeelTextfieldComponent(props) {
8384
_setFocus(position + offset);
8485
};
8586

87+
/**
88+
* @type { import('min-dash').DebouncedFunction }
89+
*/
8690
const handleInputCallback = useMemo(() => {
8791
return debounce((newValue) => {
8892
onInput(newValue);
@@ -92,12 +96,11 @@ function FeelTextfieldComponent(props) {
9296
const setLocalValue = newValue => {
9397
_setLocalValue(newValue);
9498

95-
if (typeof newValue === 'undefined' || newValue === '' || newValue === '=') {
96-
handleInputCallback(undefined);
97-
} else {
98-
handleInputCallback(newValue);
99-
}
99+
// we don't commit empty FEEL expressions,
100+
// but instead serialize them as <undefined>
101+
const newModelValue = (newValue === '' || newValue === '=') ? undefined : newValue;
100102

103+
handleInputCallback(newModelValue);
101104
};
102105

103106
const handleFeelToggle = useStaticCallback(() => {
@@ -130,6 +133,20 @@ function FeelTextfieldComponent(props) {
130133
}
131134
};
132135

136+
const handleOnBlur = (e) => {
137+
const value = e.target.value;
138+
139+
// we trim the value, if it is needed
140+
// and update input accordingly
141+
if (value.trim() !== value) {
142+
setLocalValue(value.trim());
143+
}
144+
145+
if (onBlur) {
146+
onBlur(e);
147+
}
148+
};
149+
133150
const handleLint = useStaticCallback((lint = []) => {
134151

135152
const syntaxError = lint.some(report => report.type === 'Syntax Error');
@@ -256,6 +273,7 @@ function FeelTextfieldComponent(props) {
256273
{ ...props }
257274
popupOpen={ popuOpen }
258275
onInput={ handleLocalInput }
276+
onBlur={ handleOnBlur }
259277
contentAttributes={ { 'id': prefixId(id), 'aria-label': label } }
260278
value={ localValue }
261279
ref={ editorRef }
@@ -554,7 +572,7 @@ export default function FeelEntry(props) {
554572
}
555573
}, [ value, validate ]);
556574

557-
const onInput = useStaticCallback((newValue) => {
575+
const onInput = useCallback((newValue) => {
558576
let newValidationError = null;
559577

560578
if (isFunction(validate)) {
@@ -567,7 +585,7 @@ export default function FeelEntry(props) {
567585
}
568586

569587
setValidationError(newValidationError);
570-
});
588+
},[ element ]);
571589

572590
const onError = useCallback(err => {
573591
setLocalError(err);

test/spec/components/Feel.spec.js

+142
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,76 @@ describe('<FeelField>', function() {
9292
});
9393

9494

95+
it('should trim whitespace on blur', async function() {
96+
97+
// given
98+
const setValueSpy = sinon.spy();
99+
100+
const result = createFeelField({
101+
container,
102+
setValue: setValueSpy
103+
});
104+
105+
const input = domQuery('.bio-properties-panel-input', result.container);
106+
107+
// when
108+
input.focus();
109+
changeInput(input, ' foo ');
110+
input.blur();
111+
112+
// then
113+
expect(setValueSpy).to.have.been.calledTwice;
114+
expect(setValueSpy).to.have.been.calledWith('foo');
115+
});
116+
117+
118+
it('should call onBlur if provided', async function() {
119+
120+
// given
121+
const setValueSpy = sinon.spy();
122+
const onBlurSpy = sinon.spy();
123+
124+
const result = createFeelField({
125+
container,
126+
setValue: setValueSpy,
127+
onBlur: onBlurSpy
128+
});
129+
130+
const input = domQuery('.bio-properties-panel-input', result.container);
131+
132+
// when
133+
input.focus();
134+
changeInput(input, ' foo ');
135+
input.blur();
136+
137+
// then
138+
expect(onBlurSpy).to.have.been.calledOnce;
139+
});
140+
141+
142+
it('should not call setValue if the value is same', async function() {
143+
144+
// given
145+
const setValueSpy = sinon.spy();
146+
147+
const result = createFeelField({
148+
container,
149+
setValue: setValueSpy
150+
});
151+
152+
const input = domQuery('.bio-properties-panel-input', result.container);
153+
154+
// when
155+
input.focus();
156+
changeInput(input, '');
157+
input.blur();
158+
159+
// then
160+
expect(setValueSpy).to.not.have.been.called;
161+
162+
});
163+
164+
95165
describe('#isEdited', function() {
96166

97167
it('should NOT be edited', function() {
@@ -1078,6 +1148,76 @@ describe('<FeelField>', function() {
10781148
});
10791149

10801150

1151+
it('should trim whitespace on blur', async function() {
1152+
1153+
// given
1154+
const setValueSpy = sinon.spy();
1155+
1156+
const result = createFeelTextArea({
1157+
container,
1158+
setValue: setValueSpy,
1159+
});
1160+
1161+
const input = domQuery('.bio-properties-panel-input', result.container);
1162+
1163+
// when
1164+
input.focus();
1165+
changeInput(input, ' foo ');
1166+
input.blur();
1167+
1168+
// then
1169+
expect(setValueSpy).to.have.been.calledTwice;
1170+
expect(setValueSpy).to.have.been.calledWith('foo');
1171+
});
1172+
1173+
1174+
it('should call onBlur if provided', async function() {
1175+
1176+
// given
1177+
const setValueSpy = sinon.spy();
1178+
const onBlurSpy = sinon.spy();
1179+
1180+
const result = createFeelTextArea({
1181+
container,
1182+
setValue: setValueSpy,
1183+
onBlur: onBlurSpy
1184+
});
1185+
1186+
const input = domQuery('.bio-properties-panel-input', result.container);
1187+
1188+
// when
1189+
input.focus();
1190+
changeInput(input, ' foo ');
1191+
input.blur();
1192+
1193+
// then
1194+
expect(onBlurSpy).to.have.been.calledOnce;
1195+
});
1196+
1197+
1198+
it('should not call setValue if the value is same', async function() {
1199+
1200+
// given
1201+
const setValueSpy = sinon.spy();
1202+
1203+
const result = createFeelTextArea({
1204+
container,
1205+
setValue: setValueSpy
1206+
});
1207+
1208+
const input = domQuery('.bio-properties-panel-input', result.container);
1209+
1210+
// when
1211+
input.focus();
1212+
changeInput(input, '');
1213+
input.blur();
1214+
1215+
// then
1216+
expect(setValueSpy).to.not.have.been.called;
1217+
1218+
});
1219+
1220+
10811221
describe('#isEdited', function() {
10821222

10831223
it('should NOT be edited', function() {
@@ -2622,6 +2762,7 @@ function createFeelField(options = {}, renderFn = render) {
26222762
container,
26232763
eventBus = new EventBus(),
26242764
onShow = noop,
2765+
onBlur = noop,
26252766
errors = {},
26262767
variables,
26272768
openPopup = noop,
@@ -2668,6 +2809,7 @@ function createFeelField(options = {}, renderFn = render) {
26682809
disabled={ disabled }
26692810
getValue={ getValue }
26702811
setValue={ setValue }
2812+
onBlur={ onBlur }
26712813
debounce={ debounce }
26722814
validate={ validate }
26732815
feel={ feel }

0 commit comments

Comments
 (0)