Skip to content

Commit 8b1f8b9

Browse files
committed
feat: adds the option to define icons and buttonText pr. slide. Also fixes a bug on multilinetext where focus on inputcontrol did not set the question to active
1 parent b03baca commit 8b1f8b9

File tree

9 files changed

+68
-37
lines changed

9 files changed

+68
-37
lines changed

packages/core/src/components/icons/IconResolver.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ import { EmailIcon } from "./EmailIcon";
22
import { TelephoneIcon } from "./TelephoneIcon";
33
import { UserIcon } from "./UserIcon";
44
import { IconProps } from "./iconProps";
5+
import { Checkmark } from '../icons/Checkmark';
56

67
export type IconType = "Email" | "Phone" | "User";
78
export type IconResolverProps = {
89
type: IconType,
910
} & IconProps
1011

11-
export const IconResolver: React.FC<IconResolverProps> = ({ type, color, className, size }) => {
12+
export const IconResolver: React.FC<IconResolverProps> = ({ type, color, className, size, style }): JSX.Element => {
1213
switch (type) {
13-
case "Email": return <EmailIcon className={className} color={color} size={size} />
14-
case "Phone": return <TelephoneIcon className={className} color={color} size={size} />
15-
case "User": return <UserIcon className={className} color={color} size={size} />
16-
default: return <UserIcon className={className} color={color} size={size} />
14+
case "Email": return <EmailIcon className={className} color={color} size={size} style={style} />
15+
case "Phone": return <TelephoneIcon className={className} color={color} size={size} style={style} />
16+
case "User": return <UserIcon className={className} color={color} size={size} style={style} />
17+
default: return <Checkmark className={className} color={color} size={size} style={style} />;
1718
}
1819
}

packages/core/src/components/question/input-types/baseinput/BaseInputComponent.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export const BaseInputComponent: React.FC<BaseInputComponentProps> = ({ question
8282
span.addEvent("BaseInputComponent:render");
8383
}
8484

85-
85+
8686

8787
const resize = () => {
8888
const input = ref.current;
@@ -104,7 +104,7 @@ export const BaseInputComponent: React.FC<BaseInputComponentProps> = ({ question
104104
}
105105

106106
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
107-
console.log("BaseInputComponent:handleChange", event.target.value);
107+
console.log("BaseInputComponent:handleChange", event.target.value);
108108
if (span) {
109109
span.addEvent("BaseInputComponent:handleChange", { 'value': event.target.value });
110110
}
@@ -119,9 +119,9 @@ export const BaseInputComponent: React.FC<BaseInputComponentProps> = ({ question
119119
}
120120

121121
/**
122-
* The input control is responsible of setting it self focus when becoming active.
123-
* - We should also listen to input controls being focused and if not active, trigger a reducer that its set active.
124-
* Ultimatly removing active from other questions. This happens right now when an answer is given (intermediate or not), so not critical.
122+
* The input control is responsible of setting itself focused when becoming active.
123+
* - We should also listen to inputcontrols being focused and if not active, trigger a reducer that sets it to active. Ultimately removing active from other questions.
124+
* This happens right now when an answer is given (intermediate or not), so not critical.
125125
*/
126126
useEffect(() => {
127127
if (questionModel.isActive)
@@ -132,7 +132,7 @@ export const BaseInputComponent: React.FC<BaseInputComponentProps> = ({ question
132132
* While a base input component is active we should answer the question upon enter.
133133
*/
134134
useHandleEnterKeypress("baseinput", !questionModel.isActive, () => {
135-
answerQuestion(questionModel.logicalName, text,false);
135+
answerQuestion(questionModel.logicalName, text, false);
136136
});
137137

138138
return (

packages/core/src/components/question/input-types/multiline/MultilineInput.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,26 @@ const useInputTextStyles = makeStyles({
4343

4444
export const MultilineInput: InputComponentType<MultilineProperties> = ({ questionModel }) => {
4545
const styles = useInputTextStyles();
46-
const { isFirstQuestionInCurrentSlide, answerQuestion } = useQuickForm();
46+
const { isFirstQuestionInCurrentSlide, answerQuestion, state } = useQuickForm();
4747
const { placeholder, output } = questionModel;
4848
const [text, setText] = useState<string>(output || '');
49+
const ref = useRef<HTMLTextAreaElement>(null);
4950

5051
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
5152
const newValue = event.target.value.replace(/\r?\n/g, '\n'); // Normalize newline characters
5253
setText(newValue);
5354
answerQuestion(questionModel.logicalName, newValue, true);
5455
};
5556

56-
const ref = useRef<HTMLTextAreaElement>(null);
57+
/**
58+
* The input control is responsible of setting itself focused when becoming active.
59+
* - We should also listen to inputcontrols being focused and if not active, trigger a reducer that sets it to active. Ultimately removing active from other questions.
60+
* This happens right now when an answer is given (intermediate or not), so not critical.
61+
*/
5762
useEffect(() => {
58-
if (ref.current && isFirstQuestionInCurrentSlide(questionModel.logicalName)) {
59-
ref.current.focus();
60-
}
61-
}, [ref, isFirstQuestionInCurrentSlide, questionModel.logicalName]);
63+
if (questionModel.isActive || ref.current && isFirstQuestionInCurrentSlide(questionModel.logicalName))
64+
ref.current?.focus();
65+
}, [ref, isFirstQuestionInCurrentSlide, questionModel.logicalName, questionModel.isActive]);
6266

6367
return (
6468
<textarea onBlur={() => answerQuestion(questionModel.logicalName, text, false)}

packages/core/src/components/renderers/slide-renderer/SlideRenderer.tsx

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
11
"use client";
22
import React, { useEffect, useRef, useState } from 'react';
33
import { useQuickForm } from '../../../state/QuickFormContext';
4-
import { Button } from '../../button/Button';
4+
import { Button, Slide } from '../../index';
55
import { useHandleEnterKeypress } from '../../../hooks';
6-
import { Slide } from '../../slide/Slide';
7-
import { Checkmark } from '../../icons';
8-
import { quickformtokens } from '../../../style/quickFormTokensDefinition';
6+
import { quickformtokens } from "../../../style";
97
import { mergeClasses } from '@griffel/react';
10-
11-
8+
import { IconResolver } from '../../icons/IconResolver';
9+
import { SlideModel } from '../../../model';
1210

1311
export const SlideRenderer: React.FC = () => {
12+
1413
const { state, goToNextSlide } = useQuickForm();
15-
const currentSlide = state.slides[state.currIdx];
14+
const [className, setClassName] = useState(state.classes.slide);
15+
16+
const currentSlide: SlideModel = state.slides[state.currIdx];
17+
const buttonText: string = currentSlide.buttonText ?? "OK";
18+
const showPressEnter: boolean = currentSlide.questions.some(q => q.inputType === "multilinetext" && q.isActive) === false;
19+
20+
/* KBA - Leaving this for now - have to get back to it since we never actually set .isActive property on question.. so we cant use it to condition with at the moment.. */
21+
// const showPressEnter: boolean = currentSlide.questions.some(q => q.inputType === "multilinetext" && q.isActive) === false;
22+
console.log("showPressEnter", showPressEnter);
23+
console.log("showPressEnterCondition", currentSlide.questions.some(q => q.inputType === "multilinetext" && q.isActive));
24+
console.log("showPressEnterCurrentSlide", currentSlide);
1625

17-
console.log("SlideRenderer", currentSlide);
1826
/* Listens to enter key pressed */
19-
const enterKeyDisabled = currentSlide.questions.some(q => q.inputType === "multilinetext" && q.isActive);
20-
useHandleEnterKeypress("slide", enterKeyDisabled, goToNextSlide);
27+
useHandleEnterKeypress("slide", !showPressEnter, goToNextSlide);
2128

22-
const [className, setClassName] = useState(state.classes.slide);
2329
let nextAllowedEffectTime = useRef(new Date().getTime());
2430
useEffect(() => {
2531
const timeout = setTimeout(() => {
@@ -40,8 +46,13 @@ export const SlideRenderer: React.FC = () => {
4046
<Button
4147
style={{ display: 'flex', alignItems: 'center', justifyContent: 'start' }}
4248
onClick={goToNextSlide}
43-
showPressEnter={!enterKeyDisabled}
44-
children={<>OK<Checkmark style={{ height: '100%', marginLeft: quickformtokens.gap1 }} color={quickformtokens.onPrimary} size={24} /></>} />
49+
showPressEnter={showPressEnter}
50+
children={
51+
<>
52+
{buttonText}<IconResolver type={currentSlide.icon} style={{ height: '100%', marginLeft: quickformtokens.gap1 }} color={quickformtokens.onPrimary} size={24} />
53+
</>
54+
}
55+
/>
4556
</div>
4657
);
4758
};

packages/core/src/model/SlideModel.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import { IconType } from "../components/icons/IconResolver";
12
import { resolveQuickFormService } from "../services/QuickFormServices";
23
import { QuestionModel } from "./QuestionModel";
34
import { QuestionJsonModel } from "./json-definitions/JsonDataModels";
45
import { QuestionRef } from "./json-definitions/Layout";
56

67
export class SlideModel {
78
displayName?: string;
9+
buttonText?: string;
10+
icon?: IconType;
811
questions: QuestionModel[] = [];
912
rows: Row[];
1013

packages/core/src/model/json-definitions/Layout.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { QuickFormTokens } from "../../style/quickFormTokensDefinition";
22
import { QuickformClassNames } from "../../state/QuickformState";
3+
import { IconType } from "../../components/icons/IconResolver";
34

45
export type LayoutDefinition = {
56
classes?: Partial<QuickformClassNames>,
@@ -19,7 +20,9 @@ export type SlideLayout = {
1920
style?: React.CSSProperties;
2021
rows?: SlideElements;
2122
schemaName?: string;
22-
logicalName?: string
23+
logicalName?: string;
24+
buttonText?: string;
25+
icon?: IconType;
2326
}
2427

2528
/**

packages/core/src/services/defaults/DefaultModelTransformer.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ function handleLayout(layout: LayoutDefinition, questions: QuickFormQuestionsDef
9191
Object.values(layout.slides).forEach(slide => {
9292
const slideModel = new SlideModel();
9393
slideModel.displayName = slide.title;
94+
slideModel.buttonText = slide.buttonText;
95+
slideModel.icon = slide.icon;
96+
9497
if (slide.rows) {
9598
slideModel.rows = processRows(slide.rows, slideModel, questions, payload);
9699
}
@@ -112,9 +115,9 @@ function defaultLayout(questions: QuickFormQuestionsDefinition, payload: any): S
112115
Object.keys(questions).map((key, index) => [key, index] as [string, number])
113116
.sort(([q1, i1], [q2, i2]) => (questions[q1].order ?? i1) - (questions[q2].order ?? i2))
114117
.map(([questionKey]) => {
115-
let slide: SlideModel = createSlide({ [questionKey]: questions[questionKey] }, payload);
116-
slides.push(slide);
117-
});
118+
let slide: SlideModel = createSlide({ [questionKey]: questions[questionKey] }, payload);
119+
slides.push(slide);
120+
});
118121

119122
logger.log("Generated {@slides} from layout", slides);
120123

@@ -189,7 +192,7 @@ const transformJSONInput: QuickFormModelTransformer = (definition, payload): Qui
189192

190193
// Transform questions into slides with rows and columns
191194
if (isDefined(definition.questions)) {
192-
if (definition.layout && definition.layout.slides && Object.keys(definition.layout.slides).length>0) {
195+
if (definition.layout && definition.layout.slides && Object.keys(definition.layout.slides).length > 0) {
193196
// If layout is defined, assign slides as per layout
194197
slides = handleLayout(definition.layout!, definition.questions, payload);
195198
} else {

packages/playground/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import { QuickFormDefinition } from '../../core/src/model';
3-
import testdata from "./data/allInputControlsTest.json";
3+
import testdata from "./data/allInputControlsMultipleSlidesTest.json";
44
import { QuickFormProvider } from '../../core/src/state';
55
import { NavigationButton, QuickForm } from '../../core/src/components';
66
import "./components/buttons-input/ButtonsInput";

packages/playground/src/data/allInputControlsMultipleSlidesTest.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"autoAdvanceSlides": false,
44
"slides": {
55
"slide1": {
6+
"buttonText": "Test1",
7+
"icon": "undefined",
68
"title": "Test titel",
79
"rows": {
810
"row1": {
@@ -28,6 +30,8 @@
2830
}
2931
},
3032
"slide2": {
33+
"buttonText": "Test2",
34+
"icon": "Email",
3135
"rows": {
3236
"row1": {
3337
"columns": {
@@ -52,6 +56,8 @@
5256
}
5357
},
5458
"slide3": {
59+
"buttonText": "Test3",
60+
"icon": "undefined",
5561
"rows": {
5662
"row1": {
5763
"columns": {
@@ -177,7 +183,7 @@
177183
"paragraph": "Test af multilinetext",
178184
"lang": "DA"
179185
},
180-
"nameTest": {
186+
"textTest": {
181187
"inputType": "text",
182188
"text": "Text test",
183189
"paragraph": "Test af text",

0 commit comments

Comments
 (0)