Compare commits

...

8 Commits

Author SHA1 Message Date
HarelM 732581c39e More components migration 2023-12-21 13:30:19 +02:00
HarelM f435ab79c1 More components migration 2023-12-21 13:14:34 +02:00
HarelM 50226a9b2e Fix build 2023-12-21 12:00:19 +02:00
HarelM e5688fd9a5 More components migration 2023-12-21 11:58:20 +02:00
HarelM 0e39476bd9 Migrate block and field doc label 2023-12-21 10:39:54 +02:00
HarelM 19fc3970a9 Migrate more components 2023-12-21 10:27:54 +02:00
HarelM 1a09de238a Fix typescript error 2023-12-21 09:24:59 +02:00
HarelM 66a0ee5d4e Initial migration of jsx files 2023-12-21 09:23:06 +02:00
38 changed files with 507 additions and 406 deletions
+75
View File
@@ -67,11 +67,16 @@
"@storybook/react": "^7.6.5",
"@storybook/react-vite": "^7.6.5",
"@storybook/theming": "^7.6.5",
"@types/color": "^3.0.6",
"@types/cors": "^2.8.17",
"@types/lodash.isequal": "^4.5.8",
"@types/lodash.throttle": "^4.1.9",
"@types/react": "^16.14.52",
"@types/react-aria-modal": "^4.0.9",
"@types/react-autocomplete": "^1.8.9",
"@types/react-color": "^3.0.10",
"@types/react-dom": "^16.9.24",
"@types/react-icon-base": "^2.1.6",
"@types/uuid": "^9.0.7",
"@vitejs/plugin-react": "^4.2.0",
"cors": "^2.8.5",
@@ -4583,6 +4588,30 @@
"@types/chai": "*"
}
},
"node_modules/@types/color": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.6.tgz",
"integrity": "sha512-NMiNcZFRUAiUUCCf7zkAelY8eV3aKqfbzyFQlXpPIEeoNDbsEHGpb854V3gzTsGKYj830I5zPuOwU/TP5/cW6A==",
"dev": true,
"dependencies": {
"@types/color-convert": "*"
}
},
"node_modules/@types/color-convert": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.3.tgz",
"integrity": "sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==",
"dev": true,
"dependencies": {
"@types/color-name": "*"
}
},
"node_modules/@types/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-87W6MJCKZYDhLAx/J1ikW8niMvmGRyY+rpUxWpL1cO7F8Uu5CHuQoFv+R0/L5pgNdW4jTyda42kv60uwVIPjLw==",
"dev": true
},
"node_modules/@types/connect": {
"version": "3.4.38",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
@@ -4831,6 +4860,34 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-aria-modal": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/react-aria-modal/-/react-aria-modal-4.0.9.tgz",
"integrity": "sha512-H8SU5QoB+1ldMGYRHNm1MXfzD5oD+ZdYTrwVzT+KEiFrkTqQG2QdwVc6Ro4/RixnU4LNtMpvF5HKAIfzzGJGjw==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-autocomplete": {
"version": "1.8.9",
"resolved": "https://registry.npmjs.org/@types/react-autocomplete/-/react-autocomplete-1.8.9.tgz",
"integrity": "sha512-Il8qJEKvPU0uW+HOPiRHIKxGF61RM6cM5tEnZDmM5ek78OK5kfv04AZbNyqdPsuTnwp8HIRgBnQH2RhgKILjcg==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-color": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.10.tgz",
"integrity": "sha512-6K5BAn3zyd8lW8UbckIAVeXGxR82Za9jyGD2DBEynsa7fKaguLDVtjfypzs7fgEV7bULgs7uhds8A8v1wABTvQ==",
"dev": true,
"dependencies": {
"@types/react": "*",
"@types/reactcss": "*"
}
},
"node_modules/@types/react-dom": {
"version": "16.9.24",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.24.tgz",
@@ -4840,6 +4897,24 @@
"@types/react": "^16"
}
},
"node_modules/@types/react-icon-base": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/@types/react-icon-base/-/react-icon-base-2.1.6.tgz",
"integrity": "sha512-ebbN1JjCm6RxBd3HdI1+8VCdiOI4qMjnl9DIHWJFrB/eYLF4mzIgdL34PIqCJBLY3vlwil9v6IHQvzsa8vgMsg==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/reactcss": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.11.tgz",
"integrity": "sha512-0fFy0ubuPlhksId8r9V8nsLcxBAPQnn15g/ERAElgE9L6rOquMj2CapsxqfyBuHlkp0/ndEUVnkYI7MkTtkGpw==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/resolve": {
"version": "1.20.6",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
+5
View File
@@ -96,11 +96,16 @@
"@storybook/react": "^7.6.5",
"@storybook/react-vite": "^7.6.5",
"@storybook/theming": "^7.6.5",
"@types/color": "^3.0.6",
"@types/cors": "^2.8.17",
"@types/lodash.isequal": "^4.5.8",
"@types/lodash.throttle": "^4.1.9",
"@types/react": "^16.14.52",
"@types/react-aria-modal": "^4.0.9",
"@types/react-autocomplete": "^1.8.9",
"@types/react-color": "^3.0.10",
"@types/react-dom": "^16.9.24",
"@types/react-icon-base": "^2.1.6",
"@types/uuid": "^9.0.7",
"@vitejs/plugin-react": "^4.2.0",
"cors": "^2.8.5",
@@ -1,40 +1,43 @@
import React from 'react'
import PropTypes from 'prop-types'
import React, {SyntheticEvent} from 'react'
import classnames from 'classnames'
import FieldDocLabel from './FieldDocLabel'
import Doc from './Doc'
/** Wrap a component with a label */
export default class Block extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
label: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element,
]),
action: PropTypes.element,
children: PropTypes.node.isRequired,
style: PropTypes.object,
onChange: PropTypes.func,
fieldSpec: PropTypes.object,
wideMode: PropTypes.bool,
error: PropTypes.array,
}
type BlockProps = {
"data-wd-key"?: string
label?: string
action?: React.ReactElement
style?: object
onChange?(...args: unknown[]): unknown
fieldSpec?: object
wideMode?: boolean
error?: unknown[]
};
constructor (props) {
type BlockState = {
showDoc: boolean
};
/** Wrap a component with a label */
export default class Block extends React.Component<BlockProps, BlockState> {
_blockEl: HTMLDivElement | null = null;
constructor (props: BlockProps) {
super(props);
this.state = {
showDoc: false,
}
}
onChange(e) {
onChange(e: React.BaseSyntheticEvent<Event, HTMLInputElement, HTMLInputElement>) {
const value = e.target.value
if (this.props.onChange) {
return this.props.onChange(value === "" ? undefined : value)
}
}
onToggleDoc = (val) => {
onToggleDoc = (val: boolean) => {
this.setState({
showDoc: val
});
@@ -46,10 +49,9 @@ export default class Block extends React.Component {
* causing the picker to reopen. This causes a scenario where the picker can
* never be closed once open.
*/
onLabelClick = (event) => {
onLabelClick = (event: SyntheticEvent<any, any>) => {
const el = event.nativeEvent.target;
const nativeEvent = event.nativeEvent;
const contains = this._blockEl.contains(el);
const contains = this._blockEl?.contains(el);
if (event.nativeEvent.target.nodeName !== "INPUT" && !contains) {
event.stopPropagation();
@@ -58,8 +60,6 @@ export default class Block extends React.Component {
}
render() {
const errors = [].concat(this.props.error || []);
return <label style={this.props.style}
data-wd-key={this.props["data-wd-key"]}
className={classnames({
@@ -1,16 +1,4 @@
import React from 'react'
import PropTypes from 'prop-types'
export default class Doc extends React.Component {
static propTypes = {
fieldSpec: PropTypes.object.isRequired,
}
render () {
const {fieldSpec} = this.props;
const {doc, values} = fieldSpec;
const sdkSupport = fieldSpec['sdk-support'];
const headers = {
js: "JS",
@@ -19,6 +7,27 @@ export default class Doc extends React.Component {
macos: "macOS",
};
type DocProps = {
fieldSpec: {
doc?: string
values?: {
[key: string]: {
doc?: string
}
}
'sdk-support'?: {
[key: string]: typeof headers
}
}
};
export default class Doc extends React.Component<DocProps> {
render () {
const {fieldSpec} = this.props;
const {doc, values} = fieldSpec;
const sdkSupport = fieldSpec['sdk-support'];
const renderValues = (
!!values &&
// HACK: Currently we merge additional values into the style spec, so this is required
@@ -61,10 +70,9 @@ export default class Doc extends React.Component {
return (
<tr key={key}>
<td>{key}</td>
{Object.keys(headers).map(k => {
const value = supportObj[k];
{Object.keys(headers).map((k) => {
if (supportObj.hasOwnProperty(k)) {
return <td key={k}>{supportObj[k]}</td>;
return <td key={k}>{supportObj[k as keyof typeof headers]}</td>;
}
else {
return <td key={k}>no</td>;
@@ -1,26 +1,27 @@
import React from 'react'
import PropTypes from 'prop-types'
import {MdInfoOutline, MdHighlightOff} from 'react-icons/md'
export default class FieldDocLabel extends React.Component {
static propTypes = {
label: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string
]).isRequired,
fieldSpec: PropTypes.object,
onToggleDoc: PropTypes.func,
type FieldDocLabelProps = {
label: object | string | undefined
fieldSpec?: {
doc?: string
}
onToggleDoc?(...args: unknown[]): unknown
};
constructor (props) {
type FieldDocLabelState = {
open: boolean
};
export default class FieldDocLabel extends React.Component<FieldDocLabelProps, FieldDocLabelState> {
constructor (props: FieldDocLabelProps) {
super(props);
this.state = {
open: false,
}
}
onToggleDoc = (open) => {
onToggleDoc = (open: boolean) => {
this.setState({
open,
}, () => {
-20
View File
@@ -1,20 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputEnum from './InputEnum'
import Block from './Block';
import Fieldset from './Fieldset';
export default class FieldEnum extends React.Component {
static propTypes = {
...InputEnum.propTypes,
}
render() {
const {props} = this;
return <Fieldset label={props.label}>
<InputEnum {...props} />
</Fieldset>
}
}
+17
View File
@@ -0,0 +1,17 @@
import React from 'react'
import InputEnum, {InputEnumProps} from './InputEnum'
import Fieldset from './Fieldset';
type FieldEnumProps = InputEnumProps & { label : string };
export default class FieldEnum extends React.Component<FieldEnumProps> {
render() {
const {props} = this;
return <Fieldset label={props.label}>
<InputEnum {...props} />
</Fieldset>
}
}
@@ -1,18 +1,17 @@
import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import Block from './Block'
import InputString from './InputString'
export default class FieldId extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
wdKey: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
error: PropTypes.object,
}
type FieldIdProps = {
value: string
wdKey: string
onChange(...args: unknown[]): unknown
error?: unknown[]
};
export default class FieldId extends React.Component<FieldIdProps> {
render() {
return <Block label={"ID"} fieldSpec={latest.layer.id}
data-wd-key={this.props.wdKey}
-20
View File
@@ -1,20 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import Block from './Block'
import InputString from './InputString'
export default class FieldString extends React.Component {
static propTypes = {
...InputString.propTypes,
name: PropTypes.string,
}
render() {
const {props} = this;
return <Block label={props.label}>
<InputString {...props} />
</Block>
}
}
+18
View File
@@ -0,0 +1,18 @@
import React from 'react'
import Block from './Block'
import InputString, {InputStringProps} from './InputString'
type FieldStringProps = InputStringProps & {
name?: string
label?: string
};
export default class FieldString extends React.Component<FieldStringProps> {
render() {
const {props} = this;
return <Block label={props.label}>
<InputString {...props} />
</Block>
}
}
@@ -1,20 +1,19 @@
import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@maplibre/maplibre-gl-style-spec'
import Block from './Block'
import InputSelect from './InputSelect'
import InputString from './InputString'
export default class FieldType extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
wdKey: PropTypes.string,
onChange: PropTypes.func.isRequired,
error: PropTypes.object,
disabled: PropTypes.bool,
}
type FieldTypeProps = {
value: string
wdKey?: string
onChange(...args: unknown[]): unknown
error?: unknown[] | undefined
disabled?: boolean
};
export default class FieldType extends React.Component<FieldTypeProps> {
static defaultProps = {
disabled: false,
}
-22
View File
@@ -1,22 +0,0 @@
import React, {Fragment} from 'react'
import PropTypes from 'prop-types'
import InputUrl from './InputUrl'
import Block from './Block'
export default class FieldUrl extends React.Component {
static propTypes = {
...InputUrl.propTypes,
}
render () {
const {props} = this;
return (
<Block label={this.props.label}>
<InputUrl {...props} />
</Block>
);
}
}
+22
View File
@@ -0,0 +1,22 @@
import React from 'react'
import InputUrl, {FieldUrlProps as InputUrlProps} from './InputUrl'
import Block from './Block'
type FieldUrlProps = InputUrlProps & {
label: string;
};
export default class FieldUrl extends React.Component<FieldUrlProps> {
render () {
const {props} = this;
return (
<Block label={this.props.label}>
<InputUrl {...props} />
</Block>
);
}
}
@@ -1,13 +1,23 @@
import React from 'react'
import PropTypes from 'prop-types'
import FieldDocLabel from './FieldDocLabel'
import Doc from './Doc'
type FieldsetProps = {
label: string,
fieldSpec?: { doc?: string },
action?: string,
};
type FieldsetState = {
showDoc: boolean
};
let IDX = 0;
export default class Fieldset extends React.Component {
constructor (props) {
export default class Fieldset extends React.Component<FieldsetProps, FieldsetState> {
_labelId: string;
constructor (props: FieldsetProps) {
super(props);
this._labelId = `fieldset_label_${(IDX++)}`;
this.state = {
@@ -15,15 +25,13 @@ export default class Fieldset extends React.Component {
}
}
onToggleDoc = (val) => {
onToggleDoc = (val: boolean) => {
this.setState({
showDoc: val
});
}
render () {
const {props} = this;
return <div className="maputnik-input-block" role="group" aria-labelledby={this._labelId}>
{this.props.fieldSpec &&
<div className="maputnik-input-block-label">
@@ -36,14 +44,14 @@ export default class Fieldset extends React.Component {
}
{!this.props.fieldSpec &&
<div className="maputnik-input-block-label">
{props.label}
{this.props.label}
</div>
}
<div className="maputnik-input-block-action">
{this.props.action}
</div>
<div className="maputnik-input-block-content">
{props.children}
{this.props.children}
</div>
{this.props.fieldSpec &&
<div
@@ -1,14 +1,12 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputButton from './InputButton'
import {MdDelete} from 'react-icons/md'
export default class FilterEditorBlock extends React.Component {
static propTypes = {
onDelete: PropTypes.func.isRequired,
children: PropTypes.element.isRequired,
}
type FilterEditorBlockProps = {
onDelete(...args: unknown[]): unknown
};
export default class FilterEditorBlock extends React.Component<FilterEditorBlockProps> {
render() {
return <div className="maputnik-filter-editor-block">
<div className="maputnik-filter-editor-block-action">
@@ -1,19 +1,18 @@
import React from 'react'
import PropTypes from 'prop-types'
import IconLine from './IconLine.jsx'
import IconFill from './IconFill.jsx'
import IconSymbol from './IconSymbol.jsx'
import IconBackground from './IconBackground.jsx'
import IconCircle from './IconCircle.jsx'
import IconMissing from './IconMissing.jsx'
import IconLine from './IconLine'
import IconFill from './IconFill'
import IconSymbol from './IconSymbol'
import IconBackground from './IconBackground'
import IconCircle from './IconCircle'
import IconMissing from './IconMissing'
export default class IconLayer extends React.Component {
static propTypes = {
type: PropTypes.string.isRequired,
style: PropTypes.object,
}
type IconLayerProps = {
type: string
style?: object
};
export default class IconLayer extends React.Component<IconLayerProps> {
render() {
const iconProps = { style: this.props.style }
switch(this.props.type) {
@@ -1,24 +1,29 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputString from './InputString'
import InputNumber from './InputNumber'
export default class FieldArray extends React.Component {
static propTypes = {
value: PropTypes.array,
type: PropTypes.string,
length: PropTypes.number,
default: PropTypes.array,
onChange: PropTypes.func,
'aria-label': PropTypes.string,
type FieldArrayProps = {
value: string[]
type?: string
length?: number
default?: string[] | number[]
onChange?(...args: unknown[]): unknown
'aria-label'?: string
label?: string
};
type FieldArrayState = {
value: string[] | number[]
initialPropsValue: unknown[]
}
export default class FieldArray extends React.Component<FieldArrayProps, FieldArrayState> {
static defaultProps = {
value: [],
default: [],
}
constructor (props) {
constructor (props: FieldArrayProps) {
super(props);
this.state = {
value: this.props.value.slice(0),
@@ -27,8 +32,8 @@ export default class FieldArray extends React.Component {
};
}
static getDerivedStateFromProps(props, state) {
const value = [];
static getDerivedStateFromProps(props: FieldArrayProps, state: FieldArrayState) {
const value: any[] = [];
const initialPropsValue = state.initialPropsValue.slice(0);
Array(props.length).fill(null).map((_, i) => {
@@ -47,24 +52,24 @@ export default class FieldArray extends React.Component {
};
}
isComplete (value) {
isComplete(value: unknown[]) {
return Array(this.props.length).fill(null).every((_, i) => {
const val = value[i]
return !(val === undefined || val === "");
});
}
changeValue(idx, newValue) {
changeValue(idx: number, newValue: string) {
const value = this.state.value.slice(0);
value[idx] = newValue;
this.setState({
value,
}, () => {
if (this.isComplete(value)) {
if (this.isComplete(value) && this.props.onChange) {
this.props.onChange(value);
}
else {
else if (this.props.onChange){
// Unset until complete
this.props.onChange(undefined);
}
@@ -85,8 +90,8 @@ export default class FieldArray extends React.Component {
if(this.props.type === 'number') {
return <InputNumber
key={i}
default={containsValues ? undefined : this.props.default[i]}
value={value[i]}
default={containsValues || !this.props.default ? undefined : this.props.default[i] as number}
value={value[i] as number}
required={containsValues ? true : false}
onChange={this.changeValue.bind(this, i)}
aria-label={this.props['aria-label'] || this.props.label}
@@ -94,8 +99,8 @@ export default class FieldArray extends React.Component {
} else {
return <InputString
key={i}
default={containsValues ? undefined : this.props.default[i]}
value={value[i]}
default={containsValues || !this.props.default ? undefined : this.props.default[i] as string}
value={value[i] as string}
required={containsValues ? true : false}
onChange={this.changeValue.bind(this, i)}
aria-label={this.props['aria-label'] || this.props.label}
@@ -1,24 +1,25 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import Autocomplete from 'react-autocomplete'
const MAX_HEIGHT = 140;
export default class InputAutocomplete extends React.Component {
static propTypes = {
value: PropTypes.string,
options: PropTypes.array,
onChange: PropTypes.func,
keepMenuWithinWindowBounds: PropTypes.bool,
'aria-label': PropTypes.string,
}
type InputAutocompleteProps = {
value?: string
options: any[]
onChange(...args: unknown[]): unknown
keepMenuWithinWindowBounds?: boolean
'aria-label'?: string
};
export default class InputAutocomplete extends React.Component<InputAutocompleteProps> {
state = {
maxHeight: MAX_HEIGHT
}
autocompleteMenuEl: HTMLDivElement | null = null;
static defaultProps = {
onChange: () => {},
options: [],
@@ -26,7 +27,7 @@ export default class InputAutocomplete extends React.Component {
calcMaxHeight() {
if(this.props.keepMenuWithinWindowBounds) {
const maxHeight = window.innerHeight - this.autocompleteMenuEl.getBoundingClientRect().top;
const maxHeight = window.innerHeight - this.autocompleteMenuEl!.getBoundingClientRect().top;
const limitedMaxHeight = Math.min(maxHeight, MAX_HEIGHT);
if(limitedMaxHeight != this.state.maxHeight) {
@@ -45,7 +46,7 @@ export default class InputAutocomplete extends React.Component {
this.calcMaxHeight();
}
onChange (v) {
onChange(v: string) {
this.props.onChange(v === "" ? undefined : v);
}
@@ -64,7 +65,7 @@ export default class InputAutocomplete extends React.Component {
}}
wrapperProps={{
className: "maputnik-autocomplete",
style: null
style: {}
}}
inputProps={{
'aria-label': this.props['aria-label'],
@@ -75,11 +76,12 @@ export default class InputAutocomplete extends React.Component {
items={this.props.options}
getItemValue={(item) => item[0]}
onSelect={v => this.onChange(v)}
onChange={(e, v) => this.onChange(v)}
onChange={(_e, v) => this.onChange(v)}
shouldItemRender={(item, value="") => {
if (typeof(value) === "string") {
return item[0].toLowerCase().indexOf(value.toLowerCase()) > -1
}
return false
}}
renderItem={(item, isHighlighted) => (
<div
@@ -1,21 +1,20 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
export default class InputButton extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
"aria-label": PropTypes.string,
onClick: PropTypes.func,
style: PropTypes.object,
className: PropTypes.string,
children: PropTypes.node,
disabled: PropTypes.bool,
type: PropTypes.string,
id: PropTypes.string,
title: PropTypes.string,
}
type InputButtonProps = {
"data-wd-key"?: string
"aria-label"?: string
onClick?(...args: unknown[]): unknown
style?: object
className?: string
children?: React.ReactNode
disabled?: boolean
type?: typeof HTMLButtonElement.prototype.type
id?: string
title?: string
};
export default class InputButton extends React.Component<InputButtonProps> {
render() {
return <button
id={this.props.id}
@@ -32,4 +31,3 @@ export default class InputButton extends React.Component {
</button>
}
}
@@ -1,13 +1,12 @@
import React from 'react'
import PropTypes from 'prop-types'
export default class InputCheckbox extends React.Component {
static propTypes = {
value: PropTypes.bool,
style: PropTypes.object,
onChange: PropTypes.func,
}
type InputCheckboxProps = {
value?: boolean
style?: object
onChange(...args: unknown[]): unknown
};
export default class InputCheckbox extends React.Component<InputCheckboxProps> {
static defaultProps = {
value: false,
}
@@ -36,4 +35,3 @@ export default class InputCheckbox extends React.Component {
</div>
}
}
@@ -1,36 +1,37 @@
import React from 'react'
import Color from 'color'
import ChromePicker from 'react-color/lib/components/chrome/Chrome'
import PropTypes from 'prop-types'
import {ColorResult} from 'react-color';
import lodash from 'lodash';
function formatColor(color) {
function formatColor(color: ColorResult): string {
const rgb = color.rgb
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`
}
/*** Number fields with support for min, max and units and documentation*/
export default class InputColor extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
name: PropTypes.string,
value: PropTypes.string,
doc: PropTypes.string,
style: PropTypes.object,
default: PropTypes.string,
'aria-label': PropTypes.string,
}
type InputColorProps = {
onChange(...args: unknown[]): unknown
name?: string
value?: string
doc?: string
style?: object
default?: string
'aria-label'?: string
};
/*** Number fields with support for min, max and units and documentation*/
export default class InputColor extends React.Component<InputColorProps> {
state = {
pickerOpened: false
}
colorInput: HTMLInputElement | null = null;
constructor () {
super();
constructor (props: InputColorProps) {
super(props);
this.onChangeNoCheck = lodash.throttle(this.onChangeNoCheck, 1000/30);
}
onChangeNoCheck (v) {
onChangeNoCheck(v: string) {
this.props.onChange(v);
}
@@ -68,19 +69,19 @@ export default class InputColor extends React.Component {
}
}
onChange (v) {
onChange (v: string) {
this.props.onChange(v === "" ? undefined : v);
}
render() {
const offset = this.calcPickerOffset()
var currentColor = this.color.object()
currentColor = {
const currentColor = this.color.object();
const currentChromeColor = {
r: currentColor.r,
g: currentColor.g,
b: currentColor.b,
// Rename alpha -> a for ChromePicker
a: currentColor.alpha
a: currentColor.alpha!
}
const picker = <div
@@ -92,7 +93,7 @@ export default class InputColor extends React.Component {
top: offset.top,
}}>
<ChromePicker
color={currentColor}
color={currentChromeColor}
onChange={c => this.onChangeNoCheck(formatColor(c))}
/>
<div
@@ -1,10 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputSelect from './InputSelect'
import InputMultiInput from './InputMultiInput'
function optionsLabelLength(options) {
function optionsLabelLength(options: any[]) {
let sum = 0;
options.forEach(([_, label]) => {
sum += label.length
@@ -13,18 +12,20 @@ function optionsLabelLength(options) {
}
export default class InputEnum extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
value: PropTypes.string,
style: PropTypes.object,
default: PropTypes.string,
name: PropTypes.string,
onChange: PropTypes.func,
options: PropTypes.array,
'aria-label': PropTypes.string,
}
export type InputEnumProps = {
"data-wd-key"?: string
value?: string
style?: object
default?: string
name: string
onChange(...args: unknown[]): unknown
options: any[]
'aria-label'?: string
label?: string
};
export default class InputEnum extends React.Component<InputEnumProps> {
render() {
const {options, value, onChange, name, label} = this.props;
@@ -32,14 +33,14 @@ export default class InputEnum extends React.Component {
return <InputMultiInput
name={name}
options={options}
value={value || this.props.default}
value={(value || this.props.default)!}
onChange={onChange}
aria-label={this.props['aria-label'] || label}
/>
} else {
return <InputSelect
options={options}
value={value || this.props.default}
value={(value || this.props.default)!}
onChange={onChange}
aria-label={this.props['aria-label'] || label}
/>
@@ -1,17 +1,17 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputAutocomplete from './InputAutocomplete'
export default class FieldFont extends React.Component {
static propTypes = {
value: PropTypes.array,
default: PropTypes.array,
fonts: PropTypes.array,
style: PropTypes.object,
onChange: PropTypes.func.isRequired,
'aria-label': PropTypes.string,
}
type FieldFontProps = {
name: string
value?: string[]
default?: string[]
fonts?: unknown[]
style?: object
onChange(...args: unknown[]): unknown
'aria-label'?: string
};
export default class FieldFont extends React.Component<FieldFontProps> {
static defaultProps = {
fonts: []
}
@@ -28,7 +28,7 @@ export default class FieldFont extends React.Component {
}
}
changeFont(idx, newValue) {
changeFont(idx: number, newValue: string) {
const changedValues = this.values.slice(0)
changedValues[idx] = newValue
const filteredValues = changedValues
@@ -46,7 +46,7 @@ export default class FieldFont extends React.Component {
<InputAutocomplete
aria-label={this.props['aria-label'] || this.props.name}
value={value}
options={this.props.fonts.map(f => [f, f])}
options={this.props.fonts?.map(f => [f, f])}
onChange={this.changeFont.bind(this, i)}
/>
</li>
@@ -1,16 +1,15 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import InputButton from './InputButton'
export default class InputMultiInput extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
options: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
}
type InputMultiInputProps = {
name: string
value: string
options: any[]
onChange(...args: unknown[]): unknown
'aria-label'?: string
};
export default class InputMultiInput extends React.Component<InputMultiInputProps> {
render() {
let options = this.props.options
if(options.length > 0 && !Array.isArray(options[0])) {
@@ -25,7 +24,7 @@ export default class InputMultiInput extends React.Component {
>
<input type="radio"
name={this.props.name}
onChange={e => this.props.onChange(val)}
onChange={_e => this.props.onChange(val)}
value={val}
checked={val === selectedValue}
/>
@@ -1,27 +1,35 @@
import React from 'react'
import PropTypes from 'prop-types'
import React, { BaseSyntheticEvent } from 'react'
let IDX = 0;
export default class InputNumber extends React.Component {
static propTypes = {
value: PropTypes.number,
default: PropTypes.number,
min: PropTypes.number,
max: PropTypes.number,
onChange: PropTypes.func,
allowRange: PropTypes.bool,
rangeStep: PropTypes.number,
wdKey: PropTypes.string,
required: PropTypes.bool,
"aria-label": PropTypes.string,
type InputNumberProps = {
value?: number
default?: number
min?: number
max?: number
onChange?(...args: unknown[]): unknown
allowRange?: boolean
rangeStep?: number
wdKey?: string
required?: boolean
"aria-label"?: string
};
type InputNumberState = {
uuid: number
editing: boolean
editingRange?: boolean
value?: number
dirtyValue?: number
}
export default class InputNumber extends React.Component<InputNumberProps, InputNumberState> {
static defaultProps = {
rangeStep: 1
}
_keyboardEvent: boolean = false;
constructor(props) {
constructor(props: InputNumberProps) {
super(props)
this.state = {
uuid: IDX++,
@@ -31,7 +39,7 @@ export default class InputNumber extends React.Component {
}
}
static getDerivedStateFromProps(props, state) {
static getDerivedStateFromProps(props: InputNumberProps, state: InputNumberState) {
if (!state.editing && props.value !== state.value) {
return {
value: props.value,
@@ -41,16 +49,15 @@ export default class InputNumber extends React.Component {
return null;
}
changeValue(newValue) {
changeValue(newValue: number | string | undefined) {
const value = (newValue === "" || newValue === undefined) ?
undefined :
parseFloat(newValue);
undefined : +newValue;
const hasChanged = this.props.value !== value;
if(this.isValid(value) && hasChanged) {
this.props.onChange(value)
if (this.props.onChange) this.props.onChange(value)
this.setState({
value: newValue,
value: value,
});
}
else if (!this.isValid(value) && hasChanged) {
@@ -60,25 +67,25 @@ export default class InputNumber extends React.Component {
}
this.setState({
dirtyValue: newValue === "" ? undefined : newValue,
dirtyValue: newValue === "" ? undefined : value,
})
}
isValid(v) {
isValid(v: number | string | undefined) {
if (v === undefined) {
return true;
}
const value = parseFloat(v)
const value = +v;
if(isNaN(value)) {
return false
}
if(!isNaN(this.props.min) && value < this.props.min) {
if(!isNaN(this.props.min!) && value < this.props.min!) {
return false
}
if(!isNaN(this.props.max) && value > this.props.max) {
if(!isNaN(this.props.max!) && value > this.props.max!) {
return false
}
@@ -88,7 +95,7 @@ export default class InputNumber extends React.Component {
resetValue = () => {
this.setState({editing: false});
// Reset explicitly to default value if value has been cleared
if(this.state.value === "") {
if(!this.state.value) {
return;
}
@@ -104,8 +111,8 @@ export default class InputNumber extends React.Component {
}
}
onChangeRange = (e) => {
let value = parseFloat(e.target.value, 10);
onChangeRange = (e: BaseSyntheticEvent<Event, HTMLInputElement, HTMLInputElement>) => {
let value = parseFloat(e.target.value);
const step = this.props.rangeStep;
let dirtyValue = value;
@@ -119,11 +126,11 @@ export default class InputNumber extends React.Component {
// for example we might go from 13 to 13.23, however because we know
// that came from a keyboard event we always want to increase by a
// single step value.
if (value < this.state.dirtyValue) {
value = this.state.value - step;
if (value < this.state.dirtyValue!) {
value = this.state.value! - step;
}
else {
value = this.state.value + step
value = this.state.value! + step
}
dirtyValue = value;
}
@@ -140,10 +147,10 @@ export default class InputNumber extends React.Component {
this._keyboardEvent = false;
// Clamp between min/max
value = Math.max(this.props.min, Math.min(this.props.max, value));
value = Math.max(this.props.min!, Math.min(this.props.max!, value));
this.setState({value, dirtyValue});
this.props.onChange(value);
if (this.props.onChange) this.props.onChange(value);
}
render() {
@@ -196,15 +203,15 @@ export default class InputNumber extends React.Component {
type="text"
spellCheck="false"
className="maputnik-number"
placeholder={this.props.default}
placeholder={this.props.default?.toString()}
value={inputValue === undefined ? "" : inputValue}
onFocus={e => {
onFocus={_e => {
this.setState({editing: true});
}}
onChange={e => {
this.changeValue(e.target.value);
}}
onBlur={e => {
onBlur={_e => {
this.setState({editing: false});
this.resetValue()
}}
@@ -218,7 +225,7 @@ export default class InputNumber extends React.Component {
aria-label={this.props['aria-label']}
spellCheck="false"
className="maputnik-number"
placeholder={this.props.default}
placeholder={this.props.default?.toString()}
value={value === undefined ? "" : value}
onChange={e => this.changeValue(e.target.value)}
onFocus={() => {
@@ -1,22 +1,20 @@
import React from 'react'
import PropTypes from 'prop-types'
export default class InputSelect extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
"data-wd-key": PropTypes.string,
options: PropTypes.array.isRequired,
style: PropTypes.object,
onChange: PropTypes.func.isRequired,
title: PropTypes.string,
'aria-label': PropTypes.string,
}
type InputSelectProps = {
value: string
"data-wd-key"?: string
options: [string, any][] | string[]
style?: object
onChange(...args: unknown[]): unknown
title?: string
'aria-label'?: string
};
export default class InputSelect extends React.Component<InputSelectProps> {
render() {
let options = this.props.options
let options = this.props.options;
if(options.length > 0 && !Array.isArray(options[0])) {
options = options.map(v => [v, v])
options = options.map((v) => [v, v]) as [string, any][];
}
return <select
@@ -1,26 +1,30 @@
import React from 'react'
import PropTypes from 'prop-types'
export default class InputString extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
value: PropTypes.string,
style: PropTypes.object,
default: PropTypes.string,
onChange: PropTypes.func,
onInput: PropTypes.func,
multi: PropTypes.bool,
required: PropTypes.bool,
disabled: PropTypes.bool,
spellCheck: PropTypes.bool,
'aria-label': PropTypes.string,
export type InputStringProps = {
"data-wd-key"?: string
value?: string
style?: object
default?: string
onChange?(...args: unknown[]): unknown
onInput(...args: unknown[]): unknown
multi?: boolean
required?: boolean
disabled?: boolean
spellCheck?: boolean
'aria-label'?: string
};
type InputStringState = {
editing: boolean
value?: string
}
export default class InputString extends React.Component<InputStringProps, InputStringState> {
static defaultProps = {
onInput: () => {},
}
constructor(props) {
constructor(props: InputStringProps) {
super(props)
this.state = {
editing: false,
@@ -28,7 +32,7 @@ export default class InputString extends React.Component {
}
}
static getDerivedStateFromProps(props, state) {
static getDerivedStateFromProps(props: InputStringProps, state: InputStringState) {
if (!state.editing) {
return {
value: props.value
@@ -68,7 +72,7 @@ export default class InputString extends React.Component {
style: this.props.style,
value: this.state.value === undefined ? "" : this.state.value,
placeholder: this.props.default,
onChange: e => {
onChange: (e: React.BaseSyntheticEvent<Event, HTMLInputElement, HTMLInputElement>) => {
this.setState({
editing: true,
value: e.target.value
@@ -79,11 +83,11 @@ export default class InputString extends React.Component {
onBlur: () => {
if(this.state.value!==this.props.value) {
this.setState({editing: false});
this.props.onChange(this.state.value);
if (this.props.onChange) this.props.onChange(this.state.value);
}
},
onKeyDown: (e) => {
if (e.keyCode === 13) {
if (e.keyCode === 13 && this.props.onChange) {
this.props.onChange(this.state.value);
}
},
@@ -1,16 +1,15 @@
import React, {Fragment} from 'react'
import PropTypes from 'prop-types'
import React from 'react'
import InputString from './InputString'
import SmallError from './SmallError'
function validate (url) {
function validate(url: string) {
if (url === "") {
return;
}
let error;
const getProtocol = (url) => {
const getProtocol = (url: string) => {
try {
const urlObj = new URL(url);
return urlObj.protocol;
@@ -48,38 +47,42 @@ function validate (url) {
return error;
}
export default class FieldUrl extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
value: PropTypes.string,
style: PropTypes.object,
default: PropTypes.string,
onChange: PropTypes.func,
onInput: PropTypes.func,
multi: PropTypes.bool,
required: PropTypes.bool,
'aria-label': PropTypes.string,
export type FieldUrlProps = {
"data-wd-key"?: string
value: string
style?: object
default?: string
onChange(...args: unknown[]): unknown
onInput(...args: unknown[]): unknown
multi?: boolean
required?: boolean
'aria-label'?: string
};
type FieldUrlState = {
error?: React.ReactNode
}
export default class FieldUrl extends React.Component<FieldUrlProps, FieldUrlState> {
static defaultProps = {
onInput: () => {},
}
constructor (props) {
constructor (props: FieldUrlProps) {
super(props);
this.state = {
error: validate(props.value)
};
}
onInput = (url) => {
onInput = (url: string) => {
this.setState({
error: validate(url)
});
this.props.onInput(url);
}
onChange = (url) => {
onChange = (url: string) => {
this.setState({
error: validate(url)
});
@@ -1,22 +1,21 @@
import React from 'react'
import PropTypes from 'prop-types'
import {MdClose} from 'react-icons/md'
import AriaModal from 'react-aria-modal'
import classnames from 'classnames';
export default class Modal extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
isOpen: PropTypes.bool.isRequired,
title: PropTypes.string.isRequired,
onOpenToggle: PropTypes.func.isRequired,
children: PropTypes.node,
underlayClickExits: PropTypes.bool,
underlayProps: PropTypes.object,
className: PropTypes.string,
}
type ModalProps = {
"data-wd-key"?: string
isOpen: boolean
title: string
onOpenToggle(...args: unknown[]): unknown
underlayClickExits?: boolean
underlayProps?: any
className?: string
};
export default class Modal extends React.Component<ModalProps> {
static defaultProps = {
underlayClickExits: true
}
@@ -24,7 +23,7 @@ export default class Modal extends React.Component {
// See <https://github.com/maputnik/editor/issues/416>
onClose = () => {
if (document.activeElement) {
document.activeElement.blur();
(document.activeElement as HTMLElement).blur();
}
setTimeout(() => {
@@ -37,6 +36,7 @@ export default class Modal extends React.Component {
return <AriaModal
titleText={this.props.title}
underlayClickExits={this.props.underlayClickExits}
// @ts-ignore
underlayProps={this.props.underlayProps}
data-wd-key={this.props["data-wd-key"]}
verticallyCenter={true}
-15
View File
@@ -1,15 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
export default class ScrollContainer extends React.Component {
static propTypes = {
children: PropTypes.node
}
render() {
return <div className="maputnik-scroll-container">
{this.props.children}
</div>
}
}
+14
View File
@@ -0,0 +1,14 @@
import React from 'react'
type ScrollContainerProps = {
children?: React.ReactNode
};
export default class ScrollContainer extends React.Component<ScrollContainerProps> {
render() {
return <div className="maputnik-scroll-container">
{this.props.children}
</div>
}
}
@@ -1,13 +1,13 @@
import React from 'react'
import PropTypes from 'prop-types'
import './SmallError.scss';
export default class SmallError extends React.Component {
static propTypes = {
children: PropTypes.node,
}
type SmallErrorProps = {
children?: React.ReactNode
};
export default class SmallError extends React.Component<SmallErrorProps> {
render () {
return (
<div className="SmallError">
@@ -16,4 +16,3 @@ export default class SmallError extends React.Component {
);
}
}