diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d1f319 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +arrow.d.ts +node_modules/ +*.tgz \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..759b777 --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +node_modules +.gitignore +.vscode +*.tgz \ No newline at end of file diff --git a/README.md b/README.md index 73269e5..0010c60 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Following the issue of vis https://github.com/almende/vis/issues/1699, and thank 1 - Download the package -``` +```bash npm install timeline-arrows ``` @@ -20,8 +20,8 @@ npm install timeline-arrows For instance: -``` -const my_timeline = new vis.Timeline(container, items, groups, options); +```bash +const myTimeline = new vis.Timeline(container, items, groups, options); ``` @@ -35,8 +35,8 @@ And optionally: For instance: -``` -var arrows_array = [ +```javascript +var arrowsSpecs = [ { id: 2, id_item_1: 1, id_item_2: 2 }, { id: 5, id_item_1: 3, id_item_2: 5, title:'Hello!!!' }, { id: 7, id_item_1: 6, id_item_2: 7 }, @@ -48,8 +48,8 @@ var arrows_array = [ For instance: -``` -const my_Arrow = new Arrow(my_timeline, arrows_array); +```javascript +const myArrows = new Arrow(myTimeline, arrowsSpecs); ``` That's it :) @@ -59,13 +59,16 @@ That's it :) Options can be used to customize the arrows. Options are defined as a JSON object. All options are optional. -``` +```javascript const options = { followRelationships: true, - color: "#039E00" + color: "#039E00", + tooltipConfig: (el, title) => { + // tooltip initialization + }, }; -const my_Arrow = new Arrow(my_timeline, arrows_array, options); +const myArrows = new Arrow(myTimeline, arrowsSpecs, options); ``` **followRelationships** - defaults to false. @@ -74,6 +77,11 @@ If true, arrows can point backwards and will follow the relationships set in the **color** - defaults to "#9c0000". Sets the arrows color. +**strokeWidth** - defaults to 3 (px). +Sets the arrows width in pixels. + +**tooltipConfig** - if arrows have a `title` property, the default behavior will add a title attribute that shows on hover. However, you might not want to use the title attribute, but instead your own tooltip configuration. +This method takes two arguments, `el` - the arrow - and `title` - the content of the `title` property set in the arrow data. ## Methods @@ -82,29 +90,33 @@ I have created the following methods: **getArrow ( *arrow id* )** Returns the arrow whith this arrow_id. For instance: -``` -my_Arrow.getArrow (2); + +```javascript +myArrow.getArrow(2); ``` **addArrow ( *arrow object* )** Inserts a new arrow. For instance: -``` -my_Arrow.addArrow ( { id: 13, id_item_1: 15, id_item_2: 16 } ); + +```javascript +myArrow.addArrow({ id: 13, id_item_1: 15, id_item_2: 16 }); ``` -**removeArrow ( *arrow_Id* )** Removes the arrows with this arrow_Id. +**removeArrow ( *arrow_Id* )** Removes the arrows with this arrow_Id. For instance: -``` -my_Arrow.removeArrow ( 10 ); + +```javascript +myArrow.removeArrow( 10 ); ``` -**removeArrowbyItemId ( *item_Id* )** Removes the arrows connected with Items with this item_Id. Returns an array with the id's of the removed arrows. +**removeItemArrows ( *item_Id* )** Removes the arrows connected with Items with this item_Id. Returns an array with the id's of the removed arrows. For instance: -``` -my_Arrow.removeArrowbyItemId ( 23 ); + +```javascript +myArrow.removeItemArrows( 23 ); ``` ## Examples diff --git a/arrow.js b/arrow.js index cfd1faf..e779adc 100644 --- a/arrow.js +++ b/arrow.js @@ -24,20 +24,62 @@ * timeline-arrows may be distributed under either license. */ +// @ts-check + +/** + * @typedef {(number | string)} VisIdType Timeline view item id. Equivalent to vis.IdType. + */ + +/** + * @typedef {(number | string)} ArrowIdType arrow id. + */ + +/** + * @typedef ArrowSpec Arrow specification + * @property {ArrowIdType} id arrow id + * @property {VisIdType} id_item_1 start timeline item id + * @property {VisIdType} id_item_2 end timeline item id + * @property {string} [title] optional arrow title + */ + +/** + * @typedef ArrowOptions Arrow configuration options + * @property {boolean} [followRelationships] if true, arrows can point backwards and will follow the relationships set in the data + * @property {(el: SVGPathElement, title: string) => string } [tooltipConfig] if arrows have a `title` property, the default behavior will add a title attribute that shows on hover. However, you might not want to use the title attribute, but instead your own tooltip configuration. + This method takes two arguments, `el` - the arrow - and `title` - the content of the `title` property set in the arrow data. + * @property {string} [color] arrow color + * @property {number} [strokeWidth] arrow thickness in pixels + */ + +/** Arrow set for a vis.js Timeline. */ export default class Arrow { + /** + * Creates arrows. + * @param {*} timeline timeline object + * @param {ArrowSpec[]} dependencies arrows + * @param {ArrowOptions} [options] + */ constructor(timeline, dependencies, options) { this._svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); this._timeline = timeline; + /** @private @type {boolean | undefined} if true, arrows can point backwards and will follow the relationships set in the data */ this._followRelationships = options?.followRelationships; + /** @private @type {((el: SVGPathElement, title: string) => string) | undefined } */ + this._tooltipConfig = options?.tooltipConfig; + /** @private @type {string} color */ this._arrowsColor = options?.color ? options.color : "#9c0000" + /** @private @type {number} arrow thickness in pixels */ + this._arrowsStrokeWidth = options?.strokeWidth ?? 3; + /** @private @type {SVGMarkerElement} */ this._arrowHead = document.createElementNS( "http://www.w3.org/2000/svg", "marker" ); + /** @private @type {SVGPathElement} */ this._arrowHeadPath = document.createElementNS( "http://www.w3.org/2000/svg", "path" @@ -45,6 +87,7 @@ export default class Arrow { this._dependency = dependencies; + /** @private @type {SVGPathElement[]} */ this._dependencyPath = []; this._initialize(); @@ -87,6 +130,7 @@ export default class Arrow { } + /** @private */ _createPath(){ //Add a new path to array dependencyPath and to svg let somePath = document.createElementNS( @@ -95,7 +139,7 @@ export default class Arrow { ); somePath.setAttribute("d", "M 0 0"); somePath.style.stroke = this._arrowsColor; - somePath.style.strokeWidth = "3px"; + somePath.style.strokeWidth = this._arrowsStrokeWidth + "px"; somePath.style.fill = "none"; somePath.style.pointerEvents = "auto"; this._dependencyPath.push(somePath); @@ -103,7 +147,7 @@ export default class Arrow { } - + /** @private */ _drawDependencies() { //Create paths for the started dependency array for (let i = 0; i < this._dependency.length; i++) { @@ -111,20 +155,21 @@ export default class Arrow { } } + /** + * @private + * @param {ArrowSpec} dep arrow specification + * @param {number} index arrow index + */ _drawArrows(dep, index) { //Checks if both items exist //if( (typeof this._timeline.itemsData._data[dep.id_item_1] !== "undefined") && (typeof this._timeline.itemsData._data[dep.id_item_2] !== "undefined") ) { //debugger; - if( (this._timeline.itemsData.get(dep.id_item_1) !== null) && (this._timeline.itemsData.get(dep.id_item_2) !== null) ) { - var bothItemsExist = true; - } else { - var bothItemsExist = false; - } + const bothItemsExist = (this._timeline.itemsData.get(dep.id_item_1) !== null) && (this._timeline.itemsData.get(dep.id_item_2) !== null); //Checks if at least one item is visible in screen - var oneItemVisible = false; //Iniciamos a false + let oneItemVisible = false; //Iniciamos a false if (bothItemsExist) { - var visibleItems = this._timeline.getVisibleItems(); + const visibleItems = this._timeline.getVisibleItems(); for (let k = 0; k < visibleItems.length ; k++) { if (dep.id_item_1 == visibleItems[k]) oneItemVisible = true; if (dep.id_item_2 == visibleItems[k]) oneItemVisible = true; @@ -212,7 +257,9 @@ export default class Arrow { // Adding the title if property title has been added in the dependency if (dep.hasOwnProperty("title")) { - this._dependencyPath[index].innerHTML = "" +dep.title +"" + this._tooltipConfig + ? this._tooltipConfig(this._dependencyPath[index], dep.title ?? '') + : this._dependencyPath[index].innerHTML = "" + dep.title + ""; } } else { this._dependencyPath[index].setAttribute("marker-end", ""); @@ -221,7 +268,7 @@ export default class Arrow { } - //Función que recibe in Item y devuelve la posición en pantalla del item. + /** @private Función que recibe in Item y devuelve la posición en pantalla del item. */ _getItemPos (item) { let left_x = item.left; let top_y; @@ -243,38 +290,52 @@ export default class Arrow { } - addArrow (dep) { + /** + * Adds arrow between two timeline items. + * @param {ArrowSpec} dep item dependency + */ + addArrow(dep) { this._dependency.push(dep); this._createPath(); this._timeline.redraw(); } - getArrow (id) { - for (let i = 0; i < this._dependency.length; i++) { - if (this._dependency[i].id == id) { - return this._dependency[i]; - } - } - return null; + /** + * Get arrow by ID. + * @param {ArrowIdType} id arrow ID + * @returns {ArrowSpec | null} arrow spec, or null + */ + getArrow(id) { + return this._dependency.find(dep => dep.id === id) ?? null; } - //Función que recibe el id de una flecha y la elimina. + /** + * Finds arrow with the given id and removes it. + * Función que recibe el id de una flecha y la elimina. + * @param {ArrowIdType} id arrow id + */ removeArrow(id) { - for (let i = 0; i < this._dependency.length; i++) { - if (this._dependency[i].id == id) var index = i; - } + const index = this._dependency.findIndex(dep => dep.id === id); - //var list = document.getElementsByTagName("path"); //FALTA QUE ESTA SELECCION LA HAGA PARA EL DOM DEL TIMELINE INSTANCIADO!!!! - var list = document.querySelectorAll("#" +this._timeline.dom.container.id +" path"); + if (index >= 0) { - this._dependency.splice(index, 1); //Elimino del array dependency - this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath + //var list = document.getElementsByTagName("path"); //FALTA QUE ESTA SELECCION LA HAGA PARA EL DOM DEL TIMELINE INSTANCIADO!!!! + const list = document.querySelectorAll("#" + this._timeline.dom.container.id + " path"); + + this._dependency.splice(index, 1); //Elimino del array dependency + this._dependencyPath.splice(index, 1); //Elimino del array dependencyPath - list[index + 1].parentNode.removeChild(list[index + 1]); //Lo elimino del dom + list[index + 1].parentNode.removeChild(list[index + 1]); //Lo elimino del dom + } } - //Función que recibe el id de un item y elimina la flecha. - removeArrowbyItemId(id) { + /** + * Finds all arrows related to one view item and removes them all. + * Función que recibe el id de un item y elimina la flecha. + * @param {VisIdType} id view item id + * @returns {(ArrowIdType)[]} list of removed arrow ids + */ + removeItemArrows(id) { let listOfRemovedArrows = []; for (let i = 0; i < this._dependency.length; i++) { if ( (this._dependency[i].id_item_1 == id) || (this._dependency[i].id_item_2 == id) ) { @@ -286,6 +347,12 @@ export default class Arrow { return listOfRemovedArrows; } - + /** + * For backward compatibility + * @deprecated use the removeItemArrows method instead. + */ + removeArrowbyItemId(id) { + this.removeItemArrows(id); + } } \ No newline at end of file diff --git a/examples/2timelines.js b/examples/2timelines.js index 494f2c9..30137e4 100644 --- a/examples/2timelines.js +++ b/examples/2timelines.js @@ -9,12 +9,12 @@ selectable: true, editable: true, groupTemplate: function(group) { //function to hide groups - var container = document.createElement('div'); - var label = document.createElement('span'); + const container = document.createElement('div'); + const label = document.createElement('span'); label.innerHTML = group.content + ' '; container.insertAdjacentElement('afterBegin',label); - var hide = document.createElement('span'); + const hide = document.createElement('span'); hide.setAttribute("class", "oi oi-eye"); hide.addEventListener('click',function(){ groups.update({id: group.id, visible: false}); @@ -25,23 +25,23 @@ }; // Generate some - var now = vis.moment() + const now = vis.moment() .minutes(0) .seconds(0) .milliseconds(0); - var names = ["John", "Alston", "Lee", "Grant"]; - var itemCount = 20; + const names = ["John", "Alston", "Lee", "Grant"]; + const itemCount = 20; // create a data set with groups - var groups = new vis.DataSet(); - for (var g = 0; g < names.length; g++) { + const groups = new vis.DataSet(); + for (let g = 0; g < names.length; g++) { groups.add({ id: g, content: names[g] }); } // create a dataset with items - var items = new vis.DataSet(); - for (var i = 0; i < itemCount; i++) { - var start = now.clone().add(Math.random() * 200, "hours"); - var end = start + 100000000; - var group = Math.floor(Math.random() * names.length); + const items = new vis.DataSet(); + for (let i = 0; i < itemCount; i++) { + const start = now.clone().add(Math.random() * 200, "hours"); + const end = start + 100000000; + const group = Math.floor(Math.random() * names.length); items.add({ id: i, group: group, @@ -71,12 +71,12 @@ selectable: true, editable: true, groupTemplate: function(group) { //function to hide groups - var container = document.createElement('div'); - var label = document.createElement('span'); + const container = document.createElement('div'); + const label = document.createElement('span'); label.innerHTML = group.content + ' '; container.insertAdjacentElement('afterBegin',label); - var hide = document.createElement('span'); + const hide = document.createElement('span'); hide.setAttribute("class", "oi oi-eye"); hide.addEventListener('click',function(){ groups2.update({id: group.id, visible: false}); @@ -87,23 +87,23 @@ }; // Generate some - var now2 = vis.moment() + const now2 = vis.moment() .minutes(0) .seconds(0) .milliseconds(0); - var names2 = ["Juan", "Alfredo", "Luis", "David"]; - var itemCount2 = 20; + const names2 = ["Juan", "Alfredo", "Luis", "David"]; + const itemCount2 = 20; // create a data set with groups - var groups2 = new vis.DataSet(); - for (var g = 0; g < names2.length; g++) { + const groups2 = new vis.DataSet(); + for (let g = 0; g < names2.length; g++) { groups2.add({ id: g, content: names2[g] }); } // create a dataset with items - var items2 = new vis.DataSet(); - for (var i = 0; i < itemCount2; i++) { - var start = now2.clone().add(Math.random() * 200, "hours"); - var end = start + 100000000; - var group = Math.floor(Math.random() * names2.length); + const items2 = new vis.DataSet(); + for (let i = 0; i < itemCount2; i++) { + const start = now2.clone().add(Math.random() * 200, "hours"); + const end = start + 100000000; + const group = Math.floor(Math.random() * names2.length); items2.add({ id: i, group: group, @@ -134,11 +134,11 @@ onrangechange1(); }); function onrangechange1() { - var range = timelinevis.getWindow(); + const range = timelinevis.getWindow(); timelinevis2.setWindow(range.start, range.end, {animation: false}); } function onrangechange2() { - var range = timelinevis2.getWindow(); + const range = timelinevis2.getWindow(); timelinevis.setWindow(range.start, range.end, {animation: false}); } @@ -147,7 +147,7 @@ /** *CREATING 2 ARRAYS OF ARROWS */ - var dependency = [ + const dependency = [ { id: 2, id_item_1: 1, @@ -174,7 +174,7 @@ - var dependency2 = [ + const dependency2 = [ { id: 2, id_item_1: 1, @@ -219,7 +219,7 @@ /*ANOTHER FUNCTIONS (NO IMPORTANT)*/ const showVisibleItems = function () { - var a = timelinevis.getVisibleItems(); + const a = timelinevis.getVisibleItems(); document.getElementById("visibleItemsContainer").innerHTML = "" document.getElementById("visibleItemsContainer").innerHTML += a; }; diff --git a/examples/basic_example.js b/examples/basic_example.js index 4c788cd..2ab4e71 100644 --- a/examples/basic_example.js +++ b/examples/basic_example.js @@ -9,12 +9,12 @@ editable: true, // orientation: "top", groupTemplate: function(group) { //function to hide groups - var container = document.createElement('div'); - var label = document.createElement('span'); + const container = document.createElement('div'); + const label = document.createElement('span'); label.innerHTML = group.content + ' '; container.insertAdjacentElement('afterBegin',label); - var hide = document.createElement('span'); + const hide = document.createElement('span'); hide.setAttribute("class", "oi oi-eye"); hide.addEventListener('click',function(){ groups.update({id: group.id, visible: false}); @@ -25,23 +25,23 @@ }; // Generate some - var now = vis.moment() + const now = vis.moment() .minutes(0) .seconds(0) .milliseconds(0); - var names = ["John", "Alston", "Lee", "Grant"]; - var itemCount = 20; + const names = ["John", "Alston", "Lee", "Grant"]; + const itemCount = 20; // create a data set with groups - var groups = new vis.DataSet(); - for (var g = 0; g < names.length; g++) { + const groups = new vis.DataSet(); + for (let g = 0; g < names.length; g++) { groups.add({ id: g, content: names[g] }); } // create a dataset with items - var items = new vis.DataSet(); - for (var i = 0; i < itemCount; i++) { - var start = now.clone().add(Math.random() * 200, "hours"); - var end = start + 100000000; - var group = Math.floor(Math.random() * names.length); + const items = new vis.DataSet(); + for (let i = 0; i < itemCount; i++) { + const start = now.clone().add(Math.random() * 200, "hours"); + const end = start + 100000000; + const group = Math.floor(Math.random() * names.length); items.add({ id: i, group: group, @@ -68,7 +68,7 @@ /** *CREATING THE ARROWS */ - var dependency = [ + const dependency = [ { id: 2, id_item_1: 1, @@ -116,7 +116,7 @@ /*ANOTHER FUNCTIONS (NO IMPORTANT)*/ const showVisibleItems = function () { - var a = timelinevis.getVisibleItems(); + const a = timelinevis.getVisibleItems(); document.getElementById("visibleItemsContainer").innerHTML = "" document.getElementById("visibleItemsContainer").innerHTML += a; }; diff --git a/examples/colorOption.js b/examples/colorOption.js index a9def02..7c80943 100644 --- a/examples/colorOption.js +++ b/examples/colorOption.js @@ -8,12 +8,12 @@ selectable: true, editable: true, groupTemplate: function(group) { //function to hide groups - var container = document.createElement('div'); - var label = document.createElement('span'); + const container = document.createElement('div'); + const label = document.createElement('span'); label.innerHTML = group.content + ' '; container.insertAdjacentElement('afterBegin',label); - var hide = document.createElement('span'); + const hide = document.createElement('span'); hide.setAttribute("class", "oi oi-eye"); hide.addEventListener('click',function(){ groups.update({id: group.id, visible: false}); @@ -24,23 +24,23 @@ }; // Generate some - var now = vis.moment() + const now = vis.moment() .minutes(0) .seconds(0) .milliseconds(0); - var names = ["John", "Alston", "Lee", "Grant"]; - var itemCount = 20; + const names = ["John", "Alston", "Lee", "Grant"]; + const itemCount = 20; // create a data set with groups - var groups = new vis.DataSet(); - for (var g = 0; g < names.length; g++) { + const groups = new vis.DataSet(); + for (let g = 0; g < names.length; g++) { groups.add({ id: g, content: names[g] }); } // create a dataset with items - var items = new vis.DataSet(); - for (var i = 0; i < itemCount; i++) { - var start = now.clone().add(Math.random() * 200, "hours"); - var end = start + 100000000; - var group = Math.floor(Math.random() * names.length); + const items = new vis.DataSet(); + for (let i = 0; i < itemCount; i++) { + const start = now.clone().add(Math.random() * 200, "hours"); + const end = start + 100000000; + const group = Math.floor(Math.random() * names.length); items.add({ id: i, group: group, @@ -67,7 +67,7 @@ /** *CREATING THE ARROWS */ - var dependency = [ + const dependency = [ { id: 2, id_item_1: 1, @@ -119,7 +119,7 @@ /*ANOTHER FUNCTIONS (NO IMPORTANT)*/ const showVisibleItems = function () { - var a = timelinevis.getVisibleItems(); + const a = timelinevis.getVisibleItems(); document.getElementById("visibleItemsContainer").innerHTML = "" document.getElementById("visibleItemsContainer").innerHTML += a; }; diff --git a/examples/followRelationships_True.js b/examples/followRelationships_True.js index dac73f7..339cef7 100644 --- a/examples/followRelationships_True.js +++ b/examples/followRelationships_True.js @@ -8,12 +8,12 @@ selectable: true, editable: true, groupTemplate: function(group) { //function to hide groups - var container = document.createElement('div'); - var label = document.createElement('span'); + const container = document.createElement('div'); + const label = document.createElement('span'); label.innerHTML = group.content + ' '; container.insertAdjacentElement('afterBegin',label); - var hide = document.createElement('span'); + const hide = document.createElement('span'); hide.setAttribute("class", "oi oi-eye"); hide.addEventListener('click',function(){ groups.update({id: group.id, visible: false}); @@ -24,23 +24,23 @@ }; // Generate some - var now = vis.moment() + const now = vis.moment() .minutes(0) .seconds(0) .milliseconds(0); - var names = ["John", "Alston", "Lee", "Grant"]; - var itemCount = 20; + const names = ["John", "Alston", "Lee", "Grant"]; + const itemCount = 20; // create a data set with groups - var groups = new vis.DataSet(); - for (var g = 0; g < names.length; g++) { + const groups = new vis.DataSet(); + for (let g = 0; g < names.length; g++) { groups.add({ id: g, content: names[g] }); } // create a dataset with items - var items = new vis.DataSet(); - for (var i = 0; i < itemCount; i++) { - var start = now.clone().add(Math.random() * 200, "hours"); - var end = start + 100000000; - var group = Math.floor(Math.random() * names.length); + const items = new vis.DataSet(); + for (let i = 0; i < itemCount; i++) { + const start = now.clone().add(Math.random() * 200, "hours"); + const end = start + 100000000; + const group = Math.floor(Math.random() * names.length); items.add({ id: i, group: group, @@ -67,7 +67,7 @@ /** *CREATING THE ARROWS */ - var dependency = [ + const dependency = [ { id: 2, id_item_1: 1, @@ -119,7 +119,7 @@ /*ANOTHER FUNCTIONS (NO IMPORTANT)*/ const showVisibleItems = function () { - var a = timelinevis.getVisibleItems(); + const a = timelinevis.getVisibleItems(); document.getElementById("visibleItemsContainer").innerHTML = "" document.getElementById("visibleItemsContainer").innerHTML += a; }; diff --git a/index.html b/index.html index babafa9..951dc93 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ - + Timeline-arrows diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c1c0b3b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "timeline-arrows", + "version": "4.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "timeline-arrows", + "version": "4.1.0", + "license": "MIT", + "devDependencies": { + "typescript": "^5.0.4" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + } + } +} diff --git a/package.json b/package.json index 41f7296..d1b1420 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "4.1.1", "description": "Package to easily draw lines to connect items in the vis Timeline module.", "main": "arrow.js", + "types": "arrow.d.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "generateTypes": "tsc --allowJs -d --emitDeclarationOnly --lib es2015,dom arrow.js", + "prepack": "npm run generateTypes" }, "repository": { "type": "git", @@ -19,5 +22,8 @@ "bugs": { "url": "https://github.com/javdome/timeline-arrows/issues" }, - "homepage": "https://github.com/javdome/timeline-arrows#readme" + "homepage": "https://github.com/javdome/timeline-arrows#readme", + "devDependencies": { + "typescript": "^5.0.4" + } }