Migrate more components

This commit is contained in:
HarelM
2023-12-21 14:53:21 +02:00
parent 732581c39e
commit c633368a9a
16 changed files with 187 additions and 187 deletions
+10
View File
@@ -69,6 +69,7 @@
"@storybook/theming": "^7.6.5", "@storybook/theming": "^7.6.5",
"@types/color": "^3.0.6", "@types/color": "^3.0.6",
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/lodash.capitalize": "^4.2.9",
"@types/lodash.isequal": "^4.5.8", "@types/lodash.isequal": "^4.5.8",
"@types/lodash.throttle": "^4.1.9", "@types/lodash.throttle": "^4.1.9",
"@types/react": "^16.14.52", "@types/react": "^16.14.52",
@@ -4732,6 +4733,15 @@
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
"dev": true "dev": true
}, },
"node_modules/@types/lodash.capitalize": {
"version": "4.2.9",
"resolved": "https://registry.npmjs.org/@types/lodash.capitalize/-/lodash.capitalize-4.2.9.tgz",
"integrity": "sha512-SV1dav/WbuI816SVig4trFz8ID/m5maVzC8I/E/DejPvmlXvIhw7Y0GWxJ03UhU6qaZOj6qQnR1xxC0mP7ZXoQ==",
"dev": true,
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/lodash.isequal": { "node_modules/@types/lodash.isequal": {
"version": "4.5.8", "version": "4.5.8",
"resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz", "resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz",
+1
View File
@@ -98,6 +98,7 @@
"@storybook/theming": "^7.6.5", "@storybook/theming": "^7.6.5",
"@types/color": "^3.0.6", "@types/color": "^3.0.6",
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
"@types/lodash.capitalize": "^4.2.9",
"@types/lodash.isequal": "^4.5.8", "@types/lodash.isequal": "^4.5.8",
"@types/lodash.throttle": "^4.1.9", "@types/lodash.throttle": "^4.1.9",
"@types/react": "^16.14.52", "@types/react": "^16.14.52",
+2 -2
View File
@@ -1,11 +1,11 @@
import React from 'react' import React, { ReactElement } from 'react'
import FieldDocLabel from './FieldDocLabel' import FieldDocLabel from './FieldDocLabel'
import Doc from './Doc' import Doc from './Doc'
type FieldsetProps = { type FieldsetProps = {
label: string, label: string,
fieldSpec?: { doc?: string }, fieldSpec?: { doc?: string },
action?: string, action?: ReactElement,
}; };
type FieldsetState = { type FieldsetState = {
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import InputString from './InputString' import InputString from './InputString'
import InputNumber from './InputNumber' import InputNumber from './InputNumber'
type FieldArrayProps = { export type FieldArrayProps = {
value: string[] value: string[]
type?: string type?: string
length?: number length?: number
+1 -1
View File
@@ -5,7 +5,7 @@ import Autocomplete from 'react-autocomplete'
const MAX_HEIGHT = 140; const MAX_HEIGHT = 140;
type InputAutocompleteProps = { export type InputAutocompleteProps = {
value?: string value?: string
options: any[] options: any[]
onChange(...args: unknown[]): unknown onChange(...args: unknown[]): unknown
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
type InputCheckboxProps = { export type InputCheckboxProps = {
value?: boolean value?: boolean
style?: object style?: object
onChange(...args: unknown[]): unknown onChange(...args: unknown[]): unknown
+1 -1
View File
@@ -9,7 +9,7 @@ function formatColor(color: ColorResult): string {
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})` return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`
} }
type InputColorProps = { export type InputColorProps = {
onChange(...args: unknown[]): unknown onChange(...args: unknown[]): unknown
name?: string name?: string
value?: string value?: string
@@ -1,30 +1,34 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import capitalize from 'lodash.capitalize'
import {MdDelete} from 'react-icons/md'
import InputString from './InputString' import InputString from './InputString'
import InputNumber from './InputNumber' import InputNumber from './InputNumber'
import InputButton from './InputButton' import InputButton from './InputButton'
import {MdDelete} from 'react-icons/md'
import FieldDocLabel from './FieldDocLabel' import FieldDocLabel from './FieldDocLabel'
import InputEnum from './InputEnum' import InputEnum from './InputEnum'
import capitalize from 'lodash.capitalize'
import InputUrl from './InputUrl' import InputUrl from './InputUrl'
export default class FieldDynamicArray extends React.Component { export type FieldDynamicArrayProps = {
static propTypes = { value?: (string | number)[]
value: PropTypes.array, type?: 'url' | 'number' | 'enum'
type: PropTypes.string, default?: (string | number)[]
default: PropTypes.array, onChange?(...args: unknown[]): unknown
onChange: PropTypes.func, style?: object
style: PropTypes.object, fieldSpec?: {
fieldSpec: PropTypes.object, values?: any
'aria-label': PropTypes.string,
} }
'aria-label'?: string
label: string
};
changeValue(idx, newValue) {
export default class FieldDynamicArray extends React.Component<FieldDynamicArrayProps> {
changeValue(idx: number, newValue: string | number) {
const values = this.values.slice(0) const values = this.values.slice(0)
values[idx] = newValue values[idx] = newValue
this.props.onChange(values) if (this.props.onChange) this.props.onChange(values)
} }
get values() { get values() {
@@ -41,20 +45,20 @@ export default class FieldDynamicArray extends React.Component {
} }
else if (this.props.type === 'enum') { else if (this.props.type === 'enum') {
const {fieldSpec} = this.props; const {fieldSpec} = this.props;
const defaultValue = Object.keys(fieldSpec.values)[0]; const defaultValue = Object.keys(fieldSpec!.values)[0];
values.push(defaultValue); values.push(defaultValue);
} else { } else {
values.push("") values.push("")
} }
this.props.onChange(values) if (this.props.onChange) this.props.onChange(values)
} }
deleteValue(valueIdx) { deleteValue(valueIdx: number) {
const values = this.values.slice(0) const values = this.values.slice(0)
values.splice(valueIdx, 1) values.splice(valueIdx, 1)
this.props.onChange(values.length > 0 ? values : undefined); if (this.props.onChange) this.props.onChange(values.length > 0 ? values : undefined);
} }
render() { render() {
@@ -63,30 +67,30 @@ export default class FieldDynamicArray extends React.Component {
let input; let input;
if(this.props.type === 'url') { if(this.props.type === 'url') {
input = <InputUrl input = <InputUrl
value={v} value={v as string}
onChange={this.changeValue.bind(this, i)} onChange={this.changeValue.bind(this, i)}
aria-label={this.props['aria-label'] || this.props.label} aria-label={this.props['aria-label'] || this.props.label}
/> />
} }
else if (this.props.type === 'number') { else if (this.props.type === 'number') {
input = <InputNumber input = <InputNumber
value={v} value={v as number}
onChange={this.changeValue.bind(this, i)} onChange={this.changeValue.bind(this, i)}
aria-label={this.props['aria-label'] || this.props.label} aria-label={this.props['aria-label'] || this.props.label}
/> />
} }
else if (this.props.type === 'enum') { else if (this.props.type === 'enum') {
const options = Object.keys(this.props.fieldSpec.values).map(v => [v, capitalize(v)]); const options = Object.keys(this.props.fieldSpec?.values).map(v => [v, capitalize(v)]);
input = <InputEnum input = <InputEnum
options={options} options={options}
value={v} value={v as string}
onChange={this.changeValue.bind(this, i)} onChange={this.changeValue.bind(this, i)}
aria-label={this.props['aria-label'] || this.props.label} aria-label={this.props['aria-label'] || this.props.label}
/> />
} }
else { else {
input = <InputString input = <InputString
value={v} value={v as string}
onChange={this.changeValue.bind(this, i)} onChange={this.changeValue.bind(this, i)}
aria-label={this.props['aria-label'] || this.props.label} aria-label={this.props['aria-label'] || this.props.label}
/> />
@@ -120,11 +124,11 @@ export default class FieldDynamicArray extends React.Component {
} }
} }
class DeleteValueInputButton extends React.Component { type DeleteValueInputButtonProps = {
static propTypes = { onClick?(...args: unknown[]): unknown
onClick: PropTypes.func, };
}
class DeleteValueInputButton extends React.Component<DeleteValueInputButtonProps> {
render() { render() {
return <InputButton return <InputButton
className="maputnik-delete-stop" className="maputnik-delete-stop"
@@ -133,7 +137,7 @@ class DeleteValueInputButton extends React.Component {
> >
<FieldDocLabel <FieldDocLabel
label={<MdDelete />} label={<MdDelete />}
doc={"Remove array item."} fieldSpec={{doc:" Remove array item."}}
/> />
</InputButton> </InputButton>
} }
+1 -1
View File
@@ -17,7 +17,7 @@ export type InputEnumProps = {
value?: string value?: string
style?: object style?: object
default?: string default?: string
name: string name?: string
onChange(...args: unknown[]): unknown onChange(...args: unknown[]): unknown
options: any[] options: any[]
'aria-label'?: string 'aria-label'?: string
+1 -1
View File
@@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import InputAutocomplete from './InputAutocomplete' import InputAutocomplete from './InputAutocomplete'
type FieldFontProps = { export type FieldFontProps = {
name: string name: string
value?: string[] value?: string[]
default?: string[] default?: string[]
+1 -1
View File
@@ -2,7 +2,7 @@ import React from 'react'
import classnames from 'classnames' import classnames from 'classnames'
type InputMultiInputProps = { type InputMultiInputProps = {
name: string name?: string
value: string value: string
options: any[] options: any[]
onChange(...args: unknown[]): unknown onChange(...args: unknown[]): unknown
+1 -1
View File
@@ -2,7 +2,7 @@ import React, { BaseSyntheticEvent } from 'react'
let IDX = 0; let IDX = 0;
type InputNumberProps = { export type InputNumberProps = {
value?: number value?: number
default?: number default?: number
min?: number min?: number
-139
View File
@@ -1,139 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputColor from './InputColor'
import InputNumber from './InputNumber'
import InputCheckbox from './InputCheckbox'
import InputString from './InputString'
import InputSelect from './InputSelect'
import InputMultiInput from './InputMultiInput'
import InputArray from './InputArray'
import InputDynamicArray from './InputDynamicArray'
import InputFont from './InputFont'
import InputAutocomplete from './InputAutocomplete'
import InputEnum from './InputEnum'
import capitalize from 'lodash.capitalize'
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
function labelFromFieldName(fieldName) {
let label = fieldName.split('-').slice(1).join(' ')
if(label.length > 0) {
label = label.charAt(0).toUpperCase() + label.slice(1);
}
return label
}
function optionsLabelLength(options) {
let sum = 0;
options.forEach(([_, label]) => {
sum += label.length
})
return sum
}
/** Display any field from the Maplibre GL style spec and
* choose the correct field component based on the @{fieldSpec}
* to display @{value}. */
export default class SpecField extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
fieldName: PropTypes.string.isRequired,
fieldSpec: PropTypes.object.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.array,
PropTypes.bool
]),
/** Override the style of the field */
style: PropTypes.object,
'aria-label': PropTypes.string,
}
render() {
const commonProps = {
error: this.props.error,
fieldSpec: this.props.fieldSpec,
label: this.props.label,
action: this.props.action,
style: this.props.style,
value: this.props.value,
default: this.props.fieldSpec.default,
name: this.props.fieldName,
onChange: newValue => this.props.onChange(this.props.fieldName, newValue),
'aria-label': this.props['aria-label'],
}
function childNodes() {
switch(this.props.fieldSpec.type) {
case 'number': return (
<InputNumber
{...commonProps}
min={this.props.fieldSpec.minimum}
max={this.props.fieldSpec.maximum}
/>
)
case 'enum':
const options = Object.keys(this.props.fieldSpec.values).map(v => [v, capitalize(v)])
return <InputEnum
{...commonProps}
options={options}
/>
case 'resolvedImage':
case 'formatted':
case 'string':
if (iconProperties.indexOf(this.props.fieldName) >= 0) {
const options = this.props.fieldSpec.values || [];
return <InputAutocomplete
{...commonProps}
options={options.map(f => [f, f])}
/>
} else {
return <InputString
{...commonProps}
/>
}
case 'color': return (
<InputColor
{...commonProps}
/>
)
case 'boolean': return (
<InputCheckbox
{...commonProps}
/>
)
case 'array':
if(this.props.fieldName === 'text-font') {
return <InputFont
{...commonProps}
fonts={this.props.fieldSpec.values}
/>
} else {
if (this.props.fieldSpec.length) {
return <InputArray
{...commonProps}
type={this.props.fieldSpec.value}
length={this.props.fieldSpec.length}
/>
} else {
return <InputDynamicArray
{...commonProps}
fieldSpec={this.props.fieldSpec}
type={this.props.fieldSpec.value}
/>
}
}
default: return null
}
}
return (
<div data-wd-key={"spec-field:"+this.props.fieldName}>
{childNodes.call(this)}
</div>
);
}
}
+126
View File
@@ -0,0 +1,126 @@
import React, { ReactElement } from 'react'
import InputColor, { InputColorProps } from './InputColor'
import InputNumber, { InputNumberProps } from './InputNumber'
import InputCheckbox, { InputCheckboxProps } from './InputCheckbox'
import InputString, { InputStringProps } from './InputString'
import InputArray, { FieldArrayProps } from './InputArray'
import InputDynamicArray, { FieldDynamicArrayProps } from './InputDynamicArray'
import InputFont, { FieldFontProps } from './InputFont'
import InputAutocomplete, { InputAutocompleteProps } from './InputAutocomplete'
import InputEnum, { InputEnumProps } from './InputEnum'
import capitalize from 'lodash.capitalize'
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
export type SpecFieldProps = {
onChange(...args: unknown[]): unknown
fieldName: string
fieldSpec: {
default?: unknown
type: 'number' | 'enum' | 'resolvedImage' | 'formatted' | 'string' | 'color' | 'boolean' | 'array'
minimum?: number
maximum?: number
values?: unknown[]
length?: number
value?: string
}
value?: string | number | unknown[] | boolean
/** Override the style of the field */
style?: object
'aria-label'?: string
error: unknown[]
label: string
action: ReactElement
};
/** Display any field from the Maplibre GL style spec and
* choose the correct field component based on the @{fieldSpec}
* to display @{value}. */
export default class SpecField extends React.Component<SpecFieldProps> {
childNodes() {
const commonProps = {
error: this.props.error,
fieldSpec: this.props.fieldSpec,
label: this.props.label,
action: this.props.action,
style: this.props.style,
value: this.props.value,
default: this.props.fieldSpec.default,
name: this.props.fieldName,
onChange: (newValue: string) => this.props.onChange(this.props.fieldName, newValue),
'aria-label': this.props['aria-label'],
}
switch(this.props.fieldSpec.type) {
case 'number': return (
<InputNumber
{...commonProps as InputNumberProps}
min={this.props.fieldSpec.minimum}
max={this.props.fieldSpec.maximum}
/>
)
case 'enum':
const options = Object.keys(this.props.fieldSpec.values || []).map(v => [v, capitalize(v)])
return <InputEnum
{...commonProps as Omit<InputEnumProps, "options">}
options={options}
/>
case 'resolvedImage':
case 'formatted':
case 'string':
if (iconProperties.indexOf(this.props.fieldName) >= 0) {
const options = this.props.fieldSpec.values || [];
return <InputAutocomplete
{...commonProps as Omit<InputAutocompleteProps, "options">}
options={options.map(f => [f, f])}
/>
} else {
return <InputString
{...commonProps as InputStringProps}
/>
}
case 'color': return (
<InputColor
{...commonProps as InputColorProps}
/>
)
case 'boolean': return (
<InputCheckbox
{...commonProps as InputCheckboxProps}
/>
)
case 'array':
if(this.props.fieldName === 'text-font') {
return <InputFont
{...commonProps as FieldFontProps}
fonts={this.props.fieldSpec.values}
/>
} else {
if (this.props.fieldSpec.length) {
return <InputArray
{...commonProps as FieldArrayProps}
type={this.props.fieldSpec.value}
length={this.props.fieldSpec.length}
/>
} else {
return <InputDynamicArray
{...commonProps as FieldDynamicArrayProps}
fieldSpec={this.props.fieldSpec}
type={this.props.fieldSpec.value as FieldDynamicArrayProps['type']}
/>
}
}
default: return null
}
}
render() {
return (
<div data-wd-key={"spec-field:"+this.props.fieldName}>
{this.childNodes()}
</div>
);
}
}
+2 -2
View File
@@ -6,7 +6,7 @@ export type InputStringProps = {
style?: object style?: object
default?: string default?: string
onChange?(...args: unknown[]): unknown onChange?(...args: unknown[]): unknown
onInput(...args: unknown[]): unknown onInput?(...args: unknown[]): unknown
multi?: boolean multi?: boolean
required?: boolean required?: boolean
disabled?: boolean disabled?: boolean
@@ -77,7 +77,7 @@ export default class InputString extends React.Component<InputStringProps, Input
editing: true, editing: true,
value: e.target.value value: e.target.value
}, () => { }, () => {
this.props.onInput(this.state.value); if (this.props.onInput) this.props.onInput(this.state.value);
}); });
}, },
onBlur: () => { onBlur: () => {
@@ -1,13 +1,12 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types'
import Block from './Block' import Block from './Block'
import InputSpec from './InputSpec' import InputSpec, { SpecFieldProps as InputFieldSpecProps } from './InputSpec'
import Fieldset from './Fieldset' import Fieldset from './Fieldset'
const typeMap = { const typeMap = {
color: () => Block, color: () => Block,
enum: ({fieldSpec}) => (Object.keys(fieldSpec.values).length <= 3 ? Fieldset : Block), enum: ({fieldSpec}: any) => (Object.keys(fieldSpec.values).length <= 3 ? Fieldset : Block),
boolean: () => Block, boolean: () => Block,
array: () => Fieldset, array: () => Fieldset,
resolvedImage: () => Block, resolvedImage: () => Block,
@@ -16,12 +15,11 @@ const typeMap = {
formatted: () => Block, formatted: () => Block,
}; };
export default class SpecField extends React.Component { type SpecFieldProps = InputFieldSpecProps & {
static propTypes = { name?: string
...InputSpec.propTypes, };
name: PropTypes.string,
}
export default class SpecField extends React.Component<SpecFieldProps> {
render() { render() {
const {props} = this; const {props} = this;