import React from 'react' import Slugify from 'slugify' import {saveAs} from 'file-saver' import {version} from 'maplibre-gl/package.json' import {format} from '@maplibre/maplibre-gl-style-spec' import {MdMap, MdSave} from 'react-icons/md' import {WithTranslation, withTranslation} from 'react-i18next'; import FieldString from './FieldString' import InputButton from './InputButton' import Modal from './Modal' import style from '../libs/style' import fieldSpecAdditional from '../libs/field-spec-additional' import type {OnStyleChangedCallback, StyleSpecificationWithId} from '../libs/definitions' const MAPLIBRE_GL_VERSION = version; const showSaveFilePickerAvailable = typeof window.showSaveFilePicker === "function"; type ModalExportInternalProps = { mapStyle: StyleSpecificationWithId onStyleChanged: OnStyleChangedCallback isOpen: boolean onOpenToggle(...args: unknown[]): unknown onSetFileHandle(fileHandle: FileSystemFileHandle | null): unknown fileHandle: FileSystemFileHandle | null } & WithTranslation; class ModalExportInternal extends React.Component { tokenizedStyle() { return format( style.stripAccessTokens( style.replaceAccessTokens(this.props.mapStyle) ) ); } exportName() { if (this.props.mapStyle.name) { return Slugify(this.props.mapStyle.name, { replacement: '_', remove: /[*\-+~.()'"!:]/g, lower: true }); } else { return this.props.mapStyle.id } } createHtml() { const tokenStyle = this.tokenizedStyle(); const htmlTitle = this.props.mapStyle.name || this.props.t("Map"); const html = ` ${htmlTitle}
`; const blob = new Blob([html], {type: "text/html;charset=utf-8"}); const exportName = this.exportName(); saveAs(blob, exportName + ".html"); } async saveStyle() { const tokenStyle = this.tokenizedStyle(); // it is not guaranteed that the File System Access API is available on all // browsers. If the function is not available, a fallback behavior is used. if (!showSaveFilePickerAvailable) { const blob = new Blob([tokenStyle], {type: "application/json;charset=utf-8"}); const exportName = this.exportName(); saveAs(blob, exportName + ".json"); return; } let fileHandle = this.props.fileHandle; if (fileHandle == null) { fileHandle = await this.createFileHandle(); this.props.onSetFileHandle(fileHandle) if (fileHandle == null) return; } const writable = await fileHandle.createWritable(); await writable.write(tokenStyle); await writable.close(); this.props.onOpenToggle(); } async saveStyleAs() { const tokenStyle = this.tokenizedStyle(); const fileHandle = await this.createFileHandle(); this.props.onSetFileHandle(fileHandle) if (fileHandle == null) return; const writable = await fileHandle.createWritable(); await writable.write(tokenStyle); await writable.close(); this.props.onOpenToggle(); } async createFileHandle(): Promise { const pickerOpts: SaveFilePickerOptions = { types: [ { description: "json", accept: {"application/json": [".json"]}, }, ], suggestedName: this.exportName(), }; const fileHandle = await window.showSaveFilePicker(pickerOpts) as FileSystemFileHandle; this.props.onSetFileHandle(fileHandle) return fileHandle; } changeMetadataProperty(property: string, value: any) { const changedStyle = { ...this.props.mapStyle, metadata: { ...this.props.mapStyle.metadata as any, [property]: value } } this.props.onStyleChanged(changedStyle) } render() { const t = this.props.t; const fsa = fieldSpecAdditional(t); return

{t("Save Style")}

{t("Save the JSON style to your computer.")}

{t("Save")} {showSaveFilePickerAvailable && ( {t("Save as")} )} {t("Create HTML")}
} } const ModalExport = withTranslation()(ModalExportInternal); export default ModalExport;