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..6372539a 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,14 @@ ], "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 .", "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" }, "repository": { "type": "git", @@ -82,6 +84,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..65d31efb 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').EntriesGroupDefinition} 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..046725e9 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').ListGroupDefinition} props */ export default function ListGroup(props) { const { diff --git a/src/components/icons/index.js b/src/components/icons/index.js index 102472ed..1fd95f2d 100644 --- a/src/components/icons/index.js +++ b/src/components/icons/index.js @@ -1,3 +1,4 @@ +// @ts-nocheck export { default as ArrowIcon } from './Arrow.svg'; export { default as CreateIcon } from './Create.svg'; export { default as DeleteIcon } from './Delete.svg'; \ No newline at end of file diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 00000000..6f80415b --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,40 @@ +import { Component, ComponentType } from '../preact'; + +export type EntryDefinition = { + component: Component, + id: string, + isEdited?: (node: HTMLElement) => boolean +}; + +export type ListItemDefinition = { + autoFocusEntry: string, + autoOpen?: boolean, + entries: EntryDefinition[], + id: string, + label: string, + remove: (event: MouseEvent) => void +} + +export type ListGroupDefinition = { + add: (event: MouseEvent) => void, + component: ComponentType, + element: any, + id: string, + items: Array, + label: string, + shouldSort?: boolean, + shouldOpen?: boolean +} + +export type EntriesGroupDefinition = { + component?: ComponentType, + entries: EntryDefinition[], + id: string, + label: string +}; + +export type GroupDefinition = ListGroupDefinition | EntriesGroupDefinition; + +export type DescriptionConfig = { [id: string]: GetDescriptionFunction }; + +export type GetDescriptionFunction = (id: string, element: any) => string; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..380eefb8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es2019", + "dom" + ], + "target": "es2019", + "allowJs": true, + "checkJs": true, + "rootDir": ".", + "strict": false, + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + "outDir": "./dist/types", + "declaration": true, + "emitDeclarationOnly": true, + "removeComments": false + }, + "include": [ + "src/index.js" + ], + "exclude": [ + "node_modules" + ] +}