diff --git a/eslint.config.js b/eslint.config.js index 8727377..582b800 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,7 +5,15 @@ import globals from "globals" import typescriptEslint from "typescript-eslint" export default typescriptEslint.config( - { ignores: ["*.d.ts", "**/coverage", "**/dist", "assets/", "src/dev.ts"] }, + { + ignores: [ + "**/*.d.ts", + "**/coverage", + "**/dist", + "assets/", + "src/dev.ts", + ], + }, { extends: [ eslint.configs.recommended, diff --git a/src/components/ActionButtons/ActionButtons.ts b/src/components/ActionButtons/ActionButtons.ts index acc2eb4..c0de8ec 100644 --- a/src/components/ActionButtons/ActionButtons.ts +++ b/src/components/ActionButtons/ActionButtons.ts @@ -13,6 +13,7 @@ export default defineComponent({ }, data: Object, }, + emits: ["userEvent"], methods: { triggerAction(action: string) { this.$emit("userEvent", { action: action, data: this.data }) diff --git a/src/components/DataTable.ts b/src/components/DataTable.ts index 9645a13..05258f9 100644 --- a/src/components/DataTable.ts +++ b/src/components/DataTable.ts @@ -16,6 +16,7 @@ import { parseColumnProps, parseTextProps } from "../parser" import { defineComponent, reactive } from "vue" import { SORTING_MODE } from "../const" +import type { Column, Data } from "../types" export default defineComponent({ name: "VueDataTable", @@ -72,6 +73,8 @@ export default defineComponent({ vKey: { type: String, default: "" }, }, + emits: ["userEvent"], + data: () => { return reactive({ dataFetched: [] as Column[], @@ -361,6 +364,7 @@ export default defineComponent({ lastPage, ] } + throw new Error('INVALID PAGE RANGE') }, // ───────────────────────────────────────────────────────────────────── @@ -662,12 +666,12 @@ export default defineComponent({ * Set the current rows per page */ setPerPage(value: any) { - let previousFirstEntry, newPerPage, newCurrentPage + let newPerPage, newCurrentPage + const previousFirstEntry = this.firstEntry // before updating the value of currentPerPage, // we need to store the current firstEntry. // We will use it to change the current page. - previousFirstEntry = this.firstEntry newPerPage = this.currentPerPage if (!this.perPageSizes.includes(newPerPage)) { diff --git a/src/components/Pagination/Pagination.ts b/src/components/Pagination/Pagination.ts index 1acfe25..20957ca 100644 --- a/src/components/Pagination/Pagination.ts +++ b/src/components/Pagination/Pagination.ts @@ -15,6 +15,7 @@ export default defineComponent({ nextPage: Number, pagination: Array, }, + emits: ["set-page"], setup() { return { pageToGo: 1 } }, diff --git a/src/components/PerPage/PerPage.ts b/src/components/PerPage/PerPage.ts index 5187cb8..b1af2ac 100644 --- a/src/components/PerPage/PerPage.ts +++ b/src/components/PerPage/PerPage.ts @@ -8,6 +8,7 @@ export default defineComponent({ currentPerPage: { type: [Number, String], required: true }, perPageSizes: { type: Array, required: true }, }, + emits: ["set-per-page"], computed: { textBeforeOptions() { return (this.perPageText.split(":entries")[0] || "").trim() diff --git a/src/components/SearchFilter/SearchFilter.ts b/src/components/SearchFilter/SearchFilter.ts index c332898..4eab932 100644 --- a/src/components/SearchFilter/SearchFilter.ts +++ b/src/components/SearchFilter/SearchFilter.ts @@ -3,4 +3,5 @@ import { defineComponent } from "vue" export default defineComponent({ name: "VdtSearchFilter", props: { searchText: String, search: String }, + emits: ["set-search"], }) diff --git a/src/components/Table/Table.ts b/src/components/Table/Table.ts index 900f7c0..e374070 100644 --- a/src/components/Table/Table.ts +++ b/src/components/Table/Table.ts @@ -17,6 +17,7 @@ export default defineComponent({ sortingIconComponent: [Object, String], sortingIndexComponent: [Object, String], }, + emits: ["user-event", "sort-column"], methods: { // Propagate upwards an event from a user custom component emitUserEvent(payload: any) { diff --git a/src/components/Table/TableCellEditable.ts b/src/components/Table/TableCellEditable.ts index c6792a4..cc1c57c 100644 --- a/src/components/Table/TableCellEditable.ts +++ b/src/components/Table/TableCellEditable.ts @@ -6,6 +6,7 @@ export default defineComponent({ data: { type: Object, required: true }, columnKey: { type: String, required: true }, }, + emits: ["userEvent"], data: () => { return reactive({ isEditing: false, text: "" }) }, diff --git a/src/components/Table/TableCellSelectable.ts b/src/components/Table/TableCellSelectable.ts index 3b010e9..f959d26 100644 --- a/src/components/Table/TableCellSelectable.ts +++ b/src/components/Table/TableCellSelectable.ts @@ -3,6 +3,7 @@ import { defineComponent, reactive } from "vue" export default defineComponent({ name: "VdtTableCellSelectable", props: { data: { type: Object, required: true } }, + emits: ["userEvent"], data: () => { return reactive({ selected: false }) }, diff --git a/src/const.ts b/src/const.ts index 06ecb33..52b25d8 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,3 +1,5 @@ +import type { ColumnType, SortingMode } from "./types" + export const SORTING_MODE = { ASC: "asc", DESC: "desc", NONE: "none" } as { [key: string]: SortingMode } diff --git a/src/demo/App.ts b/src/demo/App.ts index 0fe27f3..bc65867 100644 --- a/src/demo/App.ts +++ b/src/demo/App.ts @@ -132,7 +132,7 @@ export default { methods: { updateUserField(user: User, field: UserField, value: any) { - const ind = this.data.findIndex(u => u.id === user.id) + const ind = this.data.findIndex((u: any) => u.id === user.id) if (ind < 0) return const newUser = { ...this.data[ind] } newUser[field] = value diff --git a/src/lang.ts b/src/lang.ts index fcc83f8..1a234a5 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -6,6 +6,13 @@ import en from "./lang/en" import es from "./lang/es" import ptBr from "./lang/pt-br" +import type { + LanguageDict, + LanguageDictKey, + LanguageDictVal, + LanguageName, + Translation, +} from "./types" const translations = { "pt-br": ptBr, "en": en, "es": es } as Translation @@ -26,5 +33,4 @@ const languageServiceProvider = { }, } -export default translations -export { languageServiceProvider, translations } +export { languageServiceProvider, translations, translations as default } diff --git a/src/lang/en.ts b/src/lang/en.ts index 10611a8..21b9055 100644 --- a/src/lang/en.ts +++ b/src/lang/en.ts @@ -1,3 +1,5 @@ +import type { LanguageDict } from "../types" + export default { perPageText: "Show :entries entries", perPageAllText: "ALL", diff --git a/src/lang/es.ts b/src/lang/es.ts index 49e29c8..6ef8c16 100644 --- a/src/lang/es.ts +++ b/src/lang/es.ts @@ -1,3 +1,5 @@ +import type { LanguageDict } from "../types" + export default { perPageText: "Mostrando :entries datos", perPageAllText: "TODOS", diff --git a/src/lang/pt-br.ts b/src/lang/pt-br.ts index 3a6cade..62d71f1 100644 --- a/src/lang/pt-br.ts +++ b/src/lang/pt-br.ts @@ -1,3 +1,5 @@ +import type { LanguageDict } from "../types" + export default { perPageText: "Exibindo :entries dados", perPageAllText: "TODOS", diff --git a/src/parser/index.ts b/src/parser/index.ts index 4d5e130..4566eb6 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -1,12 +1,10 @@ -// import VdtTableCell from "../components/Table/TableCell.vue" -// import VdtTableCellEditable from "../components/Table/TableCellEditable.vue" import { searchNumericColumn, searchStringColumn, toTitleCase } from "../utils" import { SORTING_MODE } from "../const" import translations from "../lang" +import type { Column, ColumnType, LanguageDict, LanguageName } from "../types" // default column to all instances of VDT export const globalDefaultColumn = { - // component: VdtTableCell, component: "vdt-cell", componentProps: {}, displayIndex: 1000, diff --git a/src/types.d.ts b/src/types.d.ts index 4749c21..bcb5f58 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -1,12 +1,12 @@ // ───────────────────────────────────────────────────────────────────────────── // TYPE DEFINITIONS -type VueComponent = string | any -type VueComponentProps = { [key: string]: any } +export type VueComponent = string | any +export type VueComponentProps = { [key: string]: any } -type SortingMode = "asc" | "desc" | "none" -type ColumnType = "numeric" | "string" | "array" | "other" -type Column = { +export type SortingMode = "asc" | "desc" | "none" +export type ColumnType = "numeric" | "string" | "array" | "other" +export type Column = { compareFunction: Function component: VueComponent componentProps: VueComponentProps @@ -25,8 +25,8 @@ type Column = { type: string } -type LanguageName = string -type LanguageDictKey = +export type LanguageName = string +export type LanguageDictKey = | "downloadButtonText" | "downloadText" | "emptyTableText" @@ -40,9 +40,9 @@ type LanguageDictKey = | "perPageAllText" | "previousButtonText" | "searchText" -type LanguageDictVal = string -type LanguageDict = Record -type Translation = Record +export type LanguageDictVal = string +export type LanguageDict = Record +export type Translation = Record -type Cell = { [key: string]: any } -type Data = Cell[] +export type Cell = { [key: string]: any } +export type Data = Cell[] diff --git a/src/utils.ts b/src/utils.ts index 22633ba..ea2be9c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,5 @@ +import type { Cell, Column, Data } from "./types" + export function toTitleCase(str: string): string { // convert snake case to title case str = str.replace(/_/g, " ") @@ -85,7 +87,7 @@ export function arraySafeSort(array: T[], compareFunction: Function): T[] { } // Sort an array of objects (representing the table) by the given column -export function sortDataByColumns(data: Data, columns: Column[]) { +export function sortDataByColumns(data: Data, columns: Column[]): Data { const l = columns.length const fn = (a: any, b: any) => { @@ -144,6 +146,10 @@ export function searchStringColumn(data: Cell, search: string, key: string) { } // Performs search on numeric values -export function searchNumericColumn(data: Cell, search: string, key: string) { +export function searchNumericColumn( + data: Cell, + search: string, + key: string +): boolean { return (data[key] || "").toString().includes(search) } diff --git a/tests/common.ts b/tests/common.ts index a3f1f0a..7d7fcf7 100644 --- a/tests/common.ts +++ b/tests/common.ts @@ -62,7 +62,9 @@ const CustomComponent2 = defineComponent({ // mount the component export const wrapper = mount(VueDataTable, { - global: { components: { ...components, CustomComponent1 } }, + global: { + components: { ...components, CustomComponent1, CustomComponent2 }, + }, props: { data: data, columns: [{ key: "name" }, { key: "gender" }, { key: "job" }], diff --git a/tests/sorting.test.ts b/tests/sorting.test.ts index ec72709..ebb9a16 100644 --- a/tests/sorting.test.ts +++ b/tests/sorting.test.ts @@ -9,10 +9,15 @@ import { testRowsMatchData, wrapper, } from "./common" +import { DOMWrapper } from "@vue/test-utils" test("it sorts data", async () => { - const keys = ["name", "gender", "job"] as any - let c, copy, key: any, i + const keys = ["name", "gender", "job"] + let key: string + let copy: any[] + let i: number + let c: DOMWrapper + for (i = 0; i < keys.length; i += 1) { key = keys[i] c = col(i + 1) @@ -35,7 +40,7 @@ test("it sorts data", async () => { }) test("it sorts only one column", async () => { - let arr + let arr: any[] // sets the sorting mode await wrapper.setProps({ sortingMode: "single" }) @@ -98,7 +103,7 @@ test("it sorts filtered data", async () => { test("it sorts multiple rows", async () => { // copy the data - let copy + let copy: any[] // sort by second column, then by third column await click(col(2)) diff --git a/tests/utils.test.ts b/tests/utils.test.ts index eeab2d6..999d8ff 100644 --- a/tests/utils.test.ts +++ b/tests/utils.test.ts @@ -15,7 +15,7 @@ test("test string replacement", function () { test("test safe sort", function () { let arr = [2, 45, null, 10, 20, null, 15] - let res + let res: (number | null)[] let f: Function = (a: any, b: any) => a - b let g: Function = (a: any, b: any) => b - a res = arraySafeSort(arr, f)