diff --git a/package-lock.json b/package-lock.json index 07923fe1..1b7d1534 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "dependencies": { "@aehrc/sdc-assemble": "^1.3.1", "@aehrc/sdc-populate": "^2.3.1", - "@aehrc/smart-forms-renderer": "^0.44.0", + "@aehrc/smart-forms-renderer": "^0.44.1", "@emotion/react": "^11.13.0", "@emotion/styled": "^11.13.0", "@fontsource/material-icons": "^5.0.18", @@ -111,6 +111,45 @@ "yui-lint": "^0.2.0" } }, + "apps/smart-forms-app/node_modules/@aehrc/smart-forms-renderer": { + "version": "0.44.1", + "resolved": "https://registry.npmjs.org/@aehrc/smart-forms-renderer/-/smart-forms-renderer-0.44.1.tgz", + "integrity": "sha512-ytRzHlOm6WVGn6sIP/zWwmNTDUPQDpAfE7fB0NFzApaDXOJkPHVfQAbLldmp3fffEi8l5wuRPkCVXv/jMF0jPQ==", + "dependencies": { + "@aehrc/sdc-populate": "^2.3.1", + "@iconify/react": "^4.1.1", + "dayjs": "^1.11.10", + "deep-diff": "^1.0.2", + "fhirclient": "^2.5.2", + "fhirpath": "3.11.0", + "html-react-parser": "4.2.10", + "js-base64": "^3.7.7", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.difference": "^4.5.0", + "lodash.differencewith": "^4.5.0", + "lodash.intersection": "^4.4.0", + "lodash.isequal": "^4.5.0", + "nanoid": "^5.0.7", + "react-beautiful-dnd": "^13.1.1", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-markdown": "^8.0.7", + "style-to-object": "^1.0.6", + "zustand": "^4.5.5" + }, + "peerDependencies": { + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.15.10", + "@mui/lab": "^5.0.0-alpha.165", + "@mui/material": "^5.15.10", + "@mui/x-date-pickers": "^6.19.4", + "@tanstack/react-query": "^4.36.0", + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "apps/smart-forms-app/node_modules/@typescript-eslint/parser": { "version": "6.21.0", "dev": true, @@ -217,6 +256,11 @@ "balanced-match": "^1.0.0" } }, + "apps/smart-forms-app/node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==" + }, "apps/smart-forms-app/node_modules/lru-cache": { "version": "6.0.0", "dev": true, @@ -273,6 +317,14 @@ "url": "https://opencollective.com/storybook" } }, + "apps/smart-forms-app/node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, "apps/smart-forms-app/node_modules/yallist": { "version": "4.0.0", "dev": true, @@ -451,7 +503,7 @@ "name": "@aehrc/smart-forms-documentation", "version": "0.0.0", "dependencies": { - "@aehrc/smart-forms-renderer": "^0.44.0", + "@aehrc/smart-forms-renderer": "^0.44.1", "@docusaurus/core": "^3.4.0", "@docusaurus/preset-classic": "^3.4.0", "@docusaurus/theme-live-codeblock": "^3.4.0", @@ -481,6 +533,58 @@ "node": ">=18.0" } }, + "documentation/node_modules/@aehrc/smart-forms-renderer": { + "version": "0.44.1", + "resolved": "https://registry.npmjs.org/@aehrc/smart-forms-renderer/-/smart-forms-renderer-0.44.1.tgz", + "integrity": "sha512-ytRzHlOm6WVGn6sIP/zWwmNTDUPQDpAfE7fB0NFzApaDXOJkPHVfQAbLldmp3fffEi8l5wuRPkCVXv/jMF0jPQ==", + "dependencies": { + "@aehrc/sdc-populate": "^2.3.1", + "@iconify/react": "^4.1.1", + "dayjs": "^1.11.10", + "deep-diff": "^1.0.2", + "fhirclient": "^2.5.2", + "fhirpath": "3.11.0", + "html-react-parser": "4.2.10", + "js-base64": "^3.7.7", + "lodash.clonedeep": "^4.5.0", + "lodash.debounce": "^4.0.8", + "lodash.difference": "^4.5.0", + "lodash.differencewith": "^4.5.0", + "lodash.intersection": "^4.4.0", + "lodash.isequal": "^4.5.0", + "nanoid": "^5.0.7", + "react-beautiful-dnd": "^13.1.1", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", + "react-markdown": "^8.0.7", + "style-to-object": "^1.0.6", + "zustand": "^4.5.5" + }, + "peerDependencies": { + "@emotion/react": "^11.11.3", + "@emotion/styled": "^11.11.0", + "@mui/icons-material": "^5.15.10", + "@mui/lab": "^5.0.0-alpha.165", + "@mui/material": "^5.15.10", + "@mui/x-date-pickers": "^6.19.4", + "@tanstack/react-query": "^4.36.0", + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "documentation/node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==" + }, + "documentation/node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "devOptional": true, @@ -10422,6 +10526,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -39546,7 +39651,7 @@ }, "packages/smart-forms-renderer": { "name": "@aehrc/smart-forms-renderer", - "version": "0.44.0", + "version": "1.0.0-alpha.1", "license": "Apache-2.0", "dependencies": { "@aehrc/sdc-populate": "^2.3.1", diff --git a/packages/smart-forms-renderer/package.json b/packages/smart-forms-renderer/package.json index abb48957..33e15933 100644 --- a/packages/smart-forms-renderer/package.json +++ b/packages/smart-forms-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@aehrc/smart-forms-renderer", - "version": "0.44.1", + "version": "1.0.0-alpha.1", "description": "FHIR Structured Data Captured (SDC) rendering engine for Smart Forms", "main": "lib/index.js", "scripts": { diff --git a/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelText.tsx b/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelText.tsx index 1a5388c0..d211461b 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelText.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelText.tsx @@ -25,6 +25,7 @@ import Typography from '@mui/material/Typography'; import useDisplayCqfAndCalculatedExpression from '../../../hooks/useDisplayCqfAndCalculatedExpression'; import { structuredDataCapture } from 'fhir-sdc-helpers'; import { default as styleParse } from 'style-to-js'; +import { useRendererStylingStore } from '../../../stores/rendererStylingStore'; interface ItemLabelTextProps { qItem: QuestionnaireItem; @@ -34,6 +35,8 @@ interface ItemLabelTextProps { const ItemLabelText = memo(function ItemLabelText(props: ItemLabelTextProps) { const { qItem, readOnly } = props; + const itemLabelFontWeight = useRendererStylingStore.use.itemLabelFontWeight(); + let labelText = qItem.text ?? ''; // Use calculatedExpressionString if available @@ -74,9 +77,14 @@ const ItemLabelText = memo(function ItemLabelText(props: ItemLabelTextProps) { return <>{labelText}; } + const textFontWeight = itemLabelFontWeight != 'default' ? itemLabelFontWeight : 'normal'; + // parse regular text return ( - + {labelText} ); diff --git a/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelWrapper.tsx b/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelWrapper.tsx index 7864be40..72a9a71c 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelWrapper.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/ItemLabelWrapper.tsx @@ -24,7 +24,7 @@ import ItemLabelText from './ItemLabelText'; import Tooltip from '@mui/material/Tooltip'; import Typography from '@mui/material/Typography'; import useRenderingExtensions from '../../../hooks/useRenderingExtensions'; -import Iconify from '../../Iconify/Iconify'; +import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; interface LabelWrapperProps { qItem: QuestionnaireItem; @@ -55,19 +55,21 @@ function ItemLabelWrapper(props: LabelWrapperProps) { } }}> - + {required ? ( - + * ) : null} - - {displayFlyover !== '' ? ( - - ) : null} + + + {displayFlyover !== '' ? ( + + ) : null} + diff --git a/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/index.ts b/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/index.ts new file mode 100644 index 00000000..b09bfeff --- /dev/null +++ b/packages/smart-forms-renderer/src/components/FormComponents/ItemParts/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default as ItemFieldGrid } from './ItemFieldGrid'; diff --git a/packages/smart-forms-renderer/src/components/FormComponents/SingleItem/SingleItemSwitcher.tsx b/packages/smart-forms-renderer/src/components/FormComponents/SingleItem/SingleItemSwitcher.tsx index 6edd53da..314f60ed 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/SingleItem/SingleItemSwitcher.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/SingleItem/SingleItemSwitcher.tsx @@ -41,6 +41,7 @@ import IntegerItem from '../IntegerItem/IntegerItem'; import AttachmentItem from '../AttachmentItem/AttachmentItem'; import CustomDateTimeItem from '../DateTimeItems/CustomDateTimeItem/CustomDateTimeItem'; import QuantityItem from '../QuantityItem/QuantityItem'; +import { useQuestionnaireStore } from '../../../stores'; interface SingleItemSwitcherProps extends PropsWithQrItemChangeHandler, @@ -56,6 +57,25 @@ function SingleItemSwitcher(props: SingleItemSwitcherProps) { const { qItem, qrItem, isRepeated, isTabled, showMinimalView, parentIsReadOnly, onQrItemChange } = props; + const customComponents = useQuestionnaireStore.use.customComponents(); + const CustomComponent = customComponents[qItem.linkId]; + + // If a custom component is defined for this item, render it + // Don't get too strict with the checks for now + if (CustomComponent && typeof CustomComponent === 'function') { + return ( + + ); + } + + // Otherwise, render the default form component based on the item type switch (qItem.type) { case 'display': return ; diff --git a/packages/smart-forms-renderer/src/components/FormComponents/StringItem/index.ts b/packages/smart-forms-renderer/src/components/FormComponents/StringItem/index.ts new file mode 100644 index 00000000..dfb5c5fa --- /dev/null +++ b/packages/smart-forms-renderer/src/components/FormComponents/StringItem/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default as StringField } from './StringField'; diff --git a/packages/smart-forms-renderer/src/components/FormComponents/index.ts b/packages/smart-forms-renderer/src/components/FormComponents/index.ts index bd6b316c..ead114e6 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/index.ts +++ b/packages/smart-forms-renderer/src/components/FormComponents/index.ts @@ -21,3 +21,7 @@ export { RepeatGroup } from './RepeatGroup'; export { GroupTable } from './Tables'; export { GridGroup } from './GridGroup'; export { parseFhirDateToDisplayDate } from './DateTimeItems'; +export { ItemFieldGrid } from './ItemParts'; + +// item type components +export { StringField } from './StringItem'; diff --git a/packages/smart-forms-renderer/src/components/index.ts b/packages/smart-forms-renderer/src/components/index.ts index 0fd46cc9..b7383be7 100644 --- a/packages/smart-forms-renderer/src/components/index.ts +++ b/packages/smart-forms-renderer/src/components/index.ts @@ -23,5 +23,10 @@ export { RepeatGroup, GroupTable, GridGroup, - parseFhirDateToDisplayDate + parseFhirDateToDisplayDate, + ItemFieldGrid, + StringField } from './FormComponents'; + +// Styled MUI components +export { FullWidthFormComponentBox } from './Box.styles'; diff --git a/packages/smart-forms-renderer/src/hooks/index.ts b/packages/smart-forms-renderer/src/hooks/index.ts index 5ba1b9c0..0f8ccc8a 100644 --- a/packages/smart-forms-renderer/src/hooks/index.ts +++ b/packages/smart-forms-renderer/src/hooks/index.ts @@ -1,3 +1,9 @@ export { default as useHidden } from './useHidden'; +export { default as useReadOnly } from './useReadOnly'; export { default as useBuildForm } from './useBuildForm'; export { default as useRendererQueryClient } from './useRendererQueryClient'; +export { default as useRenderingExtensions } from './useRenderingExtensions'; +export { default as useValidationFeedback } from './useValidationFeedback'; + +// CalculatedExpression hooks +export { default as useStringCalculatedExpression } from './useStringCalculatedExpression'; diff --git a/packages/smart-forms-renderer/src/hooks/useBuildForm.ts b/packages/smart-forms-renderer/src/hooks/useBuildForm.ts index aa5334f9..ffaa79c6 100644 --- a/packages/smart-forms-renderer/src/hooks/useBuildForm.ts +++ b/packages/smart-forms-renderer/src/hooks/useBuildForm.ts @@ -15,9 +15,10 @@ * limitations under the License. */ -import { useLayoutEffect, useState } from 'react'; +import { ComponentType, useLayoutEffect, useState } from 'react'; import { buildForm } from '../utils'; import type { Questionnaire, QuestionnaireResponse } from 'fhir/r4'; +import { RendererStyling, useRendererStylingStore } from '../stores/rendererStylingStore'; /** * React hook wrapping around the buildForm() function to build a form from a questionnaire and an optional QuestionnaireResponse. @@ -28,6 +29,8 @@ import type { Questionnaire, QuestionnaireResponse } from 'fhir/r4'; * @param readOnly - Applies read-only mode to all items in the form view * @param terminologyServerUrl - Terminology server url to fetch terminology. If not provided, the default terminology server will be used. (optional) * @param additionalVariables - Additional key-value pair of SDC variables `Record` for testing (optional) + * @param rendererStyling - Renderer styling to be applied to the form. See docs for styling options. (optional) + * @param customComponents - FIXME add comment * * @author Sean Fong */ @@ -36,17 +39,27 @@ function useBuildForm( questionnaireResponse?: QuestionnaireResponse, readOnly?: boolean, terminologyServerUrl?: string, - additionalVariables?: Record + additionalVariables?: Record, + rendererStyling?: RendererStyling, + customComponents?: Record> ) { const [isBuilding, setIsBuilding] = useState(true); + const setRendererStyling = useRendererStylingStore.use.setRendererStyling(); + useLayoutEffect(() => { + // Set optional renderer styling + if (rendererStyling) { + setRendererStyling(rendererStyling); + } + buildForm( questionnaire, questionnaireResponse, readOnly, terminologyServerUrl, - additionalVariables + additionalVariables, + customComponents ).then(() => { setIsBuilding(false); }); diff --git a/packages/smart-forms-renderer/src/index.ts b/packages/smart-forms-renderer/src/index.ts index e57d97e7..9a46273f 100644 --- a/packages/smart-forms-renderer/src/index.ts +++ b/packages/smart-forms-renderer/src/index.ts @@ -1,5 +1,12 @@ // interface exports -export type { Tab, Tabs, Variables, VariableXFhirQuery, LaunchContext } from './interfaces'; +export type { + Tab, + Tabs, + Variables, + VariableXFhirQuery, + LaunchContext, + CustomComponentProps +} from './interfaces'; // component exports export type { SmartFormsRendererProps } from './components'; @@ -11,7 +18,10 @@ export { RepeatGroup, GroupTable, GridGroup, - parseFhirDateToDisplayDate + parseFhirDateToDisplayDate, + ItemFieldGrid, + StringField, + FullWidthFormComponentBox } from './components'; // state management store exports @@ -33,7 +43,15 @@ export { } from './stores'; // hooks exports -export { useHidden, useBuildForm, useRendererQueryClient } from './hooks'; +export { + useHidden, + useReadOnly, + useBuildForm, + useRendererQueryClient, + useRenderingExtensions, + useValidationFeedback, + useStringCalculatedExpression +} from './hooks'; // utils exports export type { ItemToRepopulate } from './utils'; @@ -43,6 +61,7 @@ export { getResponse, removeEmptyAnswersFromResponse, removeInternalIdsFromResponse, + createEmptyQrItem, isSpecificItemControl, isRepeatItemAndNotCheckbox, initialiseQuestionnaireResponse, diff --git a/packages/smart-forms-renderer/src/interfaces/customComponent.interface.ts b/packages/smart-forms-renderer/src/interfaces/customComponent.interface.ts new file mode 100644 index 00000000..e0d29eb0 --- /dev/null +++ b/packages/smart-forms-renderer/src/interfaces/customComponent.interface.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { QuestionnaireItem, type QuestionnaireResponseItem } from 'fhir/r4'; + +export interface CustomComponentProps { + qItem: QuestionnaireItem; + qrItem: QuestionnaireResponseItem | null; + isRepeated: boolean; + isTabled: boolean; + parentIsReadOnly?: boolean; + onQrItemChange: (qrItem: QuestionnaireResponseItem) => unknown; +} diff --git a/packages/smart-forms-renderer/src/interfaces/index.ts b/packages/smart-forms-renderer/src/interfaces/index.ts index a086d07a..1c1bf7e6 100644 --- a/packages/smart-forms-renderer/src/interfaces/index.ts +++ b/packages/smart-forms-renderer/src/interfaces/index.ts @@ -19,3 +19,4 @@ export type { Tab, Tabs } from './tab.interface'; export type { Variables, VariableXFhirQuery } from './variables.interface'; export type { LaunchContext } from './populate.interface'; export type { EnableWhenItems, EnableWhenExpressions } from './enableWhen.interface'; +export type { CustomComponentProps } from './customComponent.interface'; diff --git a/packages/smart-forms-renderer/src/stores/questionnaireStore.ts b/packages/smart-forms-renderer/src/stores/questionnaireStore.ts index 0d7d2917..baa7011f 100644 --- a/packages/smart-forms-renderer/src/stores/questionnaireStore.ts +++ b/packages/smart-forms-renderer/src/stores/questionnaireStore.ts @@ -48,6 +48,8 @@ import { questionnaireResponseStore } from './questionnaireResponseStore'; import { createQuestionnaireResponseItemMap } from '../utils/questionnaireResponseStoreUtils/updatableResponseItems'; import { insertCompleteAnswerOptionsIntoQuestionnaire } from '../utils/questionnaireStoreUtils/insertAnswerOptions'; import type { InitialExpression } from '../interfaces/initialExpression.interface'; +import React from 'react'; +import { CustomComponentProps } from '../interfaces/customComponent.interface'; /** * QuestionnaireStore properties and methods @@ -116,6 +118,7 @@ export interface QuestionnaireStoreType { cachedValueSetCodings: Record; fhirPathContext: Record; populatedContext: Record; + customComponents: Record>; focusedLinkId: string; readOnly: boolean; buildSourceQuestionnaire: ( @@ -123,7 +126,8 @@ export interface QuestionnaireStoreType { questionnaireResponse?: QuestionnaireResponse, additionalVariables?: Record, terminologyServerUrl?: string, - readOnly?: boolean + readOnly?: boolean, + customComponents?: Record> ) => Promise; destroySourceQuestionnaire: () => void; switchTab: (newTabIndex: number) => void; @@ -182,6 +186,7 @@ export const questionnaireStore = createStore()((set, ge cachedValueSetCodings: {}, fhirPathContext: {}, populatedContext: {}, + customComponents: {}, focusedLinkId: '', readOnly: false, buildSourceQuestionnaire: async ( @@ -189,7 +194,8 @@ export const questionnaireStore = createStore()((set, ge questionnaireResponse = structuredClone(emptyResponse), additionalVariables = {}, terminologyServerUrl = terminologyServerStore.getState().url, - readOnly = false + readOnly = false, + customComponents = {} ) => { const questionnaireModel = await createQuestionnaireModel( questionnaire, @@ -242,6 +248,7 @@ export const questionnaireStore = createStore()((set, ge processedValueSetCodings: questionnaireModel.processedValueSetCodings, processedValueSetUrls: questionnaireModel.processedValueSetUrls, fhirPathContext: updatedFhirPathContext, + customComponents: customComponents, readOnly: readOnly }); }, @@ -264,7 +271,8 @@ export const questionnaireStore = createStore()((set, ge answerExpressions: {}, processedValueSetCodings: {}, processedValueSetUrls: {}, - fhirPathContext: {} + fhirPathContext: {}, + customComponents: {} }), switchTab: (newTabIndex: number) => set(() => ({ currentTabIndex: newTabIndex })), switchPage: (newPageIndex: number) => set(() => ({ currentPageIndex: newPageIndex })), diff --git a/packages/smart-forms-renderer/src/stores/rendererStylingStore.ts b/packages/smart-forms-renderer/src/stores/rendererStylingStore.ts new file mode 100644 index 00000000..36727850 --- /dev/null +++ b/packages/smart-forms-renderer/src/stores/rendererStylingStore.ts @@ -0,0 +1,67 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createStore } from 'zustand/vanilla'; +import { createSelectors } from './selector'; + +export interface RendererStyling { + itemLabelFontWeight?: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'default'; +} + +/** + * RendererStylingStore properties and methods + * + * @author Sean Fong + */ +export interface RendererStylingStoreType { + itemLabelFontWeight: + | '100' + | '200' + | '300' + | '400' + | '500' + | '600' + | '700' + | '800' + | '900' + | 'default'; + setRendererStyling: (params: RendererStyling) => void; +} + +/** + * @author Sean Fong + */ +export const rendererStylingStore = createStore()((set) => ({ + itemLabelFontWeight: 'default', + setRendererStyling: (params: RendererStyling) => { + set(() => ({ + itemLabelFontWeight: params.itemLabelFontWeight ?? 'default' + })); + } +})); + +export const useRendererStylingStore = createSelectors(rendererStylingStore); diff --git a/packages/smart-forms-renderer/src/utils/index.ts b/packages/smart-forms-renderer/src/utils/index.ts index 8198c0a1..1ea850b8 100644 --- a/packages/smart-forms-renderer/src/utils/index.ts +++ b/packages/smart-forms-renderer/src/utils/index.ts @@ -23,6 +23,8 @@ export { removeInternalIdsFromResponse } from './manageForm'; export { initialiseQuestionnaireResponse } from './initialise'; +export { createEmptyQrItem } from './qrItem'; + export { isSpecificItemControl } from './itemControl'; export { isRepeatItemAndNotCheckbox } from './qItem'; export type { ItemToRepopulate } from './repopulateItems'; diff --git a/packages/smart-forms-renderer/src/utils/manageForm.ts b/packages/smart-forms-renderer/src/utils/manageForm.ts index c6abce07..af625de2 100644 --- a/packages/smart-forms-renderer/src/utils/manageForm.ts +++ b/packages/smart-forms-renderer/src/utils/manageForm.ts @@ -11,6 +11,7 @@ import { readEncounter, readPatient, readUser } from '../api/smartClient'; import type Client from 'fhirclient/lib/Client'; import { updateQuestionnaireResponse } from './genericRecursive'; import { removeInternalRepeatIdsRecursive } from './removeRepeatId'; +import { ComponentType } from 'react'; /** * Build the form with an initial Questionnaire and an optional filled QuestionnaireResponse. @@ -22,6 +23,7 @@ import { removeInternalRepeatIdsRecursive } from './removeRepeatId'; * @param readOnly - Applies read-only mode to all items in the form view * @param terminologyServerUrl - Terminology server url to fetch terminology. If not provided, the default terminology server will be used. (optional) * @param additionalVariables - Additional key-value pair of SDC variables `Record` for testing (optional) + * @param customComponents - FIXME add comment * * @author Sean Fong */ @@ -30,7 +32,8 @@ export async function buildForm( questionnaireResponse?: QuestionnaireResponse, readOnly?: boolean, terminologyServerUrl?: string, - additionalVariables?: Record + additionalVariables?: Record, + customComponents?: Record> ): Promise { // Reset terminology server if (terminologyServerUrl) { @@ -42,7 +45,14 @@ export async function buildForm( // QR is set to undefined here to prevent it from being initialised twice. This is defined like that for backward compatibility purposes. await questionnaireStore .getState() - .buildSourceQuestionnaire(questionnaire, undefined, additionalVariables, terminologyServerUrl); + .buildSourceQuestionnaire( + questionnaire, + undefined, + additionalVariables, + terminologyServerUrl, + undefined, + customComponents + ); const initialisedQuestionnaireResponse = initialiseQuestionnaireResponse( questionnaire,