From dcb15a4ab2f39819c632035520958aa8a26df334 Mon Sep 17 00:00:00 2001 From: Maciej Barelkowski Date: Mon, 17 Jan 2022 17:01:25 +0100 Subject: [PATCH] feat: generate type declarations Closes #65 --- package-lock.json | 6 +++ package.json | 11 ++++-- src/PropertiesPanel.js | 51 +------------------------ src/components/DropdownButton.js | 3 +- src/components/Group.js | 6 ++- src/components/ListGroup.js | 2 +- src/components/ListItem.js | 5 ++- src/components/entries/List.js | 3 +- src/components/entries/NumberField.js | 2 +- src/components/entries/Simple.js | 6 +-- src/components/entries/TextArea.js | 2 +- src/components/entries/TextField.js | 2 +- src/components/icons/index.js | 1 + src/context/DescriptionContext.js | 3 +- src/context/LayoutContext.js | 1 + src/hooks/useDescriptionContext.js | 2 +- src/types.d.ts | 55 +++++++++++++++++++++++++++ tsconfig.json | 29 ++++++++++++++ 18 files changed, 124 insertions(+), 66 deletions(-) create mode 100644 src/types.d.ts create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 2a33a2ab..d7581c07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8351,6 +8351,12 @@ "mime-types": "~2.1.24" } }, + "typescript": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", + "dev": true + }, "ua-parser-js": { "version": "0.7.28", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz", diff --git a/package.json b/package.json index ef02140f..21458a98 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Library for creating bpmn-io properties panels.", "main": "dist/index.js", "module": "dist/index.esm.js", + "types": "dist/types/index.d.ts", "files": [ "dist", "assets", @@ -11,13 +12,16 @@ ], "scripts": { "all": "run-s lint build test", - "build": "del-cli preact dist && rollup -c", + "build": "del-cli preact dist && rollup -c && npm run generate-types", "build:watch": "rollup -c --watch", - "lint": "eslint .", + "lint": "run-p lint:*", + "lint:js": "eslint .", + "lint:types": "tsc --noEmit --emitDeclarationOnly false", "dev": "npm test -- --auto-watch --no-single-run", "test": "karma start karma.config.js", "prepublishOnly": "run-s build", - "prepare": "run-s build" + "prepare": "run-s build", + "generate-types": "tsc && cp src/*.d.ts dist/types" }, "repository": { "type": "git", @@ -82,6 +86,7 @@ "sinon": "^11.1.1", "sinon-chai": "^3.7.0", "sirv-cli": "^1.0.12", + "typescript": "^4.5.4", "webpack": "^5.38.1" } } diff --git a/src/PropertiesPanel.js b/src/PropertiesPanel.js index 244cc2bf..a7c7e2cd 100644 --- a/src/PropertiesPanel.js +++ b/src/PropertiesPanel.js @@ -27,53 +27,6 @@ const DEFAULT_LAYOUT = { const DEFAULT_DESCRIPTION = {}; -/** - * @typedef { { - * component: import('preact').ComponentChild, - * id: String, - * isEdited?: Function - * } } EntryDefinition - * - * @typedef { { - * autoFocusEntry: String, - * autoOpen?: Boolean, - * entries: Array, - * id: String, - * label: String, - * remove: (event: MouseEvent) => void - * } } ListItemDefinition - * - * @typedef { { - * add: (event: MouseEvent) => void, - * component: import('preact').Component, - * element: Object, - * id: String, - * items: Array, - * label: String, - * shouldSort?: Boolean, - * shouldOpen?: Boolean - * } } ListGroupDefinition - * - * @typedef { { - * component?: import('preact').Component, - * entries: Array, - * id: String, - * label: String - * } } GroupDefinition - * - * @typedef { { - * [id: String]: GetDescriptionFunction - * } } DescriptionConfig - * - * @callback { { - * @param {string} id - * @param {djs.model.base} element - * @returns {string} - * } } GetDescriptionFunction - * - */ - - /** * A basic properties panel component. Describes *how* content will be rendered, accepts * data from implementor to describe *what* will be rendered. @@ -81,10 +34,10 @@ const DEFAULT_DESCRIPTION = {}; * @param {Object} props * @param {Object} props.element * @param {import('./components/Header').HeaderProvider} props.headerProvider - * @param {Array} props.groups + * @param {import('./types').GroupDefinition[]} props.groups * @param {Object} [props.layoutConfig] * @param {Function} [props.layoutChanged] - * @param {DescriptionConfig} [props.descriptionConfig] + * @param {import('./types').DescriptionConfig} [props.descriptionConfig] * @param {Function} [props.descriptionLoaded] */ export default function PropertiesPanel(props) { diff --git a/src/components/DropdownButton.js b/src/components/DropdownButton.js index cdfaafec..5a7374a2 100644 --- a/src/components/DropdownButton.js +++ b/src/components/DropdownButton.js @@ -11,6 +11,7 @@ import classnames from 'classnames'; * @param {object} props * @param {string} [props.class] * @param {import('preact').Component[]} [props.menuItems] + * @param {import('preact').ComponentChildren} [props.children] * @returns */ export function DropdownButton(props) { @@ -94,7 +95,7 @@ function useGlobalClick(ignoredElements, callback) { * @param {MouseEvent} event */ function listener(event) { - if (ignoredElements.some(element => element && element.contains(event.target))) { + if (ignoredElements.some(element => element && element.contains(/** @type {Node} */ (event.target)))) { return; } diff --git a/src/components/Group.js b/src/components/Group.js index a71d98ce..d0a694de 100644 --- a/src/components/Group.js +++ b/src/components/Group.js @@ -20,7 +20,7 @@ import { import { ArrowIcon } from './icons'; /** - * @param {import('../PropertiesPanel').GroupDefinition} props + * @param {import('../types').EntriesGroupProps} props */ export default function Group(props) { const { @@ -39,18 +39,20 @@ export default function Group(props) { // set edited state depending on all entries useEffect(() => { - const hasOneEditedEntry = entries.find(entry => { + const hasOneEditedEntry = !!entries.find(entry => { const { id, isEdited } = entry; + /** @type {HTMLElement} */ const entryNode = domQuery(`[data-entry-id="${id}"]`); if (!isFunction(isEdited) || !entryNode) { return false; } + /** @type {HTMLElement} */ const inputNode = domQuery('.bio-properties-panel-input', entryNode); return isEdited(inputNode); diff --git a/src/components/ListGroup.js b/src/components/ListGroup.js index 8c93b4d0..977239e2 100644 --- a/src/components/ListGroup.js +++ b/src/components/ListGroup.js @@ -25,7 +25,7 @@ import { const noop = () => {}; /** - * @param {import('../PropertiesPanel').ListGroupDefinition} props + * @param {import('../types').ListGroupProps} props */ export default function ListGroup(props) { const { diff --git a/src/components/ListItem.js b/src/components/ListItem.js index 053ddd4d..f46a8f60 100644 --- a/src/components/ListItem.js +++ b/src/components/ListItem.js @@ -11,7 +11,7 @@ import { isFunction } from 'min-dash'; import CollapsibleEntry from './entries/Collapsible'; /** - * @param {import('../PropertiesPanel').ListItemDefinition} props + * @param {import('../types').ListItemDefinition} props */ export default function ListItem(props) { const { @@ -22,8 +22,11 @@ export default function ListItem(props) { // focus specified entry on auto open useEffect(() => { if (autoOpen && autoFocusEntry) { + + /** @type {HTMLElement} */ const entry = domQuery(`[data-entry-id="${autoFocusEntry}"]`); + /** @type {HTMLInputElement} */ const focusableInput = domQuery('.bio-properties-panel-input', entry); if (focusableInput) { diff --git a/src/components/entries/List.js b/src/components/entries/List.js index 2bcbbe48..ca78d411 100644 --- a/src/components/entries/List.js +++ b/src/components/entries/List.js @@ -31,7 +31,7 @@ import { * @param {string} props.id * @param {*} props.element * @param {Function} props.onAdd - * @param {(item: Item, index: number, isNew: boolean) => JSX.Element} props.renderItem + * @param {(item: Item, index: number, isNew: boolean) => import('preact').JSX.Element} props.renderItem * @param {string} [props.label=''] * @param {Function} [props.onRemove] * @param {Item[]} [props.items] @@ -176,6 +176,7 @@ function ItemsList(props) { if (newItem && autoFocusEntry) { // (0) select the parent entry (containing all list items) + /** @type {HTMLElement} */ const entry = domQuery(`[data-entry-id="${id}"]`); // (1) select the first input or a custom element to be focussed diff --git a/src/components/entries/NumberField.js b/src/components/entries/NumberField.js index 517d4c6b..20c6a853 100644 --- a/src/components/entries/NumberField.js +++ b/src/components/entries/NumberField.js @@ -39,7 +39,7 @@ function NumberField(props) { id={ prefixId(id) } type="number" name={ id } - spellCheck="false" + spellcheck={ false } autoComplete="off" disabled={ disabled } class="bio-properties-panel-input" diff --git a/src/components/entries/Simple.js b/src/components/entries/Simple.js index 299d9457..192f2bea 100644 --- a/src/components/entries/Simple.js +++ b/src/components/entries/Simple.js @@ -9,8 +9,8 @@ import { * @param {Object} props.element * @param {Function} props.getValue * @param {String} props.id - * @param {Function} [props.onBlur] - * @param {Function} [props.onFocus] + * @param {(event: FocusEvent) => void} [props.onBlur] + * @param {(event: FocusEvent) => void} [props.onFocus] * @param {Function} props.setValue */ export default function Simple(props) { @@ -37,7 +37,7 @@ export default function Simple(props) { id={ prefixId(id) } type="text" name={ id } - spellCheck="false" + spellcheck={ false } autoComplete="off" disabled={ disabled } class="bio-properties-panel-input" diff --git a/src/components/entries/TextArea.js b/src/components/entries/TextArea.js index e9a685a9..219d9f03 100644 --- a/src/components/entries/TextArea.js +++ b/src/components/entries/TextArea.js @@ -29,7 +29,7 @@ function TextArea(props) {