diff --git a/.storybook/decorators.tsx b/.storybook/decorators.tsx index da0a0bd7..2ad69c94 100644 --- a/.storybook/decorators.tsx +++ b/.storybook/decorators.tsx @@ -10,6 +10,7 @@ import { DEFAULT_COMPONENT_TREE, DEFAULT_DOCUMENT_TYPES, DEFAULT_FILE_TYPES, + DEFAULT_MAP_TILE_LAYERS, DEFAULT_PREFILL_ATTRIBUTES, DEFAULT_PREFILL_PLUGINS, DEFAULT_REGISTRATION_ATTRIBUTES, @@ -74,6 +75,7 @@ export const BuilderContextDecorator: Decorator = (Story, context) => { uniquifyKey: key => key, supportedLanguageCodes: supportedLanguageCodes, richTextColors: DEFAULT_COLORS, + getMapTileLayers: async () => DEFAULT_MAP_TILE_LAYERS, theme, getFormComponents: () => context?.args?.componentTree || defaultComponentTree, getValidatorPlugins: async () => { diff --git a/package-lock.json b/package-lock.json index 4d8e1ab9..68c183d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "@formatjs/cli": "^6.1.1", "@formatjs/ts-transformer": "^3.12.0", "@fortawesome/fontawesome-free": "^6.4.0", - "@open-formulieren/types": "^0.35.0", + "@open-formulieren/types": "^0.37.0", "@storybook/addon-actions": "^8.3.5", "@storybook/addon-essentials": "^8.3.5", "@storybook/addon-interactions": "^8.3.5", @@ -5087,10 +5087,11 @@ } }, "node_modules/@open-formulieren/types": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@open-formulieren/types/-/types-0.35.0.tgz", - "integrity": "sha512-89LHE9MF6t0pp5IfQqEnrA2QA4zQDpbE47VD6F+s5SRdZeaBt6GbKuwcCUjz3Fwhr1C+iq2MtgJ5YcX6XRtpSw==", - "dev": true + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@open-formulieren/types/-/types-0.37.0.tgz", + "integrity": "sha512-8lgFytKGV9AeoUQ1oaYZcsoZoyWe/KoFJKkp66V8QQ9pd/IUt6i92VzTZSOqRr0D3kuMGf7aChXEJOhnaEcWSA==", + "dev": true, + "license": "EUPL-1.2" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -24606,9 +24607,9 @@ } }, "@open-formulieren/types": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@open-formulieren/types/-/types-0.35.0.tgz", - "integrity": "sha512-89LHE9MF6t0pp5IfQqEnrA2QA4zQDpbE47VD6F+s5SRdZeaBt6GbKuwcCUjz3Fwhr1C+iq2MtgJ5YcX6XRtpSw==", + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@open-formulieren/types/-/types-0.37.0.tgz", + "integrity": "sha512-8lgFytKGV9AeoUQ1oaYZcsoZoyWe/KoFJKkp66V8QQ9pd/IUt6i92VzTZSOqRr0D3kuMGf7aChXEJOhnaEcWSA==", "dev": true }, "@pkgjs/parseargs": { diff --git a/package.json b/package.json index 0f19cb9e..918ab50e 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@formatjs/cli": "^6.1.1", "@formatjs/ts-transformer": "^3.12.0", "@fortawesome/fontawesome-free": "^6.4.0", - "@open-formulieren/types": "^0.35.0", + "@open-formulieren/types": "^0.37.0", "@storybook/addon-actions": "^8.3.5", "@storybook/addon-essentials": "^8.3.5", "@storybook/addon-interactions": "^8.3.5", diff --git a/src/components/ComponentConfiguration.stories.tsx b/src/components/ComponentConfiguration.stories.tsx index 15f3ce89..6aba7ed3 100644 --- a/src/components/ComponentConfiguration.stories.tsx +++ b/src/components/ComponentConfiguration.stories.tsx @@ -13,6 +13,7 @@ import { DEFAULT_COLORS, DEFAULT_DOCUMENT_TYPES, DEFAULT_FILE_TYPES, + DEFAULT_MAP_TILE_LAYERS, } from '@/tests/sharedUtils'; import {AnyComponentSchema} from '@/types'; @@ -109,6 +110,7 @@ const Template: StoryFn = ({ getPrefillPlugins={async () => prefillPlugins} getPrefillAttributes={async (plugin: string) => prefillAttributes[plugin]} getFileTypes={async () => fileTypes} + getMapTileLayers={async () => DEFAULT_MAP_TILE_LAYERS} serverUploadLimit="50MB" getDocumentTypes={async () => DEFAULT_DOCUMENT_TYPES} getConfidentialityLevels={async () => CONFIDENTIALITY_LEVELS} diff --git a/src/components/ComponentConfiguration.tsx b/src/components/ComponentConfiguration.tsx index eca05a25..7fec9d2a 100644 --- a/src/components/ComponentConfiguration.tsx +++ b/src/components/ComponentConfiguration.tsx @@ -33,6 +33,7 @@ const ComponentConfiguration: React.FC = ({ uniquifyKey, supportedLanguageCodes = ['nl', 'en'], richTextColors, + getMapTileLayers, theme, getFormComponents, getValidatorPlugins, @@ -60,6 +61,7 @@ const ComponentConfiguration: React.FC = ({ uniquifyKey, supportedLanguageCodes, richTextColors, + getMapTileLayers, theme, getFormComponents, getValidatorPlugins, diff --git a/src/components/builder/loader.stories.tsx b/src/components/builder/loader.stories.tsx new file mode 100644 index 00000000..bdcefc32 --- /dev/null +++ b/src/components/builder/loader.stories.tsx @@ -0,0 +1,15 @@ +import {Meta, StoryObj} from '@storybook/react'; + +import Loader from '@/components/builder/loader'; + +type Story = StoryObj; + +export default { + title: 'Formio/Builder/Loader', + component: Loader, + parameters: { + modal: {noModal: true}, + }, +} satisfies Meta; + +export const Default: Story = {}; diff --git a/src/components/builder/loader.tsx b/src/components/builder/loader.tsx new file mode 100644 index 00000000..5d54c777 --- /dev/null +++ b/src/components/builder/loader.tsx @@ -0,0 +1,13 @@ +import {FormattedMessage} from 'react-intl'; + +const Loader: React.FC = () => { + return ( +
+ + + +
+ ); +}; + +export default Loader; diff --git a/src/context.ts b/src/context.ts index 3d42eb93..6af2f831 100644 --- a/src/context.ts +++ b/src/context.ts @@ -29,6 +29,17 @@ export interface DocumentTypeOption { description: string; } +/* + Map tile layers + + This datastructure is created by the Open Forms backend. + */ +export interface MapTileLayer { + identifier: string; + url: string; + label: string; +} + /* Builder */ @@ -48,6 +59,7 @@ export interface BuilderContextType { getDocumentTypes: () => Promise>; getConfidentialityLevels: () => Promise; getAuthPlugins: () => Promise; + getMapTileLayers: () => Promise; } const BuilderContext = React.createContext({ @@ -65,6 +77,7 @@ const BuilderContext = React.createContext({ getDocumentTypes: async () => [], getConfidentialityLevels: async () => [], getAuthPlugins: async () => [], + getMapTileLayers: async () => [], }); BuilderContext.displayName = 'BuilderContext'; diff --git a/src/registry/map/edit.tsx b/src/registry/map/edit.tsx index f4613db4..4ce73b10 100644 --- a/src/registry/map/edit.tsx +++ b/src/registry/map/edit.tsx @@ -1,7 +1,8 @@ import {MapComponentSchema} from '@open-formulieren/types'; import {useFormikContext} from 'formik'; -import {useEffect} from 'react'; +import {useContext, useEffect} from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; +import useAsync from 'react-use/esm/useAsync'; import { BuilderTabs, @@ -20,7 +21,8 @@ import { useDeriveComponentKey, } from '@/components/builder'; import {LABELS} from '@/components/builder/messages'; -import {Checkbox, TabList, TabPanel, Tabs} from '@/components/formio'; +import {Checkbox, Select, TabList, TabPanel, Tabs} from '@/components/formio'; +import {BuilderContext} from '@/context'; import {useErrorChecker} from '@/utils/errors'; import {EditFormDefinition} from '../types'; @@ -62,7 +64,8 @@ const EditForm: EditFormDefinition = () => { 'isSensitiveData', 'useConfigDefaultMapSettings', 'defaultZoom', - 'initialCenter' + 'initialCenter', + 'tileLayerIdentifier' )} /> @@ -83,6 +86,7 @@ const EditForm: EditFormDefinition = () => { {!values.useConfigDefaultMapSettings && } + {/* Advanced tab */} @@ -134,6 +138,7 @@ EditForm.defaultValues = { lat: undefined, lng: undefined, }, + tileLayerIdentifier: undefined, defaultValue: null, // Advanced tab conditional: { @@ -174,4 +179,38 @@ const UseConfigDefaultMapSettings: React.FC<{}> = () => { ); }; +const TileLayer: React.FC = () => { + const {getMapTileLayers} = useContext(BuilderContext); + const intl = useIntl(); + const {value: options, loading, error} = useAsync(async () => await getMapTileLayers(), []); + if (error) { + throw error; + } + + const tooltip = intl.formatMessage({ + description: "Tooltip for 'tileLayerIdentifier' builder field", + defaultMessage: + 'The tile layer is responsible for showing the map background. ' + + 'This effects the map style at particular coordinates and zoom levels.', + }); + return ( +