diff --git a/components/accordion/Accordion.spec.js b/components/accordion/Accordion.spec.js index e721b6e7c..398f41fbe 100644 --- a/components/accordion/Accordion.spec.js +++ b/components/accordion/Accordion.spec.js @@ -1,6 +1,6 @@ import { mount } from '@vue/test-utils'; -import Accordion from '../accordion/Accordion.vue'; -import AccordionTab from '../accordiontab/AccordionTab.vue'; +import Accordion from '@/components/accordion/Accordion.vue'; +import AccordionTab from '@/components/accordiontab/AccordionTab.vue'; describe('Accordion.vue', () => { let wrapper; diff --git a/components/accordion/Accordion.vue b/components/accordion/Accordion.vue index 9d96e3d72..f0427c3e9 100755 --- a/components/accordion/Accordion.vue +++ b/components/accordion/Accordion.vue @@ -40,8 +40,8 @@ diff --git a/components/contextmenu/ContextMenu.d.ts b/components/contextmenu/ContextMenu.d.ts index bd701e204..219515f7a 100755 --- a/components/contextmenu/ContextMenu.d.ts +++ b/components/contextmenu/ContextMenu.d.ts @@ -1,6 +1,6 @@ import { VNode } from 'vue'; -import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers'; import { MenuItem } from '../menuitem'; +import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers'; type ContextMenuAppendTo = 'body' | 'self' | string | undefined | HTMLElement; @@ -34,6 +34,18 @@ export interface ContextMenuProps { * Default value is true. */ exact?: boolean | undefined; + /** + * Index of the element in tabbing order. + */ + tabindex?: number | string | undefined; + /** + * Defines a string value that labels an interactive element. + */ + 'aria-label'?: string | undefined; + /** + * Identifier of the underlying menu element. + */ + 'aria-labelledby'?: string | undefined; } export interface ContextMenuSlots { @@ -49,7 +61,34 @@ export interface ContextMenuSlots { }) => VNode[]; } -export declare type ContextMenuEmits = {}; +export declare type ContextMenuEmits = { + /** + * Callback to invoke when the component receives focus. + * @param {Event} event - Browser event. + */ + focus: (event: Event) => void; + /** + * Callback to invoke when the component loses focus. + * @param {Event} event - Browser event. + */ + blur: (event: Event) => void; + /** + * Callback to invoke before the popup is shown. + */ + 'before-show': () => void; + /** + * Callback to invoke before the popup is hidden. + */ + 'before-hide': () => void; + /** + * Callback to invoke when the popup is shown. + */ + show: () => void; + /** + * Callback to invoke when the popup is hidden. + */ + hide: () => void; +}; declare class ContextMenu extends ClassComponent { /** diff --git a/components/contextmenu/ContextMenu.spec.js b/components/contextmenu/ContextMenu.spec.js index 035d2ae36..389ef344c 100644 --- a/components/contextmenu/ContextMenu.spec.js +++ b/components/contextmenu/ContextMenu.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import PrimeVue from '../config/PrimeVue'; +import PrimeVue from 'primevue/config'; import ContextMenu from './ContextMenu.vue'; describe('ContextMenu.vue', () => { @@ -147,7 +147,7 @@ describe('ContextMenu.vue', () => { it('should exist', async () => { const event = { pageX: 100, pageY: 120, preventDefault: () => {}, stopPropagation: () => {} }; - const show = vi.spyOn(wrapper.vm, 'show'); + const show = jest.spyOn(wrapper.vm, 'show'); wrapper.vm.show(event); await wrapper.setData({ visible: true }); @@ -159,7 +159,7 @@ describe('ContextMenu.vue', () => { }); it('should hide menu', async () => { - const hide = vi.spyOn(wrapper.vm, 'hide'); + const hide = jest.spyOn(wrapper.vm, 'hide'); await wrapper.setData({ visible: true }); diff --git a/components/contextmenu/ContextMenu.vue b/components/contextmenu/ContextMenu.vue index d32ca8674..e7502abb0 100755 --- a/components/contextmenu/ContextMenu.vue +++ b/components/contextmenu/ContextMenu.vue @@ -1,21 +1,46 @@ diff --git a/components/datatable/DataTable.d.ts b/components/datatable/DataTable.d.ts index 2e1a58dae..7e9f62a09 100755 --- a/components/datatable/DataTable.d.ts +++ b/components/datatable/DataTable.d.ts @@ -1,6 +1,5 @@ -import { VNode } from 'vue'; +import { InputHTMLAttributes, TableHTMLAttributes, VNode } from 'vue'; import { ClassComponent, GlobalComponentConstructor, Nullable } from '../ts-helpers'; -import Column from '../column'; import { VirtualScrollerProps } from '../virtualscroller'; type DataTablePaginatorPositionType = 'top' | 'bottom' | 'both' | undefined; @@ -511,7 +510,7 @@ export interface DataTableProps { * - JumpToPageInput * - CurrentPageReport */ - paginatorTemplate?: string | undefined; + paginatorTemplate?: any | string; /** * Number of page links to display. * Default value is 5. @@ -685,7 +684,7 @@ export interface DataTableProps { /** * One or more field names to use in row grouping. */ - groupRowsBy?: string[] | string | undefined; + groupRowsBy?: (field: string) => object | string[] | string | undefined; /** * Whether the row groups can be expandable. */ @@ -776,6 +775,14 @@ export interface DataTableProps { * Style class of the table element. */ tableClass?: any; + /** + * Uses to pass all properties of the TableHTMLAttributes to table element inside the component. + */ + tableProps?: TableHTMLAttributes | undefined; + /** + * Uses to pass all properties of the HTMLInputElement to the focusable filter input element inside the component. + */ + filterInputProps?: InputHTMLAttributes | undefined; } export interface DataTableSlots { diff --git a/components/datatable/DataTable.spec.js b/components/datatable/DataTable.spec.js index 0d251d2c3..0fafeabd7 100644 --- a/components/datatable/DataTable.spec.js +++ b/components/datatable/DataTable.spec.js @@ -1,11 +1,12 @@ +import Button from '@/components/button/Button.vue'; +import Column from '@/components/column/Column.vue'; +import ColumnGroup from '@/components/columngroup/ColumnGroup.vue'; +import InputText from '@/components/inputtext/InputText.vue'; +import Row from '@/components/row/Row.vue'; import { mount } from '@vue/test-utils'; -import DataTable from './DataTable.vue'; -import ColumnGroup from '../columngroup/ColumnGroup.vue'; -import Row from '../row/Row.vue'; -import Column from '../column/Column.vue'; -import Button from '../button/Button.vue'; -import InputText from '../inputtext/InputText.vue'; import { FilterMatchMode } from 'primevue/api'; +import PrimeVue from 'primevue/config'; +import DataTable from './DataTable.vue'; window.URL.createObjectURL = function () {}; @@ -86,6 +87,7 @@ describe('DataTable.vue', () => { beforeEach(() => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column, Button @@ -284,6 +286,7 @@ describe('DataTable.vue', () => { it('should single sort', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -301,7 +304,7 @@ describe('DataTable.vue', () => { const sortableTH = wrapper.findAll('.p-sortable-column')[0]; const firstCellText = wrapper.findAll('.p-datatable-tbody > tr')[0].findAll('td')[1].text(); - const headerClick = vi.spyOn(wrapper.vm, 'onColumnHeaderClick'); + const headerClick = jest.spyOn(wrapper.vm, 'onColumnHeaderClick'); await sortableTH.trigger('click'); @@ -315,6 +318,7 @@ describe('DataTable.vue', () => { it('should multiple sort', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -333,7 +337,7 @@ describe('DataTable.vue', () => { const sortableTHs = wrapper.findAll('.p-sortable-column'); const firstCellText = wrapper.findAll('.p-datatable-tbody > tr')[0].findAll('td')[1].text(); - const headerClick = vi.spyOn(wrapper.vm, 'onColumnHeaderClick'); + const headerClick = jest.spyOn(wrapper.vm, 'onColumnHeaderClick'); await sortableTHs[0].trigger('click'); @@ -355,6 +359,7 @@ describe('DataTable.vue', () => { it('should have presort', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -381,6 +386,7 @@ describe('DataTable.vue', () => { it('should remove sort', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -509,6 +515,7 @@ describe('DataTable.vue', () => { it('should select when radiobutton selection is enabled', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -544,6 +551,7 @@ describe('DataTable.vue', () => { it('should select when checkbox selection is enabled', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -577,6 +585,7 @@ describe('DataTable.vue', () => { it('should select all rows', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -603,6 +612,7 @@ describe('DataTable.vue', () => { it('should unselect all rows', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -663,6 +673,7 @@ describe('DataTable.vue', () => { wrapper = null; wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -719,6 +730,7 @@ describe('DataTable.vue', () => { it('should init row editing', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column, InputText @@ -759,6 +771,7 @@ describe('DataTable.vue', () => { it('should save row editing', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column, InputText @@ -795,6 +808,7 @@ describe('DataTable.vue', () => { it('should cancel row editing', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column, InputText @@ -832,6 +846,7 @@ describe('DataTable.vue', () => { it('should fit mode expanding exists', () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -857,6 +872,7 @@ describe('DataTable.vue', () => { it('should fit mode resize start', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -885,6 +901,7 @@ describe('DataTable.vue', () => { it('should fit mode resize', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -910,6 +927,7 @@ describe('DataTable.vue', () => { it('should fit mode column resize end', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -939,6 +957,7 @@ describe('DataTable.vue', () => { it('should expand mode resize start', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -967,6 +986,7 @@ describe('DataTable.vue', () => { it('should fit mode resize', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -992,6 +1012,7 @@ describe('DataTable.vue', () => { it('should fit mode column resize end', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1030,6 +1051,7 @@ describe('DataTable.vue', () => { it('should exist', () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1054,6 +1076,7 @@ describe('DataTable.vue', () => { it('should exist', () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1085,6 +1108,7 @@ describe('DataTable.vue', () => { it('should have groupheader templating', () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1115,6 +1139,7 @@ describe('DataTable.vue', () => { it('should have groupfooter templating', () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1145,6 +1170,7 @@ describe('DataTable.vue', () => { it('should have expandable row groups and expand rows', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1270,6 +1296,7 @@ describe('DataTable.vue', () => { it('should have rowspan grouping', async () => { wrapper = mount(DataTable, { global: { + plugins: [PrimeVue], components: { Column } @@ -1338,7 +1365,7 @@ describe('DataTable.vue', () => { // export it('should export table', async () => { - const exportCSV = vi.spyOn(wrapper.vm, 'exportCSV'); + const exportCSV = jest.spyOn(wrapper.vm, 'exportCSV'); await wrapper.vm.exportCSV(); @@ -1355,8 +1382,8 @@ describe('DataTable.vue', () => { }); it('should save session storage', async () => { - vi.spyOn(window.sessionStorage.__proto__, 'setItem'); - window.sessionStorage.__proto__.setItem = vi.fn(); + jest.spyOn(window.sessionStorage.__proto__, 'setItem'); + window.sessionStorage.__proto__.setItem = jest.fn(); await wrapper.vm.saveState(); @@ -1365,8 +1392,8 @@ describe('DataTable.vue', () => { }); it('should save local storage', async () => { - vi.spyOn(window.localStorage.__proto__, 'setItem'); - window.localStorage.__proto__.setItem = vi.fn(); + jest.spyOn(window.localStorage.__proto__, 'setItem'); + window.localStorage.__proto__.setItem = jest.fn(); await wrapper.vm.saveState(); diff --git a/components/datatable/DataTable.vue b/components/datatable/DataTable.vue index 22885afc1..bf34932d9 100755 --- a/components/datatable/DataTable.vue +++ b/components/datatable/DataTable.vue @@ -31,7 +31,7 @@
diff --git a/components/datatable/RowCheckbox.vue b/components/datatable/RowCheckbox.vue index 4f805aa2f..ac22a3767 100755 --- a/components/datatable/RowCheckbox.vue +++ b/components/datatable/RowCheckbox.vue @@ -1,24 +1,19 @@ diff --git a/components/fileupload/FileUpload.d.ts b/components/fileupload/FileUpload.d.ts index 8e3e4e105..adbe9aea2 100755 --- a/components/fileupload/FileUpload.d.ts +++ b/components/fileupload/FileUpload.d.ts @@ -87,6 +87,17 @@ export interface FileUploadRemoveEvent { files: File[]; } +export interface FileUploadRemoveUploadedFile { + /** + * Removed file. + */ + file: File; + /** + * Remaining files to be uploaded. + */ + files: File[]; +} + export interface FileUploadProps { /** * Name of the request parameter to identify the files at backend. @@ -202,7 +213,61 @@ export interface FileUploadProps { export interface FileUploadSlots { /** - * Custom empty template. + * Custom header content template. + */ + header: (scope: { + /** + * Files to upload. + */ + files: File[]; + /** + * Uploaded files. + */ + uploadedFiles: File[]; + /** + * Choose function + */ + chooseCallback: () => void; + /** + * Upload function + */ + uploadCallback: () => void; + /** + * Clear function + */ + clearCallback: () => void; + }) => VNode[]; + /** + * Custom uploaded content template. + */ + content: (scope: { + /** + * Files to upload. + */ + files: File[]; + /** + * Uploaded files. + */ + uploadedFiles: File[]; + /** + * Function to remove an uploaded file. + */ + removeUploadedFileCallback: () => void; + /** + * Function to remove a file. + */ + removeFileCallback: () => void; + /** + * Uploaded progress as number. + */ + progress: number; + /** + * Status messages about upload process. + */ + messages: string | undefined; + }) => VNode[]; + /** + * Custom content when there is no selected file. */ empty: () => VNode[]; } @@ -252,6 +317,11 @@ export declare type FileUploadEmits = { * @param {FileUploadRemoveEvent} event - Custom remove event. */ remove: (event: FileUploadRemoveEvent) => void; + /** + * Callback to invoke when a single uploaded file is removed from the uploaded file list. + * @param {FileUploadRemoveUploadedFile} event - Custom uploaded file remove event. + */ + removeUploadedFile: (event: FileUploadRemoveUploadedFile) => void; }; declare class FileUpload extends ClassComponent {} diff --git a/components/fileupload/FileUpload.vue b/components/fileupload/FileUpload.vue index e842971c7..9f180880f 100755 --- a/components/fileupload/FileUpload.vue +++ b/components/fileupload/FileUpload.vue @@ -1,30 +1,24 @@ @@ -406,7 +674,7 @@ export default { top: 0; } -.p-megamenu-vertical .p-megamenu-root-list > .p-menuitem > .p-menuitem-link > .p-submenu-icon { +.p-megamenu-vertical .p-megamenu-root-list > .p-menuitem > .p-menuitem-content > .p-menuitem-link > .p-submenu-icon { margin-left: auto; } diff --git a/components/megamenu/MegaMenuSub.vue b/components/megamenu/MegaMenuSub.vue new file mode 100644 index 000000000..c7d741e68 --- /dev/null +++ b/components/megamenu/MegaMenuSub.vue @@ -0,0 +1,231 @@ + + + diff --git a/components/menu/Menu.d.ts b/components/menu/Menu.d.ts index 627544819..e72c4118b 100755 --- a/components/menu/Menu.d.ts +++ b/components/menu/Menu.d.ts @@ -1,6 +1,6 @@ import { VNode } from 'vue'; -import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers'; import { MenuItem } from '../menuitem'; +import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers'; type MenuAppendToType = 'body' | 'self' | string | undefined | HTMLElement; @@ -34,6 +34,18 @@ export interface MenuProps { * Default value is true. */ exact?: boolean | undefined; + /** + * Index of the element in tabbing order. + */ + tabindex?: number | string | undefined; + /** + * Defines a string value that labels an interactive element. + */ + 'aria-label'?: string | undefined; + /** + * Identifier of the underlying input element. + */ + 'aria-labelledby'?: string | undefined; } export interface MenuSlots { @@ -44,7 +56,18 @@ export interface MenuSlots { item: (scope: { item: MenuItem }) => VNode[]; } -export declare type MenuEmits = {}; +export declare type MenuEmits = { + /** + * Callback to invoke when the component receives focus. + * @param {Event} event - Browser event. + */ + focus: (event: Event) => void; + /** + * Callback to invoke when the component loses focus. + * @param {Event} event - Browser event. + */ + blur: (event: Event) => void; +}; declare class Menu extends ClassComponent { /** diff --git a/components/menu/Menu.spec.js b/components/menu/Menu.spec.js index 0fc9551e2..653d9d82a 100644 --- a/components/menu/Menu.spec.js +++ b/components/menu/Menu.spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import PrimeVue from '../config/PrimeVue'; +import PrimeVue from 'primevue/config'; import Menu from './Menu.vue'; describe('Menu.vue', () => { diff --git a/components/menu/Menu.vue b/components/menu/Menu.vue old mode 100755 new mode 100644 index 8f3402f97..e3c9e5817 --- a/components/menu/Menu.vue +++ b/components/menu/Menu.vue @@ -1,20 +1,32 @@