diff --git a/package-lock.json b/package-lock.json index ca09a9fa..d489f929 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,9 @@ "@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-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", @@ -4841,6 +4843,15 @@ "@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-dom": { "version": "16.9.24", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.24.tgz", @@ -4850,6 +4861,15 @@ "@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/resolve": { "version": "1.20.6", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", diff --git a/package.json b/package.json index 7dc1709b..2c3b67eb 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,9 @@ "@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-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", diff --git a/src/components/Block.tsx b/src/components/Block.tsx index 3aaa2aa3..d7fe3709 100644 --- a/src/components/Block.tsx +++ b/src/components/Block.tsx @@ -9,7 +9,7 @@ type BlockProps = { label?: string action?: React.ReactElement style?: object - onChange(...args: unknown[]): unknown + onChange?(...args: unknown[]): unknown fieldSpec?: object wideMode?: boolean error?: unknown[] @@ -32,7 +32,9 @@ export default class Block extends React.Component { onChange(e: React.BaseSyntheticEvent) { const value = e.target.value - return this.props.onChange(value === "" ? undefined : value) + if (this.props.onChange) { + return this.props.onChange(value === "" ? undefined : value) + } } onToggleDoc = (val: boolean) => { diff --git a/src/components/FieldUrl.jsx b/src/components/FieldUrl.jsx deleted file mode 100644 index 3c53b19b..00000000 --- a/src/components/FieldUrl.jsx +++ /dev/null @@ -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 ( - - - - ); - } -} - diff --git a/src/components/FieldUrl.tsx b/src/components/FieldUrl.tsx new file mode 100644 index 00000000..9e7c23b0 --- /dev/null +++ b/src/components/FieldUrl.tsx @@ -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 { + render () { + const {props} = this; + + return ( + + + + ); + } +} + diff --git a/src/components/IconBackground.jsx b/src/components/IconBackground.tsx similarity index 100% rename from src/components/IconBackground.jsx rename to src/components/IconBackground.tsx diff --git a/src/components/IconCircle.jsx b/src/components/IconCircle.tsx similarity index 100% rename from src/components/IconCircle.jsx rename to src/components/IconCircle.tsx diff --git a/src/components/IconFill.jsx b/src/components/IconFill.tsx similarity index 100% rename from src/components/IconFill.jsx rename to src/components/IconFill.tsx diff --git a/src/components/IconLine.jsx b/src/components/IconLine.tsx similarity index 100% rename from src/components/IconLine.jsx rename to src/components/IconLine.tsx diff --git a/src/components/IconMissing.jsx b/src/components/IconMissing.tsx similarity index 100% rename from src/components/IconMissing.jsx rename to src/components/IconMissing.tsx diff --git a/src/components/IconSymbol.jsx b/src/components/IconSymbol.tsx similarity index 100% rename from src/components/IconSymbol.jsx rename to src/components/IconSymbol.tsx diff --git a/src/components/InputAutocomplete.jsx b/src/components/InputAutocomplete.tsx similarity index 80% rename from src/components/InputAutocomplete.jsx rename to src/components/InputAutocomplete.tsx index c2848f09..e574aca3 100644 --- a/src/components/InputAutocomplete.jsx +++ b/src/components/InputAutocomplete.tsx @@ -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 { 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) => (
{ + 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 { 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) });