From 58facc56d55640f64b34455b6f484bc23916458b Mon Sep 17 00:00:00 2001 From: "Ghislain B." Date: Sat, 19 Oct 2024 14:05:49 -0400 Subject: [PATCH] feat: allow providing a Custom Pagination Component (#420) * feat: allow providing a Custom Pagination Component --- src/favicon.ico => favicon.ico | Bin favicon.svg | 15 -- index.html | 2 +- package.json | 28 +-- src/examples/slickgrid/App.tsx | 2 + src/examples/slickgrid/Example24.tsx | 2 +- .../slickgrid/Example42-Custom-Pager.scss | 67 ++++++ .../slickgrid/Example42-Custom-Pager.tsx | 160 +++++++++++++ src/examples/slickgrid/Example42.tsx | 222 ++++++++++++++++++ src/examples/slickgrid/example24.scss | 106 +++++---- .../components/slickgrid-react.tsx | 60 +++-- src/slickgrid-react/services/reactUtils.ts | 15 ++ test/cypress/e2e/example42.cy.ts | 80 +++++++ yarn.lock | 204 ++++++++-------- 14 files changed, 752 insertions(+), 211 deletions(-) rename src/favicon.ico => favicon.ico (100%) delete mode 100644 favicon.svg create mode 100644 src/examples/slickgrid/Example42-Custom-Pager.scss create mode 100644 src/examples/slickgrid/Example42-Custom-Pager.tsx create mode 100644 src/examples/slickgrid/Example42.tsx create mode 100644 src/slickgrid-react/services/reactUtils.ts create mode 100644 test/cypress/e2e/example42.cy.ts diff --git a/src/favicon.ico b/favicon.ico similarity index 100% rename from src/favicon.ico rename to favicon.ico diff --git a/favicon.svg b/favicon.svg deleted file mode 100644 index de4aeddc..00000000 --- a/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/index.html b/index.html index c9c3c07f..85e161c7 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ - + diff --git a/package.json b/package.json index 25fd8c03..281d94aa 100644 --- a/package.json +++ b/package.json @@ -83,13 +83,13 @@ "/src/slickgrid-react" ], "dependencies": { - "@slickgrid-universal/common": "~5.8.0", - "@slickgrid-universal/custom-footer-component": "~5.8.0", - "@slickgrid-universal/empty-warning-component": "~5.8.0", - "@slickgrid-universal/event-pub-sub": "~5.8.0", - "@slickgrid-universal/pagination-component": "~5.8.0", + "@slickgrid-universal/common": "~5.9.0", + "@slickgrid-universal/custom-footer-component": "~5.9.0", + "@slickgrid-universal/empty-warning-component": "~5.9.0", + "@slickgrid-universal/event-pub-sub": "~5.9.0", + "@slickgrid-universal/pagination-component": "~5.9.0", "dequal": "^2.0.3", - "i18next": "^23.16.0", + "i18next": "^23.16.1", "sortablejs": "^1.15.3" }, "devDependencies": { @@ -100,13 +100,13 @@ "@formkit/tempo": "^0.1.2", "@popperjs/core": "^2.11.8", "@release-it/conventional-changelog": "^9.0.0", - "@slickgrid-universal/composite-editor-component": "~5.8.0", - "@slickgrid-universal/custom-tooltip-plugin": "~5.8.0", - "@slickgrid-universal/excel-export": "~5.8.0", - "@slickgrid-universal/graphql": "~5.8.0", - "@slickgrid-universal/odata": "~5.8.0", - "@slickgrid-universal/rxjs-observable": "~5.8.0", - "@slickgrid-universal/text-export": "~5.8.0", + "@slickgrid-universal/composite-editor-component": "~5.9.0", + "@slickgrid-universal/custom-tooltip-plugin": "~5.9.0", + "@slickgrid-universal/excel-export": "~5.9.0", + "@slickgrid-universal/graphql": "~5.9.0", + "@slickgrid-universal/odata": "~5.9.0", + "@slickgrid-universal/rxjs-observable": "~5.9.0", + "@slickgrid-universal/text-export": "~5.9.0", "@types/dompurify": "^3.0.5", "@types/fnando__sparkline": "^0.3.7", "@types/i18next-xhr-backend": "^1.4.2", @@ -115,7 +115,7 @@ "@types/react-dom": "^18.3.1", "@types/sortablejs": "^1.15.8", "@types/text-encoding-utf-8": "^1.0.5", - "@vitejs/plugin-react": "^4.3.2", + "@vitejs/plugin-react": "^4.3.3", "bootstrap": "^5.3.3", "concurrently": "^9.0.1", "copyfiles": "^2.4.1", diff --git a/src/examples/slickgrid/App.tsx b/src/examples/slickgrid/App.tsx index c84a945c..ff79bf35 100644 --- a/src/examples/slickgrid/App.tsx +++ b/src/examples/slickgrid/App.tsx @@ -41,6 +41,7 @@ import Example38 from './Example38'; import Example39 from './Example39'; import Example40 from './Example40'; import Example41 from './Example41'; +import Example42 from './Example42'; const routes: Array<{ path: string; route: string; component: any; title: string; }> = [ { path: 'example1', route: '/example1', component: , title: '1- Basic Grid / 2 Grids' }, @@ -82,6 +83,7 @@ const routes: Array<{ path: string; route: string; component: any; title: string { path: 'example39', route: '/example39', component: , title: '39- Infinite Scroll with GraphQL' }, { path: 'example40', route: '/example40', component: , title: '40- Infinite Scroll from JSON data' }, { path: 'example41', route: '/example41', component: , title: '41- Drag & Drop' }, + { path: 'example42', route: '/example42', component: , title: '42- Custom Pagination' }, ]; export default function Routes() { diff --git a/src/examples/slickgrid/Example24.tsx b/src/examples/slickgrid/Example24.tsx index bb8c339c..25d2178f 100644 --- a/src/examples/slickgrid/Example24.tsx +++ b/src/examples/slickgrid/Example24.tsx @@ -579,7 +579,7 @@ class Example24 extends React.Component { render() { return !this.state.gridOptions ? '' : ( -
+

{this.title} diff --git a/src/examples/slickgrid/Example42-Custom-Pager.scss b/src/examples/slickgrid/Example42-Custom-Pager.scss new file mode 100644 index 00000000..b04f2be3 --- /dev/null +++ b/src/examples/slickgrid/Example42-Custom-Pager.scss @@ -0,0 +1,67 @@ +@use 'sass:color'; + +.custom-pagination { + display: flex; + justify-content: flex-end; + margin: 10px; + font-size: 13px; + + .custom-pagination-settings { + display: inline-flex; + align-items: center; + margin-right: 30px; + + .item-from, + .item-to, + .total-items { + margin: 0 4px; + } + } + + .custom-pagination-nav { + display: flex; + align-items: center; + list-style-type: none; + + .page-item { + display: flex; + width: 26px; + justify-content: center; + margin: 0; + &.disabled .pagination-link { + color: rgb(180, 179, 179); + background-color: rgb(180, 179, 179); + } + } + + .page-number { + .page-number { + margin: 0 4px; + padding: 0 5px; + display: inline-flex; + justify-content: center; + width: 20px; + } + } + + .page-count { + margin: 0 4px; + } + + nav { + ul.custom-pagination-ul { + display: flex; + margin: 0; + padding: 0 5px; + color: #0d6efd; + + .pagination-link { + color: #0d6efd; + &:hover { + color: color.adjust(#0d6efd, $lightness: 10%); + } + } + } + } + } +} diff --git a/src/examples/slickgrid/Example42-Custom-Pager.tsx b/src/examples/slickgrid/Example42-Custom-Pager.tsx new file mode 100644 index 00000000..78e770db --- /dev/null +++ b/src/examples/slickgrid/Example42-Custom-Pager.tsx @@ -0,0 +1,160 @@ +import type { BasePaginationComponent, PaginationMetadata, PaginationService, PubSubService, SlickGrid, Subscription } from '@slickgrid-universal/common'; +import React from 'react'; + +import './Example42-Custom-Pager.scss'; + +interface Props { } +interface State { + currentPagination: PaginationMetadata; + isLeftPaginationDisabled: boolean; + isRightPaginationDisabled: boolean; +} + +/** Custom Pagination Componnet, please note that you MUST `implements BasePaginationComponent` with required functions */ +export class CustomPagerComponent extends React.Component implements BasePaginationComponent { + protected _elm?: HTMLDivElement | null; + protected _grid!: SlickGrid; + protected _paginationElement!: HTMLDivElement; + protected _paginationService!: PaginationService; + protected _pubSubService!: PubSubService; + protected _subscriptions: Subscription[] = []; + + constructor(public readonly props: Props) { + super(props); + this.state = { + currentPagination: {} as PaginationMetadata, + isLeftPaginationDisabled: false, + isRightPaginationDisabled: false + }; + } + + init(grid: SlickGrid, paginationService: PaginationService, pubSubService: PubSubService) { + this._grid = grid; + this._paginationService = paginationService; + this._pubSubService = pubSubService; + const currentPagination = this._paginationService.getFullPagination(); + this.setState((props: Props, state: any) => { + return { + ...state, + currentPagination, + isLeftPaginationDisabled: this.checkLeftPaginationDisabled(currentPagination), + isRightPaginationDisabled: this.checkRightPaginationDisabled(currentPagination) + } + }); + + // Anytime the pagination is initialized or has changes, + // we'll copy the data into a local object so that we can add binding to this local object + this._subscriptions.push( + this._pubSubService.subscribe('onPaginationRefreshed', paginationChanges => { + this.setState((props: Props, state: any) => { + return { + ...state, + currentPagination: paginationChanges, + isLeftPaginationDisabled: this.checkLeftPaginationDisabled(paginationChanges), + isRightPaginationDisabled: this.checkRightPaginationDisabled(paginationChanges) + } + }); + }) + ); + } + + /** + * dispose (unmount), please note that `componentWillUnmount()` will NOT be called and `dispose()` is the only one that will be called + * (because Slickgrid-Universal only deals with `dispose()` and also to avoid conflicts between the 2 methods) + */ + dispose() { + this._pubSubService.unsubscribeAll(this._subscriptions); + this._paginationElement.remove(); + } + + renderPagination() { + this._paginationElement = this._elm as HTMLDivElement; + this._paginationElement.id = 'pager'; + this._paginationElement.className = `custom-pagination pager ${this._grid.getUID()}`; + this._paginationElement.style.width = '100%'; + } + + onFirstPageClicked(event: any): void { + if (!this.checkLeftPaginationDisabled(this.state.currentPagination)) { + this._paginationService.goToFirstPage(event); + } + } + + onLastPageClicked(event: any): void { + if (!this.checkRightPaginationDisabled(this.state.currentPagination)) { + this._paginationService.goToLastPage(event); + } + } + + onNextPageClicked(event: any): void { + if (!this.checkRightPaginationDisabled(this.state.currentPagination)) { + this._paginationService.goToNextPage(event); + } + } + + onPreviousPageClicked(event: any): void { + if (!this.checkLeftPaginationDisabled(this.state.currentPagination)) { + this._paginationService.goToPreviousPage(event); + } + } + + protected checkLeftPaginationDisabled(currentPagination: PaginationMetadata): boolean { + return currentPagination.pageNumber === 1 || currentPagination.totalItems === 0; + } + + protected checkRightPaginationDisabled(currentPagination: PaginationMetadata): boolean { + return currentPagination.pageNumber === currentPagination.pageCount || currentPagination.totalItems === 0; + } + + render() { + return ( +
this._elm = elm}> + + + + + {this.state.currentPagination.dataFrom} + - + + {this.state.currentPagination.dataTo} + + of + + + {this.state.currentPagination.totalItems} + items + + + +
+ +
+ Page + {this.state.currentPagination.pageNumber} + of + {this.state.currentPagination.pageCount} +
+ +
+
+ ); + } +} diff --git a/src/examples/slickgrid/Example42.tsx b/src/examples/slickgrid/Example42.tsx new file mode 100644 index 00000000..9a7e60aa --- /dev/null +++ b/src/examples/slickgrid/Example42.tsx @@ -0,0 +1,222 @@ +import React from 'react'; +import { + type Column, + FieldType, + Filters, + Formatters, + type GridOption, + type MultipleSelectOption, + OperatorType, + type Pagination, + SlickgridReact, + type SlickgridReactInstance, + type SliderRangeOption, +} from '../../slickgrid-react'; + +import { CustomPagerComponent } from './Example42-Custom-Pager'; +import type BaseSlickGridState from './state-slick-grid-base'; + +const NB_ITEMS = 5000; + +interface Props { } +interface State extends BaseSlickGridState { + pageSize: number, +} + +function randomBetween(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1) + min); +} + +export default class Example42 extends React.Component { + paginationPosition: 'bottom' | 'top' = 'top'; + paginationOptions!: Pagination; + reactGrid!: SlickgridReactInstance; + + constructor(public readonly props: Props) { + super(props); + + this.state = { + gridOptions: undefined, + columnDefinitions: [], + dataset: this.loadData(NB_ITEMS), + pageSize: 50, + }; + } + + componentDidMount() { + this.defineGrid(); + } + + reactGridReady(reactGrid: SlickgridReactInstance) { + this.reactGrid = reactGrid; + } + + getColumnsDefinition(): Column[] { + return [ + { + id: 'title', name: 'Title', field: 'id', minWidth: 100, + sortable: true, + filterable: true, + formatter: (_row, _cell, val) => `Task ${val}`, + params: { useFormatterOuputToFilter: true } + }, + { + id: 'description', name: 'Description', field: 'description', filterable: true, sortable: true, minWidth: 80, + type: FieldType.string, + }, + { + id: 'percentComplete', name: '% Complete', field: 'percentComplete', minWidth: 120, + customTooltip: { position: 'center' }, + sortable: true, + type: FieldType.number, + formatter: Formatters.progressBar, + filterable: true, + filter: { + model: Filters.sliderRange, + maxValue: 100, // or you can use the filterOptions as well + operator: OperatorType.rangeInclusive, // defaults to inclusive + filterOptions: { + hideSliderNumbers: false, // you can hide/show the slider numbers on both side + min: 0, step: 5 + } as SliderRangeOption + } + }, + { + id: 'start', name: 'Start', field: 'start', formatter: Formatters.dateIso, sortable: true, minWidth: 75, width: 100, exportWithFormatter: true, + type: FieldType.date, filterable: true, filter: { model: Filters.compoundDate } + }, + { + id: 'finish', name: 'Finish', field: 'finish', formatter: Formatters.dateIso, sortable: true, minWidth: 75, width: 120, exportWithFormatter: true, + type: FieldType.date, + filterable: true, + filter: { + model: Filters.dateRange, + } + }, + { + id: 'duration', field: 'duration', name: 'Duration', maxWidth: 90, + type: FieldType.number, + sortable: true, + filterable: true, + filter: { + model: Filters.input, + operator: OperatorType.rangeExclusive // defaults to exclusive + } + }, + { + id: 'completed', name: 'Completed', field: 'completed', minWidth: 85, maxWidth: 90, + formatter: Formatters.checkmarkMaterial, + exportWithFormatter: true, // you can set this property in the column definition OR in the grid options, column def has priority over grid options + filterable: true, + filter: { + collection: [{ value: '', label: '' }, { value: true, label: 'True' }, { value: false, label: 'False' }], + model: Filters.singleSelect, + filterOptions: { autoAdjustDropHeight: true } as MultipleSelectOption + } + } + ]; + } + + defineGrid() { + const columnDefinitions = this.getColumnsDefinition(); + const gridOptions = this.getGridOptions(); + + this.setState((props: Props, state: any) => { + return { + ...state, + columnDefinitions, + gridOptions + }; + }); + } + + getGridOptions(): GridOption { + return { + autoResize: { + container: '#demo-container', + bottomPadding: 20 // add a padding to include our custom pagination + }, + enableExcelCopyBuffer: true, + enableFiltering: true, + customPaginationComponent: CustomPagerComponent, // load our Custom Pagination Component + enablePagination: true, + pagination: { + pageSize: this.state.pageSize + }, + rowHeight: 40, + }; + } + + loadData(itemCount: number): any[] { + // mock a dataset + const tempDataset: any[] = []; + for (let i = 0, ln = itemCount; i < ln; i++) { + const randomDuration = randomBetween(0, 365); + const randomYear = randomBetween(new Date().getFullYear(), new Date().getFullYear() + 1); + const randomMonth = randomBetween(0, 12); + const randomDay = randomBetween(10, 28); + const randomPercent = randomBetween(0, 100); + + tempDataset.push({ + id: i, + title: 'Task ' + i, + description: (i % 5) ? 'desc ' + i : null, // also add some random to test NULL field + duration: randomDuration, + percentComplete: randomPercent, + percentCompleteNumber: randomPercent, + start: (i % 4) ? null : new Date(randomYear, randomMonth, randomDay), // provide a Date format + finish: new Date(randomYear, randomMonth, randomDay), + completed: (randomPercent === 100) ? true : false, + }); + } + + return tempDataset; + } + + pageSizeChanged(pageSize: number | string) { + this.setState((props: Props, state: any) => { + return { ...state, pageSize: +pageSize } + }); + this.reactGrid.paginationService?.changeItemPerPage(+pageSize); + } + + render() { + return !this.state.gridOptions ? '' : ( +
+
+

+ Example 42: Custom Pagination + + see  + + code + + +

+ +
+
+ You can create a Custom Pagination by passing a React Custom Component and it must implements BasePaginationComponent. + Any of the pagination controls could be moved anywhere on the page (for example we purposely moved the page size away from the rest of the pagination elements). +
+
+ +
+ + Page Size  + this.pageSizeChanged(($event.target as HTMLInputElement).value)} /> + +
+ + this.reactGridReady($event.detail)} + /> +
+
+ ); + } +} diff --git a/src/examples/slickgrid/example24.scss b/src/examples/slickgrid/example24.scss index b8675f92..aa18fdf8 100644 --- a/src/examples/slickgrid/example24.scss +++ b/src/examples/slickgrid/example24.scss @@ -1,64 +1,66 @@ -.bold { - font-weight: bold; -} - -.italic { - font-style: italic; -} +.grid24 { + .bold { + font-weight: bold; + } -.grey { - color: grey; -} + .italic { + font-style: italic; + } -.orange { - color: orange; -} + .grey { + color: grey; + } -.red { - color: red; -} + .orange { + color: orange; + } -.yellow { - color: rgb(255, 235, 52); -} + .red { + color: red; + } -.pointer { - cursor: pointer; -} + .yellow { + color: rgb(255, 235, 52); + } -.cell-menu-dropdown-outline { - border: 1px solid #a0a0a0; - border-radius: 4px; - width: max-content; - padding: 2px 14px; - cursor: pointer; - &:hover:not(.disabled) { - background-color: #a3a3a3; - color: #ffffff; + .pointer { + cursor: pointer; } - .mdi-caret-down { - margin-left: 5px; + + .cell-menu-dropdown-outline { + border: 1px solid #a0a0a0; + border-radius: 4px; + width: max-content; + padding: 2px 14px; + cursor: pointer; + &:hover:not(.disabled) { + background-color: #a3a3a3; + color: #ffffff; + } + &.disabled { + color: #d4d4d4; + border: 1px solid #d8d8d8; + } + .mdi-caret-down { + margin-left: 5px; + } } -} -.disabled { - color: #d4d4d4; - border: 1px solid #d8d8d8; -} -.slick-dark-mode { - .disabled { - border: 1px solid #616161; - color: #686868; + .slick-dark-mode { + .disabled { + border: 1px solid #616161; + color: #686868; + } } -} -.fake-hyperlink { - cursor: pointer; - color: #08c; -} -.row.locale { - margin-top: 5px; -} -span.cell-menu { - margin-left: 15px; + .fake-hyperlink { + cursor: pointer; + color: #08c; + } + .row.locale { + margin-top: 5px; + } + span.cell-menu { + margin-left: 15px; + } } diff --git a/src/slickgrid-react/components/slickgrid-react.tsx b/src/slickgrid-react/components/slickgrid-react.tsx index 32c26562..5b59d6cd 100644 --- a/src/slickgrid-react/components/slickgrid-react.tsx +++ b/src/slickgrid-react/components/slickgrid-react.tsx @@ -1,13 +1,10 @@ -// import 3rd party vendor libs -import i18next from 'i18next'; -import React from 'react'; - import { // interfaces/types type AutocompleterEditor, type BackendService, type BackendServiceApi, type BackendServiceOption, + type BasePaginationComponent, type Column, type DataViewOption, type EventSubscription, @@ -18,8 +15,8 @@ import { type Locale, type Metrics, type Pagination, + type PaginationMetadata, type SelectEditor, - type ServicePagination, SlickDataView, SlickEventHandler, SlickGrid, @@ -56,18 +53,18 @@ import { SlickFooterComponent } from '@slickgrid-universal/custom-footer-compone import { SlickEmptyWarningComponent } from '@slickgrid-universal/empty-warning-component'; import { SlickPaginationComponent } from '@slickgrid-universal/pagination-component'; import { extend } from '@slickgrid-universal/utils'; - import { dequal } from 'dequal/lite'; +import i18next from 'i18next'; +import React from 'react'; +import type { Subscription } from 'rxjs'; + import { Constants } from '../constants'; import { GlobalGridOptions } from '../global-grid-options'; import type { SlickgridReactInstance, GridOption, } from '../models/index'; -import { - disposeAllSubscriptions, - TranslaterService, -} from '../services/index'; -import type { Subscription } from 'rxjs'; - +import { disposeAllSubscriptions } from '../services/utilities'; import { GlobalContainerService } from '../services/singletons'; +import { loadReactComponentDynamically } from '../services/reactUtils'; +import { TranslaterService } from '../services/translater.service'; import type { SlickgridReactProps } from './slickgridReactProps'; const WARN_NO_PREPARSE_DATE_SIZE = 10000; // data size to warn user when pre-parse isn't enabled @@ -152,7 +149,7 @@ export class SlickgridReact extends React.Component extends React.Component extends React.Component extends React.Component extends React.Component extends React.Component('onPaginationChanged', paginationChanges => this.paginationChanged(paginationChanges)), - this._eventPubSubService.subscribe('onPaginationOptionsChanged', paginationChanges => this.paginationOptionsChanged(paginationChanges)), + this._eventPubSubService.subscribe('onPaginationChanged', paginationChanges => this.paginationChanged(paginationChanges)), + this._eventPubSubService.subscribe('onPaginationOptionsChanged', paginationChanges => this.paginationOptionsChanged(paginationChanges)), this._eventPubSubService.subscribe<{ visible: boolean; }>('onPaginationVisibilityChanged', (visibility: { visible: boolean }) => { this.showPagination = visibility?.visible ?? false; if (this.gridOptions?.backendServiceApi) { @@ -1250,11 +1247,22 @@ export class SlickgridReact extends React.Component(this.gridOptions.customPaginationComponent, paginationContainer); + this.slickPagination = component; + } else { + this.slickPagination = new SlickPaginationComponent(); + } + + if (this.slickPagination) { + this.slickPagination.init(this.grid, this.paginationService, this._eventPubSubService, this.props.translaterService); + this.slickPagination.renderPagination(this._elm as HTMLDivElement); + this._isPaginationInitialized = true; + } } else if (!showPagination) { this.slickPagination?.dispose(); this._isPaginationInitialized = false; @@ -1447,7 +1455,7 @@ export class SlickgridReact extends React.Component extends React.Component WARN_NO_PREPARSE_DATE_SIZE && !this.gridOptions.preParseDateColumns && this.grid.getColumns().some(c => isColumnDateType(c.type))) { + if (!this.gridOptions.silenceWarnings && this.dataView?.getItemCount() > WARN_NO_PREPARSE_DATE_SIZE && !this.gridOptions.preParseDateColumns && this.grid.getColumns().some(c => isColumnDateType(c.type))) { console.warn( '[Slickgrid-Universal] For getting better perf, we suggest you enable the `preParseDateColumns` grid option, ' + 'for more info visit => https://ghiscoding.gitbook.io/slickgrid-react/column-functionalities/sorting#pre-parse-date-columns-for-better-perf' diff --git a/src/slickgrid-react/services/reactUtils.ts b/src/slickgrid-react/services/reactUtils.ts new file mode 100644 index 00000000..42bd9b9c --- /dev/null +++ b/src/slickgrid-react/services/reactUtils.ts @@ -0,0 +1,15 @@ +import React from 'react'; +import { createRef } from 'react'; +import { createRoot, type Root } from 'react-dom/client'; + +export function loadReactComponentDynamically(customComponent: any, targetElm: HTMLElement, props?: any, root?: Root | null): Promise<{ component: T, root: Root }> { + return new Promise(resolve => { + const compRef = createRef(); + root ??= createRoot(targetElm); + root.render(React.createElement(customComponent, { ...props, ref: compRef })); + + queueMicrotask(() => { + resolve({ component: compRef.current as T, root: root as Root }); + }); + }); +} diff --git a/test/cypress/e2e/example42.cy.ts b/test/cypress/e2e/example42.cy.ts new file mode 100644 index 00000000..6d09398c --- /dev/null +++ b/test/cypress/e2e/example42.cy.ts @@ -0,0 +1,80 @@ +describe('Example 42 - Custom Pagination', () => { + const GRID_ROW_HEIGHT = 40; + const titles = ['Title', 'Description', '% Complete', 'Start', 'Finish', 'Duration', 'Completed']; + + it('should display Example title', () => { + cy.visit(`${Cypress.config('baseUrl')}/example42`); + cy.get('h2').should('contain', 'Example 42: Custom Pagination'); + }); + + it('should have exact Column Titles in the grid', () => { + cy.get('.slick-header-columns') + .children() + .each(($child, index) => expect($child.text()).to.eq(titles[index])); + }); + + it('should expect first row to be Task 0', () => { + cy.get('.seek-first').should('have.class', 'disabled'); + cy.get('.seek-prev').should('have.class', 'disabled'); + cy.get('.item-from').should('contain', 1); + cy.get('.item-to').should('contain', 50); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 1'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 2'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4'); + }); + + it('should click on next page and expect top row to be Task 50', () => { + cy.get('.page-item.seek-next').click(); + + cy.get('.seek-first').should('not.have.class', 'disabled'); + cy.get('.seek-prev').should('not.have.class', 'disabled'); + cy.get('.item-from').should('contain', 51); + cy.get('.item-to').should('contain', 100); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 50'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 51'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 52'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 53'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 54'); + }); + + it('should click on goto last page and expect top row to be Task 50', () => { + cy.get('.page-item.seek-end').click(); + + cy.get('.seek-next').should('have.class', 'disabled'); + cy.get('.seek-end').should('have.class', 'disabled'); + cy.get('.item-from').should('contain', 4951); + cy.get('.item-to').should('contain', 5000); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4950'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4951'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4952'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4953'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4954'); + }); + + it('should change page size and expect pagination to be updated', () => { + cy.get('[data-test="page-size-input"]').type('{backspace}{backspace}75'); + cy.get('.seek-first').should('have.class', 'disabled'); + cy.get('.seek-prev').should('have.class', 'disabled'); + cy.get('.item-from').should('contain', 1); + cy.get('.item-to').should('contain', 75); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 1'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 2'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 4'); + }); + + it('should be able to goto next page', () => { + cy.get('.page-item.seek-next').click(); + + cy.get('.item-from').should('contain', 76); + cy.get('.item-to').should('contain', 150); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 75'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 76'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 77'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 78'); + cy.get(`[style="top: ${GRID_ROW_HEIGHT * 4}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 79'); + }); +}); diff --git a/yarn.lock b/yarn.lock index 909f700f..9d8cb69b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -465,10 +465,10 @@ dependencies: levn "^0.4.1" -"@excel-builder-vanilla/types@^3.0.7": - version "3.0.7" - resolved "https://registry.yarnpkg.com/@excel-builder-vanilla/types/-/types-3.0.7.tgz#15b951cea16f32bcaf1e6ec13d13c0fd69ac7211" - integrity sha512-WDvLaT5eHAQUHnOXFoMSfse3ePWZMros9TEbmG468iXm0Qmrft9bTIHUWo+VtLhJWVEx6XHN6LJHbpZ43EmPjw== +"@excel-builder-vanilla/types@^3.0.14": + version "3.0.14" + resolved "https://registry.yarnpkg.com/@excel-builder-vanilla/types/-/types-3.0.14.tgz#162fd36f21c100c4046903c0e11d335ed82c0de9" + integrity sha512-9gq9hPPdVGzz/3fESgVW6WlxienIxpr83QnGS364cRPmzxg3cZQewZvKns2DFYfLLMxBLH3L6PperVqInR+0ag== dependencies: fflate "^0.8.2" @@ -924,124 +924,124 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== -"@slickgrid-universal/binding@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/binding/-/binding-5.8.0.tgz#6cd883a46b21d5a8ed655263b6b8ed52de06a080" - integrity sha512-+XJEtey7Y0SHX4KYHFJyxxxG9BDME4MlNnyKRAq6zI8csGozNT5/b9pheS3gHD4ZrCWNuabczMxya+849+07lg== +"@slickgrid-universal/binding@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/binding/-/binding-5.9.0.tgz#c78948f323e26619efcad1fe360a15363b32fae8" + integrity sha512-u3tP6UMbDdG+bBuOrxajN18l/KI0qMN6QoMkY/JjFNgV9E/Iq/EYa0QafZyV6DJnwdQD2ZlBb2nBqFj1MEIP4w== -"@slickgrid-universal/common@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/common/-/common-5.8.0.tgz#d8877824b264201b867a55f843c59f872aca5505" - integrity sha512-9NU6PhxaoL4ZvsAS8piBwl4ROrPDkvANyGpCFxUpxSmo1I27sfnGdQXwKuTdISoLdewTBXTajEO/pr7HAOHA8A== +"@slickgrid-universal/common@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/common/-/common-5.9.0.tgz#c4238f6c47e47e5caf83f02bf553f2c38adb5adf" + integrity sha512-l3HlQB8zKhllhwg8kQuKi8+4Lozfe3mVoXJr6MUbiWX8gauYPy0ZTRO9gS+Y7LgxYJzNKuyzanGIbWYC6Dqogw== dependencies: - "@excel-builder-vanilla/types" "^3.0.7" + "@excel-builder-vanilla/types" "^3.0.14" "@formkit/tempo" "^0.1.2" - "@slickgrid-universal/binding" "~5.8.0" - "@slickgrid-universal/event-pub-sub" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/binding" "~5.9.0" + "@slickgrid-universal/event-pub-sub" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" "@types/sortablejs" "^1.15.8" "@types/trusted-types" "^2.0.7" autocompleter "^9.3.2" dequal "^2.0.3" - multiple-select-vanilla "^3.3.4" + multiple-select-vanilla "^3.3.7" sortablejs "^1.15.3" un-flatten-tree "^2.0.12" vanilla-calendar-pro "^2.9.10" -"@slickgrid-universal/composite-editor-component@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/composite-editor-component/-/composite-editor-component-5.8.0.tgz#8079c50a1ad3b41d756dafc9bcaeb9b7d5d71243" - integrity sha512-teJ6Z/qVnYVIUN/0Q/h/7OFdySAatrZVACOXc7EBLFgyrnD80FIYxLMui2P1xkZYLsHHOmJiTueQe/8l/agYxw== +"@slickgrid-universal/composite-editor-component@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/composite-editor-component/-/composite-editor-component-5.9.0.tgz#f588c34490c71b010e7bbfbb48046890b473f77b" + integrity sha512-ufmWDG7GWVvuOjTzbQVEr+gSrpkYmC8c8FMyWIvzUSkofwiljHK1SVqJ/maRqkNFhMwFmTdtlLw+ChLxtRlDOw== dependencies: - "@slickgrid-universal/binding" "~5.8.0" - "@slickgrid-universal/common" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/binding" "~5.9.0" + "@slickgrid-universal/common" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" -"@slickgrid-universal/custom-footer-component@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-footer-component/-/custom-footer-component-5.8.0.tgz#e17f4707edbd36338b6d11a10b980f9d965e2f8d" - integrity sha512-jyKIx/9wemcT1CCIHBv7HbemBPqfOK8izEQv+yd2CiwtdlhXVpnzD1qWO25Q1RpEWCN67sEdzXUVnQGmzHX5VQ== +"@slickgrid-universal/custom-footer-component@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-footer-component/-/custom-footer-component-5.9.0.tgz#68ecd03228f3c30d2c8d7af562430cb318eeeb40" + integrity sha512-yjQZXk7TTvlis7uoBFRrLOitd+FiV9z89czWjBOo+QyJ4hfwGFXrbsiQDJcx5DrjcjdltKpp0ia5ZDLgz1o+Lg== dependencies: "@formkit/tempo" "^0.1.2" - "@slickgrid-universal/binding" "~5.8.0" - "@slickgrid-universal/common" "~5.8.0" + "@slickgrid-universal/binding" "~5.9.0" + "@slickgrid-universal/common" "~5.9.0" -"@slickgrid-universal/custom-tooltip-plugin@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-tooltip-plugin/-/custom-tooltip-plugin-5.8.0.tgz#d6df06d6064644448c4e57b6301a717c83d22ea0" - integrity sha512-A5ff/R+S/zK6PHBWiyoyj3gvBEnhhiE1/nsyPkXwmR9lDJresnPkS3e/LVvvlcEe2kOkiNDC//XEyNIgsiOQEQ== +"@slickgrid-universal/custom-tooltip-plugin@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/custom-tooltip-plugin/-/custom-tooltip-plugin-5.9.0.tgz#2571e439b6b6371394599c6c91e9a8cb3af6a51b" + integrity sha512-6bTr1Zg2xsLIMZRKkmoWGlGa/EXKhJimNTHAfjb/hK2I0Kl9ODl72QMd6Dpm2WeH7Bg5mxFLzkSKr7sml1xYTw== dependencies: - "@slickgrid-universal/common" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/common" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" -"@slickgrid-universal/empty-warning-component@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/empty-warning-component/-/empty-warning-component-5.8.0.tgz#af41ef625d02519526524ba83f68b4e0c2499af7" - integrity sha512-fNhT1gJH45PcNISrE73220s7OqdPBHN9c6117Cc3mpu2uXj84iLUTgd66MkotglEnINketLCskolsdUCQ/zepA== +"@slickgrid-universal/empty-warning-component@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/empty-warning-component/-/empty-warning-component-5.9.0.tgz#153bb422e74c1cd6aaf2dfe87763344241bffe92" + integrity sha512-gjYgvDDhOMh0R4qV8/ZDaAw0eqISfc9a+5JKBzC284n0acgDuQRmWevtSjhV66pIrHTZ5MAQNlZoVsIabKOeTg== dependencies: - "@slickgrid-universal/common" "~5.8.0" + "@slickgrid-universal/common" "~5.9.0" -"@slickgrid-universal/event-pub-sub@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/event-pub-sub/-/event-pub-sub-5.8.0.tgz#7214f6256fa0059e2a693c67350d38cd4509ff54" - integrity sha512-77yuw4yDjRJ7zJJ8GMaTL4R1+9iMvIogT4rd7Hjc5sEH5aVLHNRK95Cgj/OaWa7SB+mlU0v0bTs22omgKbMAFg== +"@slickgrid-universal/event-pub-sub@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/event-pub-sub/-/event-pub-sub-5.9.0.tgz#47aa780d6ec3b1d40c63d38ffefbcf1207e32db1" + integrity sha512-KnpY/WCTIwm6jWrX2RDKmDb1ifT2u4xs+1CPGWOWY6qQ/J0Fl9Ah25sZj/mM20BZvmg5/oCu7c9F62TdSiU3Zg== dependencies: - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/utils" "~5.9.0" -"@slickgrid-universal/excel-export@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/excel-export/-/excel-export-5.8.0.tgz#cb667256814cf6773fd5bccc108274061676b3d5" - integrity sha512-sMWOOcdjmW9HnNVqY7/YIXceX6sGVJN1XDP2qHBOvZe7aOAd3d5/AUZyl6y3GVfy9dBgxQovsxsjQEDzCf3ZqA== +"@slickgrid-universal/excel-export@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/excel-export/-/excel-export-5.9.0.tgz#13c84991a7cc5dcbb552b56609471503b54b03a4" + integrity sha512-pakTTesp2YH6hni5sq0ZQkHSBJvbkUBIjWCaSDUwHZXcrTwHmVWPd55kzL9yabyZ3urbEmkvh0H1lAnegPei4Q== dependencies: - "@slickgrid-universal/common" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" - excel-builder-vanilla "^3.0.6" + "@slickgrid-universal/common" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" + excel-builder-vanilla "^3.0.14" -"@slickgrid-universal/graphql@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/graphql/-/graphql-5.8.0.tgz#cbc1e854d6faa7c532c45441ea986e621b42aa2b" - integrity sha512-OAu4KHdL9JZtwJ0l/47UTTh9VRcNdUF7/U5j4l1oWqxBXtuUonM3qDfVL1sL+3zO85EO8SgY8RWR3NMNV/0CQA== +"@slickgrid-universal/graphql@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/graphql/-/graphql-5.9.0.tgz#08f19fbbc33253bdff885f2bdb594777cb149d55" + integrity sha512-m/E08Q37Lg6JBscDqvcZO65ZZuTy2zBt+1iggq6RxufQdYwmZjoj7WpRUAeEOigAk0CtnxvYPdPP6FAfkGWSIQ== dependencies: - "@slickgrid-universal/common" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/common" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" -"@slickgrid-universal/odata@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/odata/-/odata-5.8.0.tgz#f598c6697dd9578dea2ad4df14526d114b251c43" - integrity sha512-KMyoc4EJB5x+rFelVrTcCrIx6BzmKCm57NQQ3B4uXkE6fQTpCOrT5jNQ79afle6/x5WLoWcKMMlaWFpcULYgkg== +"@slickgrid-universal/odata@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/odata/-/odata-5.9.0.tgz#31ae02047f2e489aa01db6421e95698d087733d2" + integrity sha512-llgrrNZhd66jwr4d8HtGPzK15m+W4nzNQ1tkNksTd5EHjD3FDJGB3bqFAdwv5aX0YRYgSC2l7dvTxfY50AVx/A== dependencies: - "@slickgrid-universal/common" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/common" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" -"@slickgrid-universal/pagination-component@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/pagination-component/-/pagination-component-5.8.0.tgz#dbf1e830f81f19d53602f087be9e9abbaeaf9826" - integrity sha512-2qwdEk+AHzq1yn9ZwPQwG6u8ljzaTSVjiYJxCXlfN6/+43IdlK6fhDkANcvAGEbFDHYDFoquT3/B971nUVerXw== +"@slickgrid-universal/pagination-component@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/pagination-component/-/pagination-component-5.9.0.tgz#c64d4a21a30795cd692ab6f0ac4fa190ac1e1356" + integrity sha512-8R2X9/CUujT4LGGGnq3tZt8qzbhxsGUKEKdWxgn+2WYm87gkH1Rcw4YXABRzM2B93P1US0tUmoRds1DrQ5TG4w== dependencies: - "@slickgrid-universal/binding" "~5.8.0" - "@slickgrid-universal/common" "~5.8.0" + "@slickgrid-universal/binding" "~5.9.0" + "@slickgrid-universal/common" "~5.9.0" -"@slickgrid-universal/rxjs-observable@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/rxjs-observable/-/rxjs-observable-5.8.0.tgz#d1ee8f46eb47ecd325a1635e6b08d473c7da4cb7" - integrity sha512-o7EK9wxoZ3WlI9cdAH3NGWQ4kl6YLR2g1fty1lX+iNq2/pBn0zapQURQoQu5rn0LCdpVmt6AgYVLjUbFjST5CQ== +"@slickgrid-universal/rxjs-observable@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/rxjs-observable/-/rxjs-observable-5.9.0.tgz#0efa6da06d9ddf94ae5e6e2d8513ddedecdcb512" + integrity sha512-tNyLV5NX26ZKFrMs0nmH+qHkI9tiTI3qHv1GcZmVbPKYDMoqo3DjZdkIQoNwNaI1MopArUv1QIcs/Rw9XnQRYg== dependencies: - "@slickgrid-universal/common" "~5.8.0" + "@slickgrid-universal/common" "~5.9.0" rxjs "^7.8.1" -"@slickgrid-universal/text-export@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/text-export/-/text-export-5.8.0.tgz#7ba1ffe6f683d2bef1e67af41304d52053919c57" - integrity sha512-Z6JUIMmkEdZRLxXsSr5Bv7IFq3HNckwbVEtk9fQbWZ1Eey2ClcpHe1IL/UJEXF+csRHGfaEmX8f2gfSEdwmqhQ== +"@slickgrid-universal/text-export@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/text-export/-/text-export-5.9.0.tgz#d26a7e6ab098b6893b533fd09751c27b6d559dfb" + integrity sha512-4g/mjESz3YtN+ysAz4B/cl1m6nvyiShRvqzowHIaHwwZdKkOTb6wvX03ftBiPwppVhFxY94m9cX1u1c6lKsoOg== dependencies: - "@slickgrid-universal/common" "~5.8.0" - "@slickgrid-universal/utils" "~5.8.0" + "@slickgrid-universal/common" "~5.9.0" + "@slickgrid-universal/utils" "~5.9.0" text-encoding-utf-8 "^1.0.2" -"@slickgrid-universal/utils@~5.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@slickgrid-universal/utils/-/utils-5.8.0.tgz#abc608d490a08d8c96fe49b74b7e9df2b8e5a668" - integrity sha512-fUDKcI9hsqWKeXQlQbinSYgCIFtDVwK2d3BP9mGvP7NmaWDIKkmCQzrBkPV3fHWV875pXvYHDHOyvsj13FnaXg== +"@slickgrid-universal/utils@~5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@slickgrid-universal/utils/-/utils-5.9.0.tgz#639925da241014f62a677384485a3e01250d7421" + integrity sha512-2A/OoTvautUZ4FR86E9npoIA6f0iFSEqqiXivmKdQK3Ed0UAQEGak639p1dkFAHfbJxd7U7l6Gx0n0vtgjNu/Q== "@svgr/babel-plugin-add-jsx-attribute@8.0.0": version "8.0.0" @@ -1363,10 +1363,10 @@ "@typescript-eslint/types" "8.10.0" eslint-visitor-keys "^3.4.3" -"@vitejs/plugin-react@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.2.tgz#1e13f666fe3135b477220d3c13b783704636b6e4" - integrity sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg== +"@vitejs/plugin-react@^4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.3.3.tgz#28301ac6d7aaf20b73a418ee5c65b05519b4836c" + integrity sha512-NooDe9GpHGqNns1i8XDERg0Vsg5SSYRhRxxyTGogUdkdNt47jal+fbuYi+Yfq6pzRCKXyoPcWisfxE6RIM3GKA== dependencies: "@babel/core" "^7.25.2" "@babel/plugin-transform-react-jsx-self" "^7.24.7" @@ -3088,10 +3088,10 @@ eventemitter2@6.4.7: resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== -excel-builder-vanilla@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/excel-builder-vanilla/-/excel-builder-vanilla-3.0.6.tgz#c83700a045819659ab2f2c75a5c392885ca25222" - integrity sha512-WV+I1DgJ30TfqhjqEJZsp9G2wpSm+N/4Wk+EmP552NzW4wjGYq4bjw59jddetbrFyaCNBxXVcyOK2ae8z6zfaQ== +excel-builder-vanilla@^3.0.14: + version "3.0.14" + resolved "https://registry.yarnpkg.com/excel-builder-vanilla/-/excel-builder-vanilla-3.0.14.tgz#622775c71652fc1e96487543a3239cbb7912eae9" + integrity sha512-lXjyxAVVSwkHIikzCpQq+ydtrXWIGec/x6f5IzZV30BvW30i1adzNISSuq+OZqMuxbffKgmH0wgRkvSrl9WHgg== dependencies: fflate "^0.8.2" @@ -3721,10 +3721,10 @@ i18next-xhr-backend@*: dependencies: "@babel/runtime" "^7.5.5" -i18next@^23.16.0: - version "23.16.0" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.16.0.tgz#6127b49a30c19ba5caf0de8aeb3e15df60f7f01e" - integrity sha512-Ni3CG6c14teOogY19YNRl+kYaE/Rb59khy0VyHVn4uOZ97E2E/Yziyi6r3C3s9+wacjdLZiq/LLYyx+Cgd+FCw== +i18next@^23.16.1: + version "23.16.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.16.1.tgz#e5e72f72841e56c451a12240e672c9ab2ea86944" + integrity sha512-H73h/H7BN7PI38Sq9XsOXzWFBH6mtyCYFiUMVtd9BxiYNDWPPIzKcBmDrqhjKbw3IXP5j6JoSW4ugJlaZuOvKw== dependencies: "@babel/runtime" "^7.23.2" @@ -4607,10 +4607,10 @@ ms@^2.1.1, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -multiple-select-vanilla@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/multiple-select-vanilla/-/multiple-select-vanilla-3.3.4.tgz#946d4cec3230eb88414b07e6c4ab7564c207356e" - integrity sha512-NQuuoJqj+LY9JAhg94qvGIXPELKQpVlocuegxi1vhADvUnZSFbbgflcryO3CgcHII77zkWl82U0sFs8tLpBmlg== +multiple-select-vanilla@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/multiple-select-vanilla/-/multiple-select-vanilla-3.3.7.tgz#cf9d3d94e7808c06048634aefe2c9a6c523ba1b0" + integrity sha512-SpaHK0r2Kd343nRUSQsJxCdsy7Gt6l1K71NDDEohgmUAOPrM2j6+FSPRjr3W2E7fAyltT9ihyW0RY5FrmHZPgg== dependencies: "@types/trusted-types" "^2.0.7"