diff --git a/packages/docs/docs/.vitepress/configs/components.mts b/packages/docs/docs/.vitepress/configs/components.mts index c260fcacfc..8493f45d8b 100644 --- a/packages/docs/docs/.vitepress/configs/components.mts +++ b/packages/docs/docs/.vitepress/configs/components.mts @@ -7,13 +7,11 @@ export const components = { items: [ { text: 'MazBtn', link: '/components/maz-btn' }, { text: 'MazCheckbox', link: '/components/maz-checkbox' }, - { text: 'MazDropzone', link: '/components/maz-dropzone' }, { text: 'MazInput', link: '/components/maz-input' }, { text: 'MazInputCode', link: '/components/maz-input-code' }, { text: 'MazInputNumber', link: '/components/maz-input-number' }, { text: 'MazInputPrice', link: '/components/maz-input-price' }, { text: 'MazInputTags', link: '/components/maz-input-tags' }, - { text: 'MazPicker', link: '/components/maz-picker' }, { text: 'MazPhoneNumberInput', link: '/components/maz-phone-number-input' }, { text: 'MazRadio', link: '/components/maz-radio' }, { text: 'MazRadioButtons', link: '/components/maz-radio-buttons' }, @@ -23,6 +21,14 @@ export const components = { { text: 'MazTextarea', link: '/components/maz-textarea' }, ] }, + { + text: 'Data', + items: [ + { text: 'MazDropzone', link: '/components/maz-dropzone' }, + { text: 'MazPicker', link: '/components/maz-picker' }, + { text: 'MazTable (data-table)', link: '/components/maz-table' }, + ] + }, { text: 'UI', items: [ @@ -43,6 +49,7 @@ export const components = { { text: 'MazGallery', link: '/components/maz-gallery' }, { text: 'MazIcon', link: '/components/maz-icon' }, { text: 'MazLazyImg', link: '/components/maz-lazy-img' }, + { text: 'MazLoadingBar', link: '/components/maz-loading-bar' }, { text: 'MazPullToRefresh', link: '/components/maz-pull-to-refresh' }, { text: 'MazStepper', link: '/components/maz-stepper' }, { text: 'MazSpinner', link: '/components/maz-spinner' }, diff --git a/packages/docs/docs/components/competitions.ts b/packages/docs/docs/components/competitions.ts new file mode 100644 index 0000000000..cc7e109689 --- /dev/null +++ b/packages/docs/docs/components/competitions.ts @@ -0,0 +1,145 @@ +export const competitions = [ + { + id: '0262672d-7c7a-4d30-866e-edb88b5a5336', + name: 'UEFA Champions League', + code: 'CL', + type: 'CUP', + areaName: 'Europe', + matchday: 6, + logoUrl: 'https://crests.football-data.org/CL.png', + groups: 1, + index: 1, + }, + { + id: '08d15e97-a319-4772-9b82-f1877369b40f', + name: 'Premier League', + code: 'PL', + type: 'LEAGUE', + areaName: 'England', + matchday: 18, + logoUrl: 'https://crests.football-data.org/PL.png', + groups: 1, + index: 2, + }, + { + id: '17e62396-bbcb-42f5-acff-caed11534976', + name: 'Serie A', + code: 'SA', + type: 'LEAGUE', + areaName: 'Italy', + matchday: 17, + logoUrl: 'https://crests.football-data.org/SA.png', + groups: 0, + index: 3, + }, + { + id: '3726264e-ba3a-4a9f-b4a4-8fc33e12747c', + name: 'FIFA World Cup', + code: 'WC', + type: 'CUP', + areaName: 'World', + matchday: 8, + logoUrl: 'https://crests.football-data.org/qatar.png', + groups: 1, + index: 4, + }, + { + id: '555dc3f4-e592-46af-b634-59f07a201f2e', + name: 'Primeira Liga', + code: 'PPL', + type: 'LEAGUE', + areaName: 'Portugal', + matchday: 15, + logoUrl: 'https://crests.football-data.org/PPL.png', + groups: 0, + index: 5, + }, + { + id: '59bbdfa0-86d8-4a74-b701-435747c55a42', + name: 'Primera Division', + code: 'PD', + type: 'LEAGUE', + areaName: 'Spain', + matchday: 18, + logoUrl: 'https://crests.football-data.org/PD.png', + groups: 1, + index: 6, + }, + { + id: '6ae53332-3d27-4781-912d-d9c4e69657f9', + name: 'Ligue 1', + code: 'FL1', + type: 'LEAGUE', + areaName: 'France', + matchday: 17, + logoUrl: 'https://crests.football-data.org/FL1.png', + groups: 4, + index: 7, + }, + { + id: '747c79ee-89c8-436a-b0ea-53f05f180007', + name: 'European Championship', + code: 'EC', + type: 'CUP', + areaName: 'Europe', + matchday: 1, + logoUrl: 'https://crests.football-data.org/EUR.svg', + groups: 1, + index: 8, + }, + { + id: '7a32d897-6b22-4212-8ffe-049ae912c346', + name: 'Eredivisie', + code: 'DED', + type: 'LEAGUE', + areaName: 'Netherlands', + matchday: 18, + logoUrl: 'https://crests.football-data.org/ED.png', + groups: 0, + index: 9, + }, + { + id: 'ab57e2dc-272c-45e6-b13e-57617a13b753', + name: 'Championship', + code: 'ELC', + type: 'LEAGUE', + areaName: 'England', + matchday: 23, + logoUrl: 'https://crests.football-data.org/ELC.png', + groups: 0, + index: 10, + }, + { + id: 'b84e3295-7315-46c7-b979-6d9d784e5460', + name: 'Campeonato Brasileiro Série A', + code: 'BSA', + type: 'LEAGUE', + areaName: 'Brazil', + matchday: 38, + logoUrl: 'https://crests.football-data.org/764.svg', + groups: 0, + index: 11, + }, + { + id: 'cafad3ce-1783-4652-9248-4bcad024dd98', + name: 'Copa Libertadores', + code: 'CLI', + type: 'CUP', + areaName: 'South America', + matchday: 11, + logoUrl: 'https://crests.football-data.org/CLI.svg', + groups: 0, + index: 12, + }, + { + id: 'ed945bea-9a58-450a-8d62-7baa7722b5e7', + name: 'Bundesliga', + code: 'BL1', + type: 'LEAGUE', + areaName: 'Germany', + matchday: 16, + logoUrl: 'https://crests.football-data.org/BL1.png', + groups: 0, + index: 13, + }, +] diff --git a/packages/docs/docs/components/maz-loading-bar.md b/packages/docs/docs/components/maz-loading-bar.md new file mode 100644 index 0000000000..a1ca0a0a14 --- /dev/null +++ b/packages/docs/docs/components/maz-loading-bar.md @@ -0,0 +1,26 @@ +--- +title: MazLoadingBar +description: MazLoadingBar is a standalone component +--- + +# {{ $frontmatter.title }} + +{{ $frontmatter.description }} + + + +## Basic usage + + + +```vue + + + +``` + + diff --git a/packages/docs/docs/components/maz-table.md b/packages/docs/docs/components/maz-table.md new file mode 100644 index 0000000000..ea612d2dad --- /dev/null +++ b/packages/docs/docs/components/maz-table.md @@ -0,0 +1,441 @@ +--- +title: MazTable +description: MazTable is designed to be a reusable data table with advanced features. Pagination, Search, Column Sorting, Row Selection, UI options, Loading and Slots. +--- + +# {{ $frontmatter.title }} + +{{ $frontmatter.description }} + + + +## Key Features + +1. Pagination (prop `pagination`) + * The component supports pagination with buttons to go to the first, previous, next, and last page. + * You can display only the pagination elements (input and buttons) and make API calls to your server to get elements by using the prop `pagination` with `no-paginate-rows`. +2. Search (prop `search`): It includes a search feature with a search bar where users can enter a query to filter displayed data. You can choose the column where the search will be activated. +3. Column Sorting (prop: `sortable`): Columns are sortable, indicated by arrow icons. Sorting can be activated by clicking on the column header. +4. Row Selection (prop `select-value="key"`): There is a dedicated column for selection with a checkbox for each row. Users can individually or collectively select/deselect rows. +5. Customizable Page Size: Users can choose the number of items to display per page using a dropdown list. +6. Loading Indicator (prop `loading`): A loading indicator (MazLoadingBar) is displayed when data is being loaded. + +## Available models + +* v-model: `(string | boolean | number)[] | undefined` (list of selected key) +* v-model:search-query: `string | undefined` +* v-model:page: `number` +* v-model:page-size: `number` + +## Basic usage + +You can use MazTable and his child component to build a simple table and enjoy the style. + + + + + 1 + + + John + + + Doe + + + 99 + + + + + 2 + + + Doe + + + John + + + 30 + + + + +::: details Show code + +```vue + + + +``` + +::: + +## Advanced + +You can also provide all your data, the table is auto-generated and you can use the features [listed on top](#key-features) + +--- + +`v-model="{{selectedIds ?? 'undefined'}}"` +
+`v-model:search-query="{{searchQuery ?? 'undefined'}}"` +
+`v-model:page="{{page ?? 'undefined'}}"` +
+`v-model:page-size="{{pageSize ?? 'undefined'}}"` + + + + + + + + + +::: details Show code + +```vue + + + +``` + +::: + +## Loading + + + + + 1 + + + John + + + Doe + + + 99 + + + + + + +## Props & Events emitted + +## MazTable + + + +## MazTableCell + + + +## MazTableRow + + + +## MazTableTitle + + + + diff --git a/packages/lib/components/MazGallery.vue b/packages/lib/components/MazGallery.vue index b128e095a5..49caabb5c6 100644 --- a/packages/lib/components/MazGallery.vue +++ b/packages/lib/components/MazGallery.vue @@ -52,7 +52,7 @@ @@ -60,7 +60,7 @@ + + diff --git a/packages/lib/components/MazTable.vue b/packages/lib/components/MazTable.vue new file mode 100644 index 0000000000..1d53e61551 --- /dev/null +++ b/packages/lib/components/MazTable.vue @@ -0,0 +1,816 @@ + + + + + diff --git a/packages/lib/components/MazTableCell.vue b/packages/lib/components/MazTableCell.vue new file mode 100644 index 0000000000..c4799e182e --- /dev/null +++ b/packages/lib/components/MazTableCell.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/packages/lib/components/MazTableRow.vue b/packages/lib/components/MazTableRow.vue new file mode 100644 index 0000000000..30aa75356b --- /dev/null +++ b/packages/lib/components/MazTableRow.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/packages/lib/components/MazTableTitle.vue b/packages/lib/components/MazTableTitle.vue new file mode 100644 index 0000000000..94d5eb993f --- /dev/null +++ b/packages/lib/components/MazTableTitle.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/packages/lib/components/index.ts b/packages/lib/components/index.ts index 870c67341b..bd6fd062d1 100644 --- a/packages/lib/components/index.ts +++ b/packages/lib/components/index.ts @@ -35,6 +35,11 @@ export { default as MazSlider } from './MazSlider.vue' export { default as MazSpinner } from './MazSpinner.vue' export { default as MazStepper } from './MazStepper.vue' export { default as MazSwitch } from './MazSwitch.vue' +export { default as MazTable } from './MazTable.vue' +export { default as MazTableCell } from './MazTableCell.vue' +export { default as MazTableRow } from './MazTableRow.vue' +export { default as MazTableTitle } from './MazTableTitle.vue' +export { default as MazLoadingBar } from './MazLoadingBar.vue' export { default as MazTabs } from './MazTabs.vue' export { default as MazTabsBar } from './MazTabsBar.vue' export { default as MazTabsContent } from './MazTabsContent.vue' diff --git a/packages/lib/modules/types/shims-vue.d.ts b/packages/lib/modules/types/shims-vue.d.ts index 28b0633f27..b6b4f86c6a 100644 --- a/packages/lib/modules/types/shims-vue.d.ts +++ b/packages/lib/modules/types/shims-vue.d.ts @@ -1,5 +1,5 @@ -declare module '*.vue' { - import type { DefineComponent } from 'vue' - const component: DefineComponent, Record, unknown> - export default component -} +// declare module '*.vue' { +// import type { DefineComponent } from 'vue' +// const component: DefineComponent, Record, unknown> +// export default component +// } diff --git a/packages/lib/tests/specs/components/maz-btn.spec.ts b/packages/lib/tests/specs/components/maz-btn.spec.ts index 4ef59ceea8..d7ee5334a8 100644 --- a/packages/lib/tests/specs/components/maz-btn.spec.ts +++ b/packages/lib/tests/specs/components/maz-btn.spec.ts @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils' describe('MazBtn', () => { test('renders the component elements and classes correctly', () => { - const wrapper = shallowMount(MazBtn) + const wrapper = shallowMount(MazBtn, { slots: { default: 'Button Text' } }) expect(wrapper.find('button').exists()).toBe(true) expect(wrapper.find('.m-btn__icon-left').exists()).toBe(false) diff --git a/packages/lib/tests/specs/components/maz-loading-bar.spec.ts b/packages/lib/tests/specs/components/maz-loading-bar.spec.ts new file mode 100644 index 0000000000..0c70caf4df --- /dev/null +++ b/packages/lib/tests/specs/components/maz-loading-bar.spec.ts @@ -0,0 +1,10 @@ +import { mount } from '@vue/test-utils' +import MazLoadingBar from '@components/MazLoadingBar.vue' + +describe('MazLoadingBar', () => { + test('renders default color correctly', () => { + const wrapper = mount(MazLoadingBar) + expect(wrapper.vm.colorCSVariables.alpha).toBe('var(--maz-color-primary-alpha-20)') + expect(wrapper.vm.colorCSVariables.main).toBe('var(--maz-color-primary)') + }) +}) diff --git a/packages/lib/tests/specs/components/maz-table.spec.ts b/packages/lib/tests/specs/components/maz-table.spec.ts new file mode 100644 index 0000000000..a9459cf88d --- /dev/null +++ b/packages/lib/tests/specs/components/maz-table.spec.ts @@ -0,0 +1,121 @@ +import { mount } from '@vue/test-utils' +import MazTable from '@components/MazTable.vue' +import { MazCheckbox, MazLoadingBar } from '@components/index' + +describe('MazTable', () => { + test('should render the component', async () => { + const wrapper = mount(MazTable, { + props: { + sortable: true, + pagination: true, + search: true, + selectedKey: 'id', + headers: [ + { label: 'Id', key: 'id' }, + { label: 'Firstname', key: 'firstname' }, + { label: 'Lastname', key: 'lastname' }, + { label: 'Age', key: 'age' }, + { label: 'City', key: 'city' }, + ], + caption: 'This is a caption', + rows: [ + { + id: 1, + firstname: 'John', + lastname: 'Doe', + age: 25, + city: 'New York', + }, + { + id: 2, + firstname: 'Jane', + lastname: 'Doe', + age: 22, + city: 'Paris', + }, + { + id: 3, + firstname: 'John', + lastname: 'Smith', + age: 32, + city: 'London', + }, + { + id: 4, + firstname: 'Jane', + lastname: 'Smith', + age: 28, + city: 'Tokyo', + }, + ], + }, + }) + + let loadingBar = wrapper.findComponent(MazLoadingBar) + + expect(loadingBar.exists()).toBe(false) + + await wrapper.setProps({ loading: true }) + + loadingBar = wrapper.findComponent(MazLoadingBar) + expect(loadingBar.isVisible()).toBe(true) + + const checkbox = wrapper.findComponent(MazCheckbox) + + expect(checkbox.exists()).toBe(true) + + wrapper.vm.allSelected = true + + expect(wrapper.emitted('update:model-value')[0]).toStrictEqual([[1, 2, 3, 4]]) + + await wrapper.findAll('thead tr th')[3].trigger('click') + + expect(wrapper.vm.rowsFiltered).toStrictEqual([ + { + age: 32, + city: 'London', + firstname: 'John', + id: 3, + lastname: 'Smith', + selected: true, + }, + { + age: 28, + city: 'Tokyo', + firstname: 'Jane', + id: 4, + lastname: 'Smith', + selected: true, + }, + { + age: 25, + city: 'New York', + firstname: 'John', + id: 1, + lastname: 'Doe', + selected: true, + }, + { + age: 22, + city: 'Paris', + firstname: 'Jane', + id: 2, + lastname: 'Doe', + selected: true, + }, + ]) + + wrapper.vm.searchQueryModel = 'Tokyo' + + expect(wrapper.vm.rowsFiltered).toStrictEqual([ + { + age: 28, + city: 'Tokyo', + firstname: 'Jane', + id: 4, + lastname: 'Smith', + selected: true, + }, + ]) + }) +}) diff --git a/packages/lib/tests/tsconfig.json b/packages/lib/tests/tsconfig.json index 0ebe0f2b49..d0462a1a01 100644 --- a/packages/lib/tests/tsconfig.json +++ b/packages/lib/tests/tsconfig.json @@ -1,14 +1,13 @@ { + "extends": ["./../node_modules/@vue/tsconfig/tsconfig.dom.json"], "compilerOptions": { - "types": ["vitest/globals"], + "types": ["vitest/globals", "vue"], "baseUrl": ".", - "target": "ESNext", - "moduleResolution": "node", "paths": { "@modules/*": ["./../modules/*"], "@components/*": ["./../components/*"], "@tests/*": ["./../tests/*"] } }, - "include": ["./../types/*", "./**/*", "./../components/**/*", "./../modules/**/*"] + "include": ["./../types/*", "**/*", "./../components/**/*", "./../modules/**/*"] } diff --git a/packages/lib/vitest.config.mts b/packages/lib/vitest.config.mts index e758e9beba..82514c4631 100644 --- a/packages/lib/vitest.config.mts +++ b/packages/lib/vitest.config.mts @@ -24,7 +24,6 @@ export default defineConfig({ // inline: ['vitest-canvas-mock'], // }, // }, - // threads: false, globalSetup: './vitest-global.setup.ts', environment: 'jsdom', environmentOptions: {