Merge branch 'main' into codex/replace-react-sortable-hoc-with-dnd-kit

This commit is contained in:
Bart Louwers
2025-07-10 00:04:39 +02:00
committed by GitHub
27 changed files with 533 additions and 596 deletions
+1
View File
@@ -14,6 +14,7 @@
- When loading a style into localStorage that causes a QuotaExceededError, purge localStorage and retry - When loading a style into localStorage that causes a QuotaExceededError, purge localStorage and retry
- Remove react-autobind dependency - Remove react-autobind dependency
- Remove usage of legacy `childContextTypes` API - Remove usage of legacy `childContextTypes` API
- Refactor Field components to use arrow function syntax
- Replace react-autocomplete with Downshift in the autocomplete component - Replace react-autocomplete with Downshift in the autocomplete component
- _...Add new stuff here..._ - _...Add new stuff here..._
+65 -64
View File
@@ -27,7 +27,7 @@
"downshift": "^9.0.9", "downshift": "^9.0.9",
"events": "^3.3.0", "events": "^3.3.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18next": "^25.3.1", "i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0", "i18next-browser-languagedetector": "^8.2.0",
"i18next-resources-to-backend": "^1.2.1", "i18next-resources-to-backend": "^1.2.1",
"json-stringify-pretty-compact": "^4.0.0", "json-stringify-pretty-compact": "^4.0.0",
@@ -109,7 +109,7 @@
"stylelint-config-recommended-scss": "^15.0.1", "stylelint-config-recommended-scss": "^15.0.1",
"stylelint-scss": "^6.12.1", "stylelint-scss": "^6.12.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.35.1", "typescript-eslint": "^8.36.0",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vite": "^6.3.5", "vite": "^6.3.5",
"vite-plugin-istanbul": "^7.0.0" "vite-plugin-istanbul": "^7.0.0"
@@ -3322,16 +3322,16 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.36.0.tgz",
"integrity": "sha512-9XNTlo7P7RJxbVeICaIIIEipqxLKguyh+3UbXuT2XQuFp6d8VOeDEGuz5IiX0dgZo8CiI6aOFLg4e8cF71SFVg==", "integrity": "sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.35.1", "@typescript-eslint/scope-manager": "8.36.0",
"@typescript-eslint/type-utils": "8.35.1", "@typescript-eslint/type-utils": "8.36.0",
"@typescript-eslint/utils": "8.35.1", "@typescript-eslint/utils": "8.36.0",
"@typescript-eslint/visitor-keys": "8.35.1", "@typescript-eslint/visitor-keys": "8.36.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^7.0.0", "ignore": "^7.0.0",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@@ -3345,7 +3345,7 @@
"url": "https://opencollective.com/typescript-eslint" "url": "https://opencollective.com/typescript-eslint"
}, },
"peerDependencies": { "peerDependencies": {
"@typescript-eslint/parser": "^8.35.1", "@typescript-eslint/parser": "^8.36.0",
"eslint": "^8.57.0 || ^9.0.0", "eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <5.9.0" "typescript": ">=4.8.4 <5.9.0"
} }
@@ -3360,15 +3360,15 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.36.0.tgz",
"integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==", "integrity": "sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.35.1", "@typescript-eslint/scope-manager": "8.36.0",
"@typescript-eslint/types": "8.35.1", "@typescript-eslint/types": "8.36.0",
"@typescript-eslint/typescript-estree": "8.35.1", "@typescript-eslint/typescript-estree": "8.36.0",
"@typescript-eslint/visitor-keys": "8.35.1", "@typescript-eslint/visitor-keys": "8.36.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -3384,13 +3384,13 @@
} }
}, },
"node_modules/@typescript-eslint/project-service": { "node_modules/@typescript-eslint/project-service": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz",
"integrity": "sha512-VYxn/5LOpVxADAuP3NrnxxHYfzVtQzLKeldIhDhzC8UHaiQvYlXvKuVho1qLduFbJjjy5U5bkGwa3rUGUb1Q6Q==", "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.35.1", "@typescript-eslint/tsconfig-utils": "^8.36.0",
"@typescript-eslint/types": "^8.35.1", "@typescript-eslint/types": "^8.36.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@@ -3405,13 +3405,13 @@
} }
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz",
"integrity": "sha512-s/Bpd4i7ht2934nG+UoSPlYXd08KYz3bmjLEb7Ye1UVob0d1ENiT3lY8bsCmik4RqfSbPw9xJJHbugpPpP5JUg==", "integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.35.1", "@typescript-eslint/types": "8.36.0",
"@typescript-eslint/visitor-keys": "8.35.1" "@typescript-eslint/visitor-keys": "8.36.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3422,9 +3422,9 @@
} }
}, },
"node_modules/@typescript-eslint/tsconfig-utils": { "node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz",
"integrity": "sha512-K5/U9VmT9dTHoNowWZpz+/TObS3xqC5h0xAIjXPw+MNcKV9qg6eSatEnmeAwkjHijhACH0/N7bkhKvbt1+DXWQ==", "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3438,13 +3438,13 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.36.0.tgz",
"integrity": "sha512-HOrUBlfVRz5W2LIKpXzZoy6VTZzMu2n8q9C2V/cFngIC5U1nStJgv0tMV4sZPzdf4wQm9/ToWUFPMN9Vq9VJQQ==", "integrity": "sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "8.35.1", "@typescript-eslint/typescript-estree": "8.36.0",
"@typescript-eslint/utils": "8.35.1", "@typescript-eslint/utils": "8.36.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^2.1.0" "ts-api-utils": "^2.1.0"
}, },
@@ -3461,9 +3461,9 @@
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz",
"integrity": "sha512-q/O04vVnKHfrrhNAscndAn1tuQhIkwqnaW+eu5waD5IPts2eX1dgJxgqcPx5BX109/qAz7IG6VrEPTOYKCNfRQ==", "integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3474,15 +3474,15 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz",
"integrity": "sha512-Vvpuvj4tBxIka7cPs6Y1uvM7gJgdF5Uu9F+mBJBPY4MhvjrjWGK4H0lVgLJd/8PWZ23FTqsaJaLEkBCFUk8Y9g==", "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/project-service": "8.35.1", "@typescript-eslint/project-service": "8.36.0",
"@typescript-eslint/tsconfig-utils": "8.35.1", "@typescript-eslint/tsconfig-utils": "8.36.0",
"@typescript-eslint/types": "8.35.1", "@typescript-eslint/types": "8.36.0",
"@typescript-eslint/visitor-keys": "8.35.1", "@typescript-eslint/visitor-keys": "8.36.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@@ -3502,15 +3502,15 @@
} }
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz",
"integrity": "sha512-lhnwatFmOFcazAsUm3ZnZFpXSxiwoa1Lj50HphnDe1Et01NF4+hrdXONSUHIcbVu2eFb1bAf+5yjXkGVkXBKAQ==", "integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.7.0", "@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.35.1", "@typescript-eslint/scope-manager": "8.36.0",
"@typescript-eslint/types": "8.35.1", "@typescript-eslint/types": "8.36.0",
"@typescript-eslint/typescript-estree": "8.35.1" "@typescript-eslint/typescript-estree": "8.36.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3525,12 +3525,12 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz",
"integrity": "sha512-VRwixir4zBWCSTP/ljEo091lbpypz57PoeAQ9imjG+vbeof9LplljsL1mos4ccG6H9IjfrVGM359RozUnuFhpw==", "integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/types": "8.35.1", "@typescript-eslint/types": "8.36.0",
"eslint-visitor-keys": "^4.2.1" "eslint-visitor-keys": "^4.2.1"
}, },
"engines": { "engines": {
@@ -7362,9 +7362,9 @@
} }
}, },
"node_modules/i18next": { "node_modules/i18next": {
"version": "25.3.1", "version": "25.3.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.1.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.2.tgz",
"integrity": "sha512-S4CPAx8LfMOnURnnJa8jFWvur+UX/LWcl6+61p9VV7SK2m0445JeBJ6tLD0D5SR0H29G4PYfWkEhivKG5p4RDg==", "integrity": "sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@@ -7379,6 +7379,7 @@
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.27.6" "@babel/runtime": "^7.27.6"
}, },
@@ -12840,14 +12841,14 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "8.35.1", "version": "8.36.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.35.1.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.36.0.tgz",
"integrity": "sha512-xslJjFzhOmHYQzSB/QTeASAHbjmxOGEP6Coh93TXmUBFQoJ1VU35UHIDmG06Jd6taf3wqqC1ntBnCMeymy5Ovw==", "integrity": "sha512-fTCqxthY+h9QbEgSIBfL9iV6CvKDFuoxg6bHPNpJ9HIUzS+jy2lCEyCmGyZRWEBSaykqcDPf1SJ+BfCI8DRopA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "8.35.1", "@typescript-eslint/eslint-plugin": "8.36.0",
"@typescript-eslint/parser": "8.35.1", "@typescript-eslint/parser": "8.36.0",
"@typescript-eslint/utils": "8.35.1" "@typescript-eslint/utils": "8.36.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+2 -2
View File
@@ -38,7 +38,7 @@
"detect-browser": "^5.3.0", "detect-browser": "^5.3.0",
"events": "^3.3.0", "events": "^3.3.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18next": "^25.3.1", "i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0", "i18next-browser-languagedetector": "^8.2.0",
"i18next-resources-to-backend": "^1.2.1", "i18next-resources-to-backend": "^1.2.1",
"json-stringify-pretty-compact": "^4.0.0", "json-stringify-pretty-compact": "^4.0.0",
@@ -140,7 +140,7 @@
"stylelint-config-recommended-scss": "^15.0.1", "stylelint-config-recommended-scss": "^15.0.1",
"stylelint-scss": "^6.12.1", "stylelint-scss": "^6.12.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.35.1", "typescript-eslint": "^8.36.0",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"vite": "^6.3.5", "vite": "^6.3.5",
"vite-plugin-istanbul": "^7.0.0" "vite-plugin-istanbul": "^7.0.0"
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import InputArray, { FieldArrayProps as InputArrayProps } from './InputArray' import InputArray, { FieldArrayProps as InputArrayProps } from './InputArray'
import Fieldset from './Fieldset' import Fieldset from './Fieldset'
@@ -9,10 +8,12 @@ type FieldArrayProps = InputArrayProps & {
} }
}; };
export default class FieldArray extends React.Component<FieldArrayProps> { const FieldArray: React.FC<FieldArrayProps> = (props) => {
render() { return (
return <Fieldset label={this.props.label} fieldSpec={this.props.fieldSpec}> <Fieldset label={props.label} fieldSpec={props.fieldSpec}>
<InputArray {...this.props} /> <InputArray {...props} />
</Fieldset> </Fieldset>
} );
} };
export default FieldArray;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import Block from './Block' import Block from './Block'
import InputAutocomplete, { InputAutocompleteProps } from './InputAutocomplete' import InputAutocomplete, { InputAutocompleteProps } from './InputAutocomplete'
@@ -8,10 +7,12 @@ type FieldAutocompleteProps = InputAutocompleteProps & {
}; };
export default class FieldAutocomplete extends React.Component<FieldAutocompleteProps> { const FieldAutocomplete: React.FC<FieldAutocompleteProps> = (props) => {
render() { return (
return <Block label={this.props.label}> <Block label={props.label}>
<InputAutocomplete {...this.props} /> <InputAutocomplete {...props} />
</Block> </Block>
} );
} };
export default FieldAutocomplete;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import Block from './Block' import Block from './Block'
import InputCheckbox, {InputCheckboxProps} from './InputCheckbox' import InputCheckbox, {InputCheckboxProps} from './InputCheckbox'
@@ -8,10 +7,12 @@ type FieldCheckboxProps = InputCheckboxProps & {
}; };
export default class FieldCheckbox extends React.Component<FieldCheckboxProps> { const FieldCheckbox: React.FC<FieldCheckboxProps> = (props) => {
render() { return (
return <Block label={this.props.label}> <Block label={props.label}>
<InputCheckbox {...this.props} /> <InputCheckbox {...props} />
</Block> </Block>
} );
} };
export default FieldCheckbox;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import Block from './Block' import Block from './Block'
import InputColor, {InputColorProps} from './InputColor' import InputColor, {InputColorProps} from './InputColor'
@@ -11,10 +10,12 @@ type FieldColorProps = InputColorProps & {
}; };
export default class FieldColor extends React.Component<FieldColorProps> { const FieldColor: React.FC<FieldColorProps> = (props) => {
render() { return (
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}> <Block label={props.label} fieldSpec={props.fieldSpec}>
<InputColor {...this.props} /> <InputColor {...props} />
</Block> </Block>
} );
} };
export default FieldColor;
+14 -12
View File
@@ -10,29 +10,31 @@ type FieldCommentInternalProps = {
error: {message: string} error: {message: string}
} & WithTranslation; } & WithTranslation;
class FieldCommentInternal extends React.Component<FieldCommentInternalProps> { const FieldCommentInternal: React.FC<FieldCommentInternalProps> = (props) => {
render() { const t = props.t;
const t = this.props.t; const fieldSpec = {
const fieldSpec = { doc: t(
doc: t("Comments for the current layer. This is non-standard and not in the spec."), "Comments for the current layer. This is non-standard and not in the spec."
}; ),
};
return <Block return (
<Block
label={t("Comments")} label={t("Comments")}
fieldSpec={fieldSpec} fieldSpec={fieldSpec}
data-wd-key="layer-comment" data-wd-key="layer-comment"
error={this.props.error} error={props.error}
> >
<InputString <InputString
multi={true} multi={true}
value={this.props.value} value={props.value}
onChange={this.props.onChange} onChange={props.onChange}
default={t("Comment...")} default={t("Comment...")}
data-wd-key="layer-comment.input" data-wd-key="layer-comment.input"
/> />
</Block> </Block>
} );
} };
const FieldComment = withTranslation()(FieldCommentInternal); const FieldComment = withTranslation()(FieldCommentInternal);
export default FieldComment; export default FieldComment;
+28 -40
View File
@@ -9,57 +9,45 @@ type FieldDocLabelProps = {
onToggleDoc?(...args: unknown[]): unknown onToggleDoc?(...args: unknown[]): unknown
}; };
type FieldDocLabelState = {
open: boolean
};
export default class FieldDocLabel extends React.Component<FieldDocLabelProps, FieldDocLabelState> { const FieldDocLabel: React.FC<FieldDocLabelProps> = (props) => {
constructor (props: FieldDocLabelProps) { const [open, setOpen] = React.useState(false);
super(props);
this.state = { const onToggleDoc = (state: boolean) => {
open: false, setOpen(state);
if (props.onToggleDoc) {
props.onToggleDoc(state);
} }
} };
onToggleDoc = (open: boolean) => { const { label, fieldSpec } = props;
this.setState({ const { doc } = fieldSpec || {};
open,
}, () => {
if (this.props.onToggleDoc) {
this.props.onToggleDoc(this.state.open);
}
});
}
render() { if (doc) {
const {label, fieldSpec} = this.props; return (
const {doc} = fieldSpec || {}; <label className="maputnik-doc-wrapper">
if (doc) {
return <label className="maputnik-doc-wrapper">
<div className="maputnik-doc-target"> <div className="maputnik-doc-target">
{label} {label}
{'\xa0'} {'\xa0'}
<button <button
aria-label={this.state.open ? "close property documentation" : "open property documentation"} aria-label={open ? 'close property documentation' : 'open property documentation'}
className={`maputnik-doc-button maputnik-doc-button--${this.state.open ? 'open' : 'closed'}`} className={`maputnik-doc-button maputnik-doc-button--${open ? 'open' : 'closed'}`}
onClick={() => this.onToggleDoc(!this.state.open)} onClick={() => onToggleDoc(!open)}
data-wd-key={'field-doc-button-'+label} data-wd-key={'field-doc-button-' + label}
> >
{this.state.open ? <MdHighlightOff /> : <MdInfoOutline />} {open ? <MdHighlightOff /> : <MdInfoOutline />}
</button> </button>
</div> </div>
</label> </label>
} );
else if (label) { } else if (label) {
return <label className="maputnik-doc-wrapper"> return (
<div className="maputnik-doc-target"> <label className="maputnik-doc-wrapper">
{label} <div className="maputnik-doc-target">{label}</div>
</div>
</label> </label>
} );
else {
<div />
}
} }
} return <div />;
};
export default FieldDocLabel;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import InputDynamicArray, {FieldDynamicArrayProps as InputDynamicArrayProps} from './InputDynamicArray' import InputDynamicArray, {FieldDynamicArrayProps as InputDynamicArrayProps} from './InputDynamicArray'
import Fieldset from './Fieldset' import Fieldset from './Fieldset'
@@ -6,10 +5,12 @@ type FieldDynamicArrayProps = InputDynamicArrayProps & {
name?: string name?: string
}; };
export default class FieldDynamicArray extends React.Component<FieldDynamicArrayProps> { const FieldDynamicArray: React.FC<FieldDynamicArrayProps> = (props) => {
render() { return (
return <Fieldset label={this.props.label}> <Fieldset label={props.label}>
<InputDynamicArray {...this.props} /> <InputDynamicArray {...props} />
</Fieldset> </Fieldset>
} );
} };
export default FieldDynamicArray;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import InputEnum, {InputEnumProps} from './InputEnum' import InputEnum, {InputEnumProps} from './InputEnum'
import Fieldset from './Fieldset'; import Fieldset from './Fieldset';
@@ -11,10 +10,12 @@ type FieldEnumProps = InputEnumProps & {
}; };
export default class FieldEnum extends React.Component<FieldEnumProps> { const FieldEnum: React.FC<FieldEnumProps> = (props) => {
render() { return (
return <Fieldset label={this.props.label} fieldSpec={this.props.fieldSpec}> <Fieldset label={props.label} fieldSpec={props.fieldSpec}>
<InputEnum {...this.props} /> <InputEnum {...props} />
</Fieldset> </Fieldset>
} );
} };
export default FieldEnum;
+188 -216
View File
@@ -111,296 +111,268 @@ type FieldFunctionProps = {
value?: any value?: any
}; };
type FieldFunctionState = {
dataType: string
isEditing: boolean
}
/** Supports displaying spec field for zoom function objects /** Supports displaying spec field for zoom function objects
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property * https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
*/ */
export default class FieldFunction extends React.Component<FieldFunctionProps, FieldFunctionState> { const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
constructor (props: FieldFunctionProps) { const [dataType, setDataType] = React.useState(
super(props); getDataType(props.value, props.fieldSpec)
this.state = { );
dataType: getDataType(props.value, props.fieldSpec), const [isEditing, setIsEditing] = React.useState(false);
isEditing: false,
}
}
static getDerivedStateFromProps(props: Readonly<FieldFunctionProps>, state: FieldFunctionState) { React.useEffect(() => {
// Because otherwise when editing values we end up accidentally changing field type. if (!isEditing) {
if (state.isEditing) { setDataType(getDataType(props.value, props.fieldSpec));
return {};
} }
else { }, [props.value, props.fieldSpec, isEditing]);
return {
isEditing: false,
dataType: getDataType(props.value, props.fieldSpec)
};
}
}
getFieldFunctionType(fieldSpec: any) { const getFieldFunctionType = (fieldSpec: any) => {
if (fieldSpec.expression.interpolated) { if (fieldSpec.expression.interpolated) {
return "exponential" return 'exponential';
} }
if (fieldSpec.type === "number") { if (fieldSpec.type === 'number') {
return "interval" return 'interval';
} }
return "categorical" return 'categorical';
} };
addStop = () => { const addStop = () => {
const stops = this.props.value.stops.slice(0) const stops = props.value.stops.slice(0);
const lastStop = stops[stops.length - 1] const lastStop = stops[stops.length - 1];
if (typeof lastStop[0] === "object") { if (typeof lastStop[0] === 'object') {
stops.push([ stops.push([
{zoom: lastStop[0].zoom + 1, value: lastStop[0].value}, { zoom: lastStop[0].zoom + 1, value: lastStop[0].value },
lastStop[1] lastStop[1],
]) ]);
} } else {
else { stops.push([lastStop[0] + 1, lastStop[1]]);
stops.push([lastStop[0] + 1, lastStop[1]])
} }
const changedValue = { const changedValue = {
...this.props.value, ...props.value,
stops: stops, stops: stops,
} };
this.props.onChange(this.props.fieldName, changedValue) props.onChange(props.fieldName, changedValue);
} };
deleteExpression = () => { const deleteExpression = () => {
const {fieldSpec, fieldName} = this.props; const { fieldSpec, fieldName } = props;
this.props.onChange(fieldName, fieldSpec.default); props.onChange(fieldName, fieldSpec.default);
this.setState({ setDataType('value');
dataType: "value", };
});
}
deleteStop = (stopIdx: number) => { const deleteStop = (stopIdx: number) => {
const stops = this.props.value.stops.slice(0) const stops = props.value.stops.slice(0);
stops.splice(stopIdx, 1) stops.splice(stopIdx, 1);
let changedValue = { let changedValue: any = {
...this.props.value, ...props.value,
stops: stops, stops: stops,
};
if (stops.length === 1) {
changedValue = stops[0][1];
} }
if(stops.length === 1) { props.onChange(props.fieldName, changedValue);
changedValue = stops[0][1] };
}
this.props.onChange(this.props.fieldName, changedValue) const makeZoomFunction = () => {
} const { value } = props;
makeZoomFunction = () => { let zoomFunc: any;
const {value} = this.props; if (typeof value === 'object') {
let zoomFunc;
if (typeof(value) === "object") {
if (value.stops) { if (value.stops) {
zoomFunc = { zoomFunc = {
base: value.base, base: value.base,
stops: value.stops.map((stop: Stop) => { stops: value.stops.map((stop: Stop) => {
return [stop[0].zoom, stop[1] || findDefaultFromSpec(this.props.fieldSpec)]; return [stop[0].zoom, stop[1] || findDefaultFromSpec(props.fieldSpec)];
}) }),
} };
} } else {
else {
zoomFunc = { zoomFunc = {
base: value.base, base: value.base,
stops: [ stops: [
[6, findDefaultFromSpec(this.props.fieldSpec)], [6, findDefaultFromSpec(props.fieldSpec)],
[10, findDefaultFromSpec(this.props.fieldSpec)] [10, findDefaultFromSpec(props.fieldSpec)],
] ],
} };
} }
} } else {
else {
zoomFunc = { zoomFunc = {
stops: [ stops: [
[6, value || findDefaultFromSpec(this.props.fieldSpec)], [6, value || findDefaultFromSpec(props.fieldSpec)],
[10, value || findDefaultFromSpec(this.props.fieldSpec)] [10, value || findDefaultFromSpec(props.fieldSpec)],
] ],
} };
} }
this.props.onChange(this.props.fieldName, zoomFunc) props.onChange(props.fieldName, zoomFunc);
} };
undoExpression = () => { const undoExpression = () => {
const {value, fieldName} = this.props; const { value, fieldName } = props;
if (isGetExpression(value)) { if (isGetExpression(value)) {
this.props.onChange(fieldName, { props.onChange(fieldName, {
"type": "identity", type: 'identity',
"property": value[1] property: value[1],
});
this.setState({
dataType: "value",
}); });
setDataType('value');
} else if (isLiteralExpression(value)) {
props.onChange(fieldName, value[1]);
setDataType('value');
} }
else if (isLiteralExpression(value)) { };
this.props.onChange(fieldName, value[1]);
this.setState({
dataType: "value",
});
}
}
canUndo = () => { const canUndo = () => {
const {value, fieldSpec} = this.props; const { value, fieldSpec } = props;
return ( return (
isGetExpression(value) || isGetExpression(value) ||
isLiteralExpression(value) || isLiteralExpression(value) ||
isPrimative(value) || isPrimative(value) ||
(Array.isArray(value) && fieldSpec.type === "array") (Array.isArray(value) && fieldSpec.type === 'array')
); );
} };
makeExpression = () => { const makeExpression = () => {
const {value, fieldSpec} = this.props; const { value, fieldSpec } = props;
let expression; let expression;
if (typeof(value) === "object" && 'stops' in value) { if (typeof value === 'object' && 'stops' in value) {
expression = styleFunction.convertFunction(value, fieldSpec); expression = styleFunction.convertFunction(value, fieldSpec);
} else if (isIdentityProperty(value)) {
expression = ['get', value.property];
} else {
expression = ['literal', value || props.fieldSpec.default];
} }
else if (isIdentityProperty(value)) { props.onChange(props.fieldName, expression);
expression = ["get", value.property]; };
}
else {
expression = ["literal", value || this.props.fieldSpec.default];
}
this.props.onChange(this.props.fieldName, expression);
}
makeDataFunction = () => { const makeDataFunction = () => {
const functionType = this.getFieldFunctionType(this.props.fieldSpec); const functionType = getFieldFunctionType(props.fieldSpec);
const stopValue = functionType === 'categorical' ? '' : 0; const stopValue = functionType === 'categorical' ? '' : 0;
const {value} = this.props; const { value } = props;
let dataFunc; let dataFunc;
if (typeof(value) === "object") { if (typeof value === 'object') {
if (value.stops) { if (value.stops) {
dataFunc = { dataFunc = {
property: "", property: '',
type: functionType, type: functionType,
base: value.base, base: value.base,
stops: value.stops.map((stop: Stop) => { stops: value.stops.map((stop: Stop) => {
return [{zoom: stop[0], value: stopValue}, stop[1] || findDefaultFromSpec(this.props.fieldSpec)]; return [{ zoom: stop[0], value: stopValue }, stop[1] || findDefaultFromSpec(props.fieldSpec)];
}) }),
} };
} } else {
else {
dataFunc = { dataFunc = {
property: "", property: '',
type: functionType, type: functionType,
base: value.base, base: value.base,
stops: [ stops: [
[{zoom: 6, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec)], [{ zoom: 6, value: stopValue }, findDefaultFromSpec(props.fieldSpec)],
[{zoom: 10, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec)] [{ zoom: 10, value: stopValue }, findDefaultFromSpec(props.fieldSpec)],
] ],
} };
} }
} } else {
else {
dataFunc = { dataFunc = {
property: "", property: '',
type: functionType, type: functionType,
base: value.base, base: value.base,
stops: [ stops: [
[{zoom: 6, value: stopValue}, this.props.value || findDefaultFromSpec(this.props.fieldSpec)], [{ zoom: 6, value: stopValue }, props.value || findDefaultFromSpec(props.fieldSpec)],
[{zoom: 10, value: stopValue}, this.props.value || findDefaultFromSpec(this.props.fieldSpec)] [{ zoom: 10, value: stopValue }, props.value || findDefaultFromSpec(props.fieldSpec)],
] ],
} };
} }
this.props.onChange(this.props.fieldName, dataFunc) props.onChange(props.fieldName, dataFunc);
};
const onMarkEditing = () => {
setIsEditing(true);
};
const onUnmarkEditing = () => {
setIsEditing(false);
};
const propClass =
props.fieldSpec.default === props.value ? 'maputnik-default-property' : 'maputnik-modified-property';
let specField;
if (dataType === 'expression') {
specField = (
<ExpressionProperty
errors={props.errors}
onChange={props.onChange.bind(null, props.fieldName)}
canUndo={canUndo}
onUndo={undoExpression}
onDelete={deleteExpression}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onFocus={onMarkEditing}
onBlur={onUnmarkEditing}
/>
);
} else if (dataType === 'zoom_function') {
specField = (
<ZoomProperty
errors={props.errors}
onChange={props.onChange.bind(null)}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onDeleteStop={deleteStop}
onAddStop={addStop}
onChangeToDataFunction={makeDataFunction}
onExpressionClick={makeExpression}
/>
);
} else if (dataType === 'data_function') {
specField = (
<DataProperty
errors={props.errors}
onChange={props.onChange.bind(null)}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onDeleteStop={deleteStop}
onAddStop={addStop}
onChangeToZoomFunction={makeZoomFunction}
onExpressionClick={makeExpression}
/>
);
} else {
specField = (
<SpecProperty
errors={props.errors}
onChange={props.onChange.bind(null)}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onZoomClick={makeZoomFunction}
onDataClick={makeDataFunction}
onExpressionClick={makeExpression}
/>
);
} }
onMarkEditing = () => { return (
this.setState({isEditing: true}); <div className={propClass} data-wd-key={'spec-field-container:' + props.fieldName}>
}
onUnmarkEditing = () => {
this.setState({isEditing: false});
}
render() {
const {dataType} = this.state;
const propClass = this.props.fieldSpec.default === this.props.value ? "maputnik-default-property" : "maputnik-modified-property"
let specField;
if (dataType === "expression") {
specField = (
<ExpressionProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this, this.props.fieldName)}
canUndo={this.canUndo}
onUndo={this.undoExpression}
onDelete={this.deleteExpression}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onFocus={this.onMarkEditing}
onBlur={this.onUnmarkEditing}
/>
);
}
else if (dataType === "zoom_function") {
specField = (
<ZoomProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this)}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onDeleteStop={this.deleteStop}
onAddStop={this.addStop}
onChangeToDataFunction={this.makeDataFunction}
onExpressionClick={this.makeExpression}
/>
)
}
else if (dataType === "data_function") {
// TODO: Rename to FieldFunction **this file** shouldn't be called that
specField = (
<DataProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this)}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onDeleteStop={this.deleteStop}
onAddStop={this.addStop}
onChangeToZoomFunction={this.makeZoomFunction}
onExpressionClick={this.makeExpression}
/>
)
}
else {
specField = (
<SpecProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this)}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onZoomClick={this.makeZoomFunction}
onDataClick={this.makeDataFunction}
onExpressionClick={this.makeExpression}
/>
)
}
return <div className={propClass} data-wd-key={"spec-field-container:"+this.props.fieldName}>
{specField} {specField}
</div> </div>
} );
} };
export default FieldFunction;
+12 -12
View File
@@ -1,4 +1,3 @@
import React from 'react'
import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json' import latest from '@maplibre/maplibre-gl-style-spec/dist/latest.json'
import Block from './Block' import Block from './Block'
@@ -11,18 +10,19 @@ type FieldIdProps = {
error?: {message: string} error?: {message: string}
}; };
export default class FieldId extends React.Component<FieldIdProps> { const FieldId: React.FC<FieldIdProps> = (props) => {
render() { return (
return <Block label="ID" fieldSpec={latest.layer.id} <Block label="ID" fieldSpec={latest.layer.id}
data-wd-key={props.wdKey}
data-wd-key={this.props.wdKey} error={props.error}
error={this.props.error}
> >
<InputString <InputString
value={this.props.value} value={props.value}
onInput={this.props.onChange} onInput={props.onChange}
data-wd-key={this.props.wdKey + ".input"} data-wd-key={props.wdKey + ".input"}
/> />
</Block> </Block>
} );
} };
export default FieldId;
+5 -6
View File
@@ -1,12 +1,11 @@
import React from 'react'
import InputJson, {InputJsonProps} from './InputJson' import InputJson, {InputJsonProps} from './InputJson'
type FieldJsonProps = InputJsonProps & {}; type FieldJsonProps = InputJsonProps & {};
export default class FieldJson extends React.Component<FieldJsonProps> { const FieldJson: React.FC<FieldJsonProps> = (props) => {
render() { return <InputJson {...props} />;
return <InputJson {...this.props} /> };
}
} export default FieldJson;
+9 -9
View File
@@ -11,25 +11,25 @@ type FieldMaxZoomInternalProps = {
error?: {message: string} error?: {message: string}
} & WithTranslation; } & WithTranslation;
class FieldMaxZoomInternal extends React.Component<FieldMaxZoomInternalProps> { const FieldMaxZoomInternal: React.FC<FieldMaxZoomInternalProps> = (props) => {
render() { const t = props.t;
const t = this.props.t; return (
return <Block label={t("Max Zoom")} fieldSpec={latest.layer.maxzoom} <Block label={t('Max Zoom')} fieldSpec={latest.layer.maxzoom}
error={this.props.error} error={props.error}
data-wd-key="max-zoom" data-wd-key="max-zoom"
> >
<InputNumber <InputNumber
allowRange={true} allowRange={true}
value={this.props.value} value={props.value}
onChange={this.props.onChange} onChange={props.onChange}
min={latest.layer.maxzoom.minimum} min={latest.layer.maxzoom.minimum}
max={latest.layer.maxzoom.maximum} max={latest.layer.maxzoom.maximum}
default={latest.layer.maxzoom.maximum} default={latest.layer.maxzoom.maximum}
data-wd-key="max-zoom.input" data-wd-key="max-zoom.input"
/> />
</Block> </Block>
} );
} };
const FieldMaxZoom = withTranslation()(FieldMaxZoomInternal); const FieldMaxZoom = withTranslation()(FieldMaxZoomInternal);
export default FieldMaxZoom; export default FieldMaxZoom;
+9 -9
View File
@@ -11,25 +11,25 @@ type FieldMinZoomInternalProps = {
error?: {message: string} error?: {message: string}
} & WithTranslation; } & WithTranslation;
class FieldMinZoomInternal extends React.Component<FieldMinZoomInternalProps> { const FieldMinZoomInternal: React.FC<FieldMinZoomInternalProps> = (props) => {
render() { const t = props.t;
const t = this.props.t; return (
return <Block label={t("Min Zoom")} fieldSpec={latest.layer.minzoom} <Block label={t('Min Zoom')} fieldSpec={latest.layer.minzoom}
error={this.props.error} error={props.error}
data-wd-key="min-zoom" data-wd-key="min-zoom"
> >
<InputNumber <InputNumber
allowRange={true} allowRange={true}
value={this.props.value} value={props.value}
onChange={this.props.onChange} onChange={props.onChange}
min={latest.layer.minzoom.minimum} min={latest.layer.minzoom.minimum}
max={latest.layer.minzoom.maximum} max={latest.layer.minzoom.maximum}
default={latest.layer.minzoom.minimum} default={latest.layer.minzoom.minimum}
data-wd-key='min-zoom.input' data-wd-key='min-zoom.input'
/> />
</Block> </Block>
} );
} };
const FieldMinZoom = withTranslation()(FieldMinZoomInternal); const FieldMinZoom = withTranslation()(FieldMinZoomInternal);
export default FieldMinZoom; export default FieldMinZoom;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import InputMultiInput, {InputMultiInputProps} from './InputMultiInput' import InputMultiInput, {InputMultiInputProps} from './InputMultiInput'
import Fieldset from './Fieldset' import Fieldset from './Fieldset'
@@ -8,10 +7,12 @@ type FieldMultiInputProps = InputMultiInputProps & {
}; };
export default class FieldMultiInput extends React.Component<FieldMultiInputProps> { const FieldMultiInput: React.FC<FieldMultiInputProps> = (props) => {
render() { return (
return <Fieldset label={this.props.label}> <Fieldset label={props.label}>
<InputMultiInput {...this.props} /> <InputMultiInput {...props} />
</Fieldset> </Fieldset>
} );
} };
export default FieldMultiInput;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import InputNumber, {InputNumberProps} from './InputNumber' import InputNumber, {InputNumberProps} from './InputNumber'
import Block from './Block' import Block from './Block'
@@ -11,10 +10,12 @@ type FieldNumberProps = InputNumberProps & {
}; };
export default class FieldNumber extends React.Component<FieldNumberProps> { const FieldNumber: React.FC<FieldNumberProps> = (props) => {
render() { return (
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}> <Block label={props.label} fieldSpec={props.fieldSpec}>
<InputNumber {...this.props} /> <InputNumber {...props} />
</Block> </Block>
} );
} };
export default FieldNumber;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import Block from './Block' import Block from './Block'
import InputSelect, {InputSelectProps} from './InputSelect' import InputSelect, {InputSelectProps} from './InputSelect'
@@ -11,10 +10,12 @@ type FieldSelectProps = InputSelectProps & {
}; };
export default class FieldSelect extends React.Component<FieldSelectProps> { const FieldSelect: React.FC<FieldSelectProps> = (props) => {
render() { return (
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}> <Block label={props.label} fieldSpec={props.fieldSpec}>
<InputSelect {...this.props}/> <InputSelect {...props} />
</Block> </Block>
} );
} };
export default FieldSelect;
+17 -17
View File
@@ -13,28 +13,28 @@ type FieldSourceInternalProps = {
error?: {message: string} error?: {message: string}
} & WithTranslation; } & WithTranslation;
class FieldSourceInternal extends React.Component<FieldSourceInternalProps> { const FieldSourceInternal: React.FC<FieldSourceInternalProps> = (props) => {
static defaultProps = { const t = props.t;
onChange: () => {}, return (
sourceIds: [], <Block
} label={t('Source')}
render() {
const t = this.props.t;
return <Block
label={t("Source")}
fieldSpec={latest.layer.source} fieldSpec={latest.layer.source}
error={this.props.error} error={props.error}
data-wd-key={this.props.wdKey} data-wd-key={props.wdKey}
> >
<InputAutocomplete <InputAutocomplete
value={this.props.value} value={props.value}
onChange={this.props.onChange} onChange={props.onChange}
options={this.props.sourceIds?.map(src => [src, src])} options={props.sourceIds?.map((src) => [src, src])}
/> />
</Block> </Block>
} );
} };
FieldSourceInternal.defaultProps = {
onChange: () => {},
sourceIds: [],
};
const FieldSource = withTranslation()(FieldSourceInternal); const FieldSource = withTranslation()(FieldSourceInternal);
export default FieldSource; export default FieldSource;
+17 -17
View File
@@ -13,29 +13,29 @@ type FieldSourceLayerInternalProps = {
error?: {message: string} error?: {message: string}
} & WithTranslation; } & WithTranslation;
class FieldSourceLayerInternal extends React.Component<FieldSourceLayerInternalProps> { const FieldSourceLayerInternal: React.FC<FieldSourceLayerInternalProps> = (props) => {
static defaultProps = { const t = props.t;
onChange: () => {}, return (
sourceLayerIds: [], <Block
isFixed: false label={t('Source Layer')}
}
render() {
const t = this.props.t;
return <Block
label={t("Source Layer")}
fieldSpec={latest.layer['source-layer']} fieldSpec={latest.layer['source-layer']}
data-wd-key="layer-source-layer" data-wd-key="layer-source-layer"
error={this.props.error} error={props.error}
> >
<InputAutocomplete <InputAutocomplete
value={this.props.value} value={props.value}
onChange={this.props.onChange} onChange={props.onChange}
options={this.props.sourceLayerIds?.map(l => [l, l])} options={props.sourceLayerIds?.map((l) => [l, l])}
/> />
</Block> </Block>
} );
} };
FieldSourceLayerInternal.defaultProps = {
onChange: () => {},
sourceLayerIds: [],
isFixed: false,
};
const FieldSourceLayer = withTranslation()(FieldSourceLayerInternal); const FieldSourceLayer = withTranslation()(FieldSourceLayerInternal);
export default FieldSourceLayer; export default FieldSourceLayer;
+8 -7
View File
@@ -1,4 +1,3 @@
import React from 'react'
import Block from './Block' import Block from './Block'
import InputString, {InputStringProps} from './InputString' import InputString, {InputStringProps} from './InputString'
@@ -10,10 +9,12 @@ type FieldStringProps = InputStringProps & {
} }
}; };
export default class FieldString extends React.Component<FieldStringProps> { const FieldString: React.FC<FieldStringProps> = (props) => {
render() { return (
return <Block label={this.props.label} fieldSpec={this.props.fieldSpec}> <Block label={props.label} fieldSpec={props.fieldSpec}>
<InputString {...this.props} /> <InputString {...props} />
</Block> </Block>
} );
} };
export default FieldString;
+20 -23
View File
@@ -14,24 +14,17 @@ type FieldTypeInternalProps = {
disabled?: boolean disabled?: boolean
} & WithTranslation; } & WithTranslation;
class FieldTypeInternal extends React.Component<FieldTypeInternalProps> { const FieldTypeInternal: React.FC<FieldTypeInternalProps> = (props) => {
static defaultProps = { const t = props.t;
disabled: false, return (
} <Block label={t('Type')} fieldSpec={latest.layer.type}
data-wd-key={props.wdKey}
render() { error={props.error}
const t = this.props.t;
return <Block label={t("Type")} fieldSpec={latest.layer.type}
data-wd-key={this.props.wdKey}
error={this.props.error}
> >
{this.props.disabled && {props.disabled && (
<InputString <InputString value={props.value} disabled={true} />
value={this.props.value} )}
disabled={true} {!props.disabled && (
/>
}
{!this.props.disabled &&
<InputSelect <InputSelect
options={[ options={[
['background', 'Background'], ['background', 'Background'],
@@ -44,14 +37,18 @@ class FieldTypeInternal extends React.Component<FieldTypeInternalProps> {
['hillshade', 'Hillshade'], ['hillshade', 'Hillshade'],
['heatmap', 'Heatmap'], ['heatmap', 'Heatmap'],
]} ]}
onChange={this.props.onChange} onChange={props.onChange}
value={this.props.value} value={props.value}
data-wd-key={this.props.wdKey + ".select"} data-wd-key={props.wdKey + '.select'}
/> />
} )}
</Block> </Block>
} );
} };
FieldTypeInternal.defaultProps = {
disabled: false,
};
const FieldType = withTranslation()(FieldTypeInternal); const FieldType = withTranslation()(FieldTypeInternal);
export default FieldType; export default FieldType;
+9 -10
View File
@@ -1,4 +1,3 @@
import React from 'react'
import InputUrl, {FieldUrlProps as InputUrlProps} from './InputUrl' import InputUrl, {FieldUrlProps as InputUrlProps} from './InputUrl'
import Block from './Block' import Block from './Block'
@@ -11,12 +10,12 @@ type FieldUrlProps = InputUrlProps & {
}; };
export default class FieldUrl extends React.Component<FieldUrlProps> { const FieldUrl: React.FC<FieldUrlProps> = (props) => {
render () { return (
return ( <Block label={props.label} fieldSpec={props.fieldSpec}>
<Block label={this.props.label} fieldSpec={this.props.fieldSpec}> <InputUrl {...props} />
<InputUrl {...this.props} /> </Block>
</Block> );
); };
}
} export default FieldUrl;
+26 -43
View File
@@ -9,57 +9,40 @@ type FieldsetProps = PropsWithChildren & {
action?: ReactElement, action?: ReactElement,
}; };
type FieldsetState = {
showDoc: boolean
};
export default class Fieldset extends React.Component<FieldsetProps, FieldsetState> { const Fieldset: React.FC<FieldsetProps> = (props) => {
_labelId: string; const [showDoc, setShowDoc] = React.useState(false);
const labelId = React.useRef(generateUniqueId('fieldset_label_'));
constructor (props: FieldsetProps) { const onToggleDoc = (val: boolean) => {
super(props); setShowDoc(val);
this._labelId = generateUniqueId(`fieldset_label_`); };
this.state = {
showDoc: false,
}
}
onToggleDoc = (val: boolean) => { return (
this.setState({ <div className="maputnik-input-block" role="group" aria-labelledby={labelId.current}>
showDoc: val {props.fieldSpec && (
});
}
render () {
return <div className="maputnik-input-block" role="group" aria-labelledby={this._labelId}>
{this.props.fieldSpec &&
<div className="maputnik-input-block-label"> <div className="maputnik-input-block-label">
<FieldDocLabel <FieldDocLabel
label={this.props.label} label={props.label}
onToggleDoc={this.onToggleDoc} onToggleDoc={onToggleDoc}
fieldSpec={this.props.fieldSpec} fieldSpec={props.fieldSpec}
/> />
</div> </div>
} )}
{!this.props.fieldSpec && {!props.fieldSpec && (
<div className="maputnik-input-block-label"> <div className="maputnik-input-block-label">
{this.props.label} {props.label}
</div> </div>
} )}
<div className="maputnik-input-block-action"> <div className="maputnik-input-block-action">{props.action}</div>
{this.props.action} <div className="maputnik-input-block-content">{props.children}</div>
</div> {props.fieldSpec && (
<div className="maputnik-input-block-content"> <div className="maputnik-doc-inline" style={{ display: showDoc ? '' : 'none' }}>
{this.props.children} <Doc fieldSpec={props.fieldSpec} />
</div>
{this.props.fieldSpec &&
<div
className="maputnik-doc-inline"
style={{display: this.state.showDoc ? '' : 'none'}}
>
<Doc fieldSpec={this.props.fieldSpec} />
</div> </div>
} )}
</div> </div>
} );
} };
export default Fieldset;
+19 -22
View File
@@ -1,4 +1,3 @@
import React from 'react'
import Block from './Block' import Block from './Block'
import InputSpec, { SpecFieldProps as InputFieldSpecProps } from './InputSpec' import InputSpec, { SpecFieldProps as InputFieldSpecProps } from './InputSpec'
import Fieldset from './Fieldset' import Fieldset from './Fieldset'
@@ -20,27 +19,25 @@ export type SpecFieldProps = InputFieldSpecProps & {
name?: string name?: string
}; };
export default class SpecField extends React.Component<SpecFieldProps> { const SpecField: React.FC<SpecFieldProps> = (props) => {
render() { const fieldType = props.fieldSpec?.type;
const fieldType = this.props.fieldSpec?.type;
const typeBlockFn = typeMap[fieldType!]; const typeBlockFn = typeMap[fieldType!];
let TypeBlock; let TypeBlock;
if (typeBlockFn) { if (typeBlockFn) {
TypeBlock = typeBlockFn(this.props); TypeBlock = typeBlockFn(props);
}
else {
console.warn("No such type for '%s'", fieldType);
TypeBlock = Block;
}
return <TypeBlock
label={this.props.label}
action={this.props.action}
fieldSpec={this.props.fieldSpec}
>
<InputSpec {...this.props} />
</TypeBlock>
} }
} else {
console.warn("No such type for '%s'", fieldType);
TypeBlock = Block;
}
return (
<TypeBlock label={props.label} action={props.action} fieldSpec={props.fieldSpec}>
<InputSpec {...props} />
</TypeBlock>
);
};
export default SpecField;
+12 -24
View File
@@ -11,6 +11,18 @@
"url": "https://americanamap.org/style.json", "url": "https://americanamap.org/style.json",
"thumbnail": "https://github.com/maplibre/maputnik/assets/649392/23fa75ad-63e6-43f5-8837-03cdb0428bac" "thumbnail": "https://github.com/maplibre/maputnik/assets/649392/23fa75ad-63e6-43f5-8837-03cdb0428bac"
}, },
{
"id": "aws-hybrid",
"title": "AWS Hybrid",
"url": "https://maps.geo.eu-west-1.amazonaws.com/v2/styles/Hybrid/descriptor?key=v1.public.eyJqdGkiOiJiOTNkYjBlZi04OWUzLTQxMGUtODFhMC0zYjZjZjVmZWZmMDgifYtukap0NBaJpcrS6Vit9j03GJgK9Bn-RSu5UCe3jkdSql2kKp3IEgLPtyLssbmKUdVO11sXddjK3ZOZy8V6QG0olv0K_1tOxyMIe4DAO3IV6H4VzHWiaXlbSakGiEgFLuHBdcfLDeMotye7N6rSRxuZb0CN9ytH9VjLly6-NEBRZezO_qPQyvdTFdeZsARIpL0f9YVpxPxPVvUcAWYCk5LpaPseRCDPrY5SlCdA1ZKqUA4F9RzxSTxB73Fel_SoNDkCNaux1VposBu791-uUpDzUpr7leKckrPXrpZ2hwnFbafVxFV9vq4fLTpB5KoBksuLfGNIwAx1RLLxWuMhE4c.ZGQzZDY2OGQtMWQxMy00ZTEwLWIyZGUtOGVjYzUzMjU3OGE4&color-scheme=Light",
"thumbnail": "https://maputnik.s3.eu-west-1.amazonaws.com/thumbnails/aws-hybrid.jpg"
},
{
"id": "aws-standard",
"title": "AWS Standard",
"url": "https://maps.geo.eu-west-1.amazonaws.com/v2/styles/Standard/descriptor?key=v1.public.eyJqdGkiOiJiOTNkYjBlZi04OWUzLTQxMGUtODFhMC0zYjZjZjVmZWZmMDgifYtukap0NBaJpcrS6Vit9j03GJgK9Bn-RSu5UCe3jkdSql2kKp3IEgLPtyLssbmKUdVO11sXddjK3ZOZy8V6QG0olv0K_1tOxyMIe4DAO3IV6H4VzHWiaXlbSakGiEgFLuHBdcfLDeMotye7N6rSRxuZb0CN9ytH9VjLly6-NEBRZezO_qPQyvdTFdeZsARIpL0f9YVpxPxPVvUcAWYCk5LpaPseRCDPrY5SlCdA1ZKqUA4F9RzxSTxB73Fel_SoNDkCNaux1VposBu791-uUpDzUpr7leKckrPXrpZ2hwnFbafVxFV9vq4fLTpB5KoBksuLfGNIwAx1RLLxWuMhE4c.ZGQzZDY2OGQtMWQxMy00ZTEwLWIyZGUtOGVjYzUzMjU3OGE4&color-scheme=Light",
"thumbnail": "https://maputnik.s3.eu-west-1.amazonaws.com/thumbnails/aws-standard.jpg"
},
{ {
"id": "dark-matter", "id": "dark-matter",
"title": "Dark Matter", "title": "Dark Matter",
@@ -29,30 +41,6 @@
"url": "https://cdn.jsdelivr.net/gh/openmaptiles/toner-gl-style@v1.0/style.json", "url": "https://cdn.jsdelivr.net/gh/openmaptiles/toner-gl-style@v1.0/style.json",
"thumbnail": "https://maputnik.github.io/thumbnails/toner.png" "thumbnail": "https://maputnik.github.io/thumbnails/toner.png"
}, },
{
"id": "os-zoomstack-light",
"title": "Zoomstack Light",
"url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-light/style.json",
"thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-light.png"
},
{
"id": "os-zoomstack-night",
"title": "Zoomstack Night",
"url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-night/style.json",
"thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-night.png"
},
{
"id": "os-zoomstack-outdoor",
"title": "Zoomstack Outdoor",
"url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-outdoor/style.json",
"thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-outdoor.png"
},
{
"id": "os-zoomstack-road",
"title": "Zoomstack Road",
"url": "https://s3-eu-west-1.amazonaws.com/tiles.os.uk/v2/styles/open-zoomstack-road/style.json",
"thumbnail": "https://maputnik.github.io/thumbnails/os-zoomstack-road.png"
},
{ {
"id": "osm-bright", "id": "osm-bright",
"title": "OSM Bright", "title": "OSM Bright",