mirror of
https://github.com/maputnik/editor.git
synced 2025-12-30 18:10:01 +00:00
Migration of jsx files to tsx 1 (#848)
In this PR I have changed some of the jsx files to tsx file. I'm starting off with the "leafs" so that migration of the rest will be easier, hopefully. What I'm basically doing is taking a jsx file, copy paste it into: https://mskelton.dev/ratchet And after that I'm fixing the types as needed. It's not a very long process. Hopefully more PRs will follow and this will be over soon. I don't plan to migrate the storybook as I generally don't understand why is it useful, I'll open an issue to see if anyone thinks differently.
This commit is contained in:
262
src/components/ModalOpen.tsx
Normal file
262
src/components/ModalOpen.tsx
Normal file
@@ -0,0 +1,262 @@
|
||||
import React, { FormEvent } from 'react'
|
||||
import {MdFileUpload} from 'react-icons/md'
|
||||
import {MdAddCircleOutline} from 'react-icons/md'
|
||||
import FileReaderInput, { Result } from 'react-file-reader-input'
|
||||
|
||||
import ModalLoading from './ModalLoading'
|
||||
import Modal from './Modal'
|
||||
import InputButton from './InputButton'
|
||||
import InputUrl from './InputUrl'
|
||||
|
||||
import style from '../libs/style'
|
||||
import publicStyles from '../config/styles.json'
|
||||
|
||||
type PublicStyleProps = {
|
||||
url: string
|
||||
thumbnailUrl: string
|
||||
title: string
|
||||
onSelect(...args: unknown[]): unknown
|
||||
};
|
||||
|
||||
class PublicStyle extends React.Component<PublicStyleProps> {
|
||||
render() {
|
||||
return <div className="maputnik-public-style">
|
||||
<InputButton
|
||||
className="maputnik-public-style-button"
|
||||
aria-label={this.props.title}
|
||||
onClick={() => this.props.onSelect(this.props.url)}
|
||||
>
|
||||
<div className="maputnik-public-style-header">
|
||||
<div>{this.props.title}</div>
|
||||
<span className="maputnik-space" />
|
||||
<MdAddCircleOutline />
|
||||
</div>
|
||||
<div
|
||||
className="maputnik-public-style-thumbnail"
|
||||
style={{
|
||||
backgroundImage: `url(${this.props.thumbnailUrl})`
|
||||
}}
|
||||
></div>
|
||||
</InputButton>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
type ModalOpenProps = {
|
||||
isOpen: boolean
|
||||
onOpenToggle(...args: unknown[]): unknown
|
||||
onStyleOpen(...args: unknown[]): unknown
|
||||
};
|
||||
|
||||
type ModalOpenState = {
|
||||
styleUrl: string
|
||||
error?: string | null
|
||||
activeRequest?: any
|
||||
activeRequestUrl?: string | null
|
||||
};
|
||||
|
||||
export default class ModalOpen extends React.Component<ModalOpenProps, ModalOpenState> {
|
||||
constructor(props: ModalOpenProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
styleUrl: ""
|
||||
};
|
||||
}
|
||||
|
||||
clearError() {
|
||||
this.setState({
|
||||
error: null
|
||||
})
|
||||
}
|
||||
|
||||
onCancelActiveRequest(e: Event) {
|
||||
// Else the click propagates to the underlying modal
|
||||
if(e) e.stopPropagation();
|
||||
|
||||
if(this.state.activeRequest) {
|
||||
this.state.activeRequest.abort();
|
||||
this.setState({
|
||||
activeRequest: null,
|
||||
activeRequestUrl: null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onStyleSelect = (styleUrl: string) => {
|
||||
this.clearError();
|
||||
|
||||
let canceled: boolean = false;
|
||||
|
||||
fetch(styleUrl, {
|
||||
mode: 'cors',
|
||||
credentials: "same-origin"
|
||||
})
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
})
|
||||
.then((body) => {
|
||||
if(canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
activeRequest: null,
|
||||
activeRequestUrl: null
|
||||
});
|
||||
|
||||
const mapStyle = style.ensureStyleValidity(body)
|
||||
console.log('Loaded style ', mapStyle.id)
|
||||
this.props.onStyleOpen(mapStyle)
|
||||
this.onOpenToggle()
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setState({
|
||||
error: `Failed to load: '${styleUrl}'`,
|
||||
activeRequest: null,
|
||||
activeRequestUrl: null
|
||||
});
|
||||
console.error(err);
|
||||
console.warn('Could not open the style URL', styleUrl)
|
||||
})
|
||||
|
||||
this.setState({
|
||||
activeRequest: {
|
||||
abort: function() {
|
||||
canceled = true;
|
||||
}
|
||||
},
|
||||
activeRequestUrl: styleUrl
|
||||
})
|
||||
}
|
||||
|
||||
onSubmitUrl = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
this.onStyleSelect(this.state.styleUrl);
|
||||
}
|
||||
|
||||
onUpload = (_: any, files: Result[]) => {
|
||||
const [_e, file] = files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
this.clearError();
|
||||
|
||||
reader.readAsText(file, "UTF-8");
|
||||
reader.onload = e => {
|
||||
let mapStyle;
|
||||
try {
|
||||
mapStyle = JSON.parse(e.target?.result as string)
|
||||
}
|
||||
catch(err) {
|
||||
this.setState({
|
||||
error: (err as Error).toString()
|
||||
});
|
||||
return;
|
||||
}
|
||||
mapStyle = style.ensureStyleValidity(mapStyle)
|
||||
this.props.onStyleOpen(mapStyle);
|
||||
this.onOpenToggle();
|
||||
}
|
||||
reader.onerror = e => console.log(e.target);
|
||||
}
|
||||
|
||||
onOpenToggle() {
|
||||
this.setState({
|
||||
styleUrl: ""
|
||||
});
|
||||
this.clearError();
|
||||
this.props.onOpenToggle();
|
||||
}
|
||||
|
||||
onChangeUrl = (url: string) => {
|
||||
this.setState({
|
||||
styleUrl: url,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const styleOptions = publicStyles.map(style => {
|
||||
return <PublicStyle
|
||||
key={style.id}
|
||||
url={style.url}
|
||||
title={style.title}
|
||||
thumbnailUrl={style.thumbnail}
|
||||
onSelect={this.onStyleSelect}
|
||||
/>
|
||||
})
|
||||
|
||||
let errorElement;
|
||||
if(this.state.error) {
|
||||
errorElement = (
|
||||
<div className="maputnik-modal-error">
|
||||
{this.state.error}
|
||||
<a href="#" onClick={() => this.clearError()} className="maputnik-modal-error-close">×</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Modal
|
||||
data-wd-key="modal:open"
|
||||
isOpen={this.props.isOpen}
|
||||
onOpenToggle={() => this.onOpenToggle()}
|
||||
title={'Open Style'}
|
||||
>
|
||||
{errorElement}
|
||||
<section className="maputnik-modal-section">
|
||||
<h1>Upload Style</h1>
|
||||
<p>Upload a JSON style from your computer.</p>
|
||||
<FileReaderInput onChange={this.onUpload} tabIndex={-1} aria-label="Style file">
|
||||
<InputButton className="maputnik-upload-button"><MdFileUpload /> Upload</InputButton>
|
||||
</FileReaderInput>
|
||||
</section>
|
||||
|
||||
<section className="maputnik-modal-section">
|
||||
<form onSubmit={this.onSubmitUrl}>
|
||||
<h1>Load from URL</h1>
|
||||
<p>
|
||||
Load from a URL. Note that the URL must have <a href="https://enable-cors.org" target="_blank" rel="noopener noreferrer">CORS enabled</a>.
|
||||
</p>
|
||||
<InputUrl
|
||||
aria-label="Style URL"
|
||||
data-wd-key="modal:open.url.input"
|
||||
type="text"
|
||||
className="maputnik-input"
|
||||
default="Enter URL..."
|
||||
value={this.state.styleUrl}
|
||||
onInput={this.onChangeUrl}
|
||||
onChange={this.onChangeUrl}
|
||||
/>
|
||||
<div>
|
||||
<InputButton
|
||||
data-wd-key="modal:open.url.button"
|
||||
type="submit"
|
||||
className="maputnik-big-button"
|
||||
disabled={this.state.styleUrl.length < 1}
|
||||
>Load from URL</InputButton>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section className="maputnik-modal-section maputnik-modal-section--shrink">
|
||||
<h1>Gallery Styles</h1>
|
||||
<p>
|
||||
Open one of the publicly available styles to start from.
|
||||
</p>
|
||||
<div className="maputnik-style-gallery-container">
|
||||
{styleOptions}
|
||||
</div>
|
||||
</section>
|
||||
</Modal>
|
||||
|
||||
<ModalLoading
|
||||
isOpen={!!this.state.activeRequest}
|
||||
title={'Loading style'}
|
||||
onCancel={(e: Event) => this.onCancelActiveRequest(e)}
|
||||
message={"Loading: "+this.state.activeRequestUrl}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user