diff --git a/packages/components/grid/src/stories/pagination.stories.ts b/packages/components/grid/src/stories/pagination.stories.ts
index 2f4e30b27..388a435f6 100644
--- a/packages/components/grid/src/stories/pagination.stories.ts
+++ b/packages/components/grid/src/stories/pagination.stories.ts
@@ -3,14 +3,12 @@ import '@sl-design-system/button-bar/register.js';
import '@sl-design-system/paginator/register.js';
import { type Person, getPeople } from '@sl-design-system/example-data';
import { ArrayDataSource } from '@sl-design-system/shared';
-import { type TextField } from '@sl-design-system/text-field';
import '@sl-design-system/text-field/register.js';
import { type Meta, type StoryObj } from '@storybook/web-components';
-import { LitElement, type TemplateResult, html } from 'lit';
-import { state } from 'lit/decorators.js';
-import { repeat } from 'lit/directives/repeat.js';
+import { html } from 'lit';
import '../../register.js';
import {PageSize, Paginator, VisibleItems} from "@sl-design-system/paginator";
+import { Grid } from '../grid.js';
type Story = StoryObj;
@@ -25,74 +23,98 @@ export default {
} satisfies Meta;
export const Basic: Story = {
- render: (_, { loaded: { people } }) => html`
-
-
-
-
-
-
-
- `
-};
+ render: (_, { loaded: { people } }) => {
+ const pageSizes = [5, 10, 15];
+ let activePage = 1,
+ itemsPerPage = pageSizes[1],
+ startIndex = (activePage - 1) * itemsPerPage,
+ endIndex = startIndex + itemsPerPage;
+
+ setTimeout(() => {
+ const paginator = document.querySelector('sl-paginator') as Paginator,
+ pageSize = document.querySelector('sl-page-size') as PageSize,
+ visibleItems = document.querySelector('sl-visible-items') as VisibleItems,
+ grid = document.querySelector('sl-grid') as Grid;
+
+ paginator?.addEventListener('sl-page-change', event => {
+ visibleItems.activePage = event.detail;
+ activePage = event.detail;
+ startIndex = (event.detail - 1) * itemsPerPage;
+ endIndex = startIndex + itemsPerPage;
+ grid.items = people.slice(startIndex, endIndex);
+ });
-export const Filtered: Story = {
- render: (_, { loaded: { people } }) => html`
-
-
-
-
-
-
-
- `
+ pageSize?.addEventListener('sl-page-size-change', event => {
+ paginator.itemsPerPage = event.detail;
+ visibleItems.itemsPerPage = event.detail;
+ itemsPerPage = event.detail;
+ });
+ });
+
+ return html`
+
+
+
+
+
+
+
+
+
+ `
+ }
};
-export const PaginatedDataSource: Story = {
+export const PaginatedDataSourceWithFilter: Story = {
render: (_, { loaded: { people } }) => {
- const pageSizes = [5, 10, 15, 20];
- const dataSource = new ArrayDataSource(people as Person[]);
- let total = dataSource.paginatedItems.length; //dataSource.items.length;
- dataSource.paginate(10, 1);
- // dataSource.items = dataSource.paginatedItems;
+ const pageSizes = [5, 10, 15, 20],
+ dataSource = new ArrayDataSource(people as Person[]);
+
+ let total = dataSource.paginatedItems.length;
+ dataSource.paginate(1, 10);
setTimeout(() => {
- const paginator = document.querySelector('sl-paginator') as Paginator;
- const pageSize = document.querySelector('sl-page-size') as PageSize;
- const visibleItems = document.querySelector('sl-visible-items') as VisibleItems;
- // const pageSizes = [5, 10, 15];
- // const dataSource = new ArrayDataSource(people as Person[]);
- // const total = dataSource.items.length;
- // dataSource.paginate(10, 1);
- console.log('dataSource in the story - paginated data', dataSource, total);
- console.log('paginator with grid', paginator, pageSize, visibleItems, paginator.activePage);
- // dataSource.addFilter('filter-profession', 'profession', 'Endo');
- // dataSource.addFilter('filter-status', 'status', 'Available');
- // dataSource.addFilter('filter-membership', 'membership', ['Regular', 'Premium']);
+ const paginator = document.querySelector('sl-paginator') as Paginator,
+ pageSize = document.querySelector('sl-page-size') as PageSize,
+ visibleItems = document.querySelector('sl-visible-items') as VisibleItems,
+ grid = document.querySelector('sl-grid') as Grid;
paginator?.addEventListener('sl-page-change', event => {
- console.log('sl-page-change event', event, event.detail, paginator.itemsPerPage);
- // pageSize.activePage = event.detail;
- dataSource.paginate(paginator.itemsPerPage ?? pageSizes[0], event.detail);
+ dataSource.paginate(event.detail, paginator.itemsPerPage ?? pageSizes[0]);
visibleItems.activePage = event.detail;
- // visibleItems.requestUpdate();
- //
- // selectedTabIndex = event.detail;
});
+
pageSize?.addEventListener('sl-page-size-change', event => {
- console.log('sl-page-size-change event', event, event.detail);
paginator.itemsPerPage = event.detail;
visibleItems.itemsPerPage = event.detail;
- dataSource.paginate(event.detail, paginator.activePage);
- // paginator.requestUpdate();
- //
- // selectedTabIndex = event.detail;
+ dataSource.paginate(paginator.activePage, event.detail);
+ });
+
+ dataSource?.addEventListener('sl-update', () => {
+ paginator.total = dataSource.paginatedItems.length;
+ visibleItems.total = dataSource.paginatedItems.length;
});
- dataSource?.addEventListener('sl-update', event => {
- console.log('sl-update event', event, dataSource.items.length, dataSource.items, dataSource.filteredItems);
- paginator.total = dataSource.paginatedItems.length; //dataSource.items.length;
- visibleItems.total = dataSource.paginatedItems.length; //dataSource.items.length;
+ grid?.addEventListener('sl-filter-value-change', () => {
+ // go back to the first page on filter change
+ paginator.activePage = 1;
});
});
@@ -126,160 +148,80 @@ export const PaginatedDataSource: Story = {
}
};
-export const FilteringWithSelection: Story = {
- render: (_, { loaded: { people } }) => html`
-
-
-
-
-
-
-
- `
-};
-
-export const Custom: Story = {
+export const PaginatedDataSourceWithSorter: Story = {
render: (_, { loaded: { people } }) => {
- const filter = (person: Person): boolean => {
- return person.profession === 'Gastroenterologist';
- };
+ const sorter = (a: Person, b: Person): number => {
+ const lastNameCmp = a.lastName.localeCompare(b.lastName);
- const dataSource = new ArrayDataSource(people as Person[]);
- dataSource.addFilter('custom', filter);
-
- return html`
- This grid filters people on the "Gastroenterologist" profession via a custom filter on the data directly.
-
-
-
-
-
-
- `;
- }
-};
-
-export const EmptyValues: Story = {
- render: () => {
- const items = [
- { key: 'Foo', value: 'foo' },
- { key: '"0"', value: '0' },
- { key: '0', value: 0 },
- { key: 'Spaces', value: ' ' },
- { key: 'Blank', value: '' },
- { key: 'Null', value: null },
- { key: 'Undefined', value: undefined }
- ];
-
- return html`
-
-
-
-
- `;
- }
-};
+ if (lastNameCmp === 0) {
+ return a.firstName.localeCompare(b.firstName);
+ } else {
+ return lastNameCmp;
+ }
+ };
-export const Grouped: Story = {
- render: (_, { loaded: { people } }) => {
const dataSource = new ArrayDataSource(people as Person[]);
- dataSource.setGroupBy('membership');
+ dataSource.setSort('custom', sorter, 'asc');
- return html`
-
-
-
-
-
-
-
- `;
- }
-};
+ const pageSizes = [10, 15, 20];
+ let total = dataSource.paginatedItems.length;
+ dataSource.paginate(1, 10);
-export const OutsideGrid: Story = {
- render: (_, { loaded: { people } }) => {
- const dataSource = new ArrayDataSource(people as Person[]);
+ setTimeout(() => {
+ const paginator = document.querySelector('sl-paginator') as Paginator,
+ pageSize = document.querySelector('sl-page-size') as PageSize,
+ visibleItems = document.querySelector('sl-visible-items') as VisibleItems,
+ grid = document.querySelector('sl-grid') as Grid;
- const onInput = ({ target }: Event & { target: TextField }): void => {
- const value = target.value?.toString().trim() ?? '';
+ paginator?.addEventListener('sl-page-change', event => {
+ dataSource.paginate(event.detail, paginator.itemsPerPage ?? pageSizes[0]);
+ visibleItems.activePage = event.detail;
+ });
- if (value) {
- const regex = new RegExp(value, 'i');
+ pageSize?.addEventListener('sl-page-size-change', event => {
+ paginator.itemsPerPage = event.detail;
+ visibleItems.itemsPerPage = event.detail;
+ dataSource.paginate(paginator.activePage, event.detail);
+ });
- dataSource.addFilter('search', ({ firstName, lastName, email, profession }) => {
- return regex.test(firstName) || regex.test(lastName) || regex.test(email) || regex.test(profession);
- });
- } else {
- dataSource.removeFilter('search');
- }
+ dataSource?.addEventListener('sl-update', () => {
+ paginator.total = dataSource.paginatedItems.length;
+ visibleItems.total = dataSource.paginatedItems.length;
+ });
- dataSource.update();
- };
+ grid?.addEventListener('sl-sort-direction-change', () => {
+ // go back to the first page on filter change
+ paginator.activePage = 1;
+ });
+ });
return html`
-
-
+ This grid sorts people by last name, then first name, via a custom sorter on the data directly.
-
-
-
+
+
-
+
`;
}
};
-export const ReorderColumns: Story = {
- render: (_, { loaded: { people } }) => {
- class GridReorderExample extends LitElement {
- @state()
- columns = [
- { path: 'firstName' },
- { path: 'lastName' },
- { path: 'profession', type: 'filter' },
- { path: 'status', type: 'filter' },
- { path: 'membership', type: 'filter' }
- ];
-
- override render(): TemplateResult {
- return html`
-
- Reorder columns
-
-
- ${repeat(
- this.columns,
- column => column.path,
- column => {
- if (column.type === 'filter') {
- return html``;
- } else {
- return html``;
- }
- }
- )}
-
- `;
- }
-
- onClick(): void {
- this.columns = [...this.columns.sort(() => Math.random() - 0.5)];
- }
- }
- try {
- customElements.define('grid-reorder-example', GridReorderExample);
- } catch {
- /* empty */
- }
-
- return html``;
- }
-};
diff --git a/packages/components/paginator/src/page-size.scss b/packages/components/paginator/src/page-size.scss
index 2984cf072..5631f4bb7 100644
--- a/packages/components/paginator/src/page-size.scss
+++ b/packages/components/paginator/src/page-size.scss
@@ -1,7 +1,5 @@
:host {
display: block;
- //padding-block: 8px;
- //padding-inline: 0;
padding: 0;
}
diff --git a/packages/components/paginator/src/paginator.stories.ts b/packages/components/paginator/src/paginator.stories.ts
index 7368f8746..7cda59352 100644
--- a/packages/components/paginator/src/paginator.stories.ts
+++ b/packages/components/paginator/src/paginator.stories.ts
@@ -104,7 +104,23 @@ export const Mobile: Story = {
};
export const ItemsPerPage: Story = {
- render: () => html`
+ args: {
+ ...Basic.args,
+ total: 100
+ },
+ render: ({pageSizes, itemsPerPage}) => {
+ let pageSize = document.querySelector('sl-page-size') as PageSize;
+ setTimeout(() => {
+ pageSize = document.querySelector('sl-page-size') as PageSize;
+
+ pageSize?.addEventListener('sl-page-size-change', event => {
+ console.log('sl-page-size-change event', event, event.detail);
+ itemsPerPage = event.detail;
+ const pEl = document.querySelector('p.info');
+ console.log('pEl', pEl);
+ });
+ })
+ return html`
TODO...
- `
+
+ There will be shown ${itemsPerPage} items per page. ${pageSize?.itemsPerPage}
+ `}
};
diff --git a/packages/components/paginator/src/paginator.ts b/packages/components/paginator/src/paginator.ts
index debd8b0b7..24909637b 100644
--- a/packages/components/paginator/src/paginator.ts
+++ b/packages/components/paginator/src/paginator.ts
@@ -438,12 +438,14 @@ export class Paginator extends ScopedElementsMixin(LitElement) {
const buttonPrev = this.renderRoot.querySelector('sl-button.prev') as Button;
const buttonNext = this.renderRoot.querySelector('sl-button.next') as Button;
const selectWrapper = this.renderRoot.querySelector('.select-wrapper') as HTMLDivElement;
+ const ulElement = this.renderRoot.querySelector('ul') as HTMLUListElement;
// reset display to check the width
pagesWrapper.style.display = '';
buttonPrev.style.display = '';
buttonNext.style.display = '';
selectWrapper.style.display = 'none';
+ ulElement.removeAttribute('mobile');
this.requestUpdate();
console.log(
@@ -580,6 +582,7 @@ export class Paginator extends ScopedElementsMixin(LitElement) {
buttonPrev.style.display = '';
buttonNext.style.display = '';
selectWrapper.style.display = 'none';
+ ulElement.removeAttribute('mobile');
// const containerWidth = pagesWrapper.clientWidth;
@@ -615,6 +618,7 @@ export class Paginator extends ScopedElementsMixin(LitElement) {
buttonPrev.style.display = '';
buttonNext.style.display = '';
selectWrapper.style.display = 'none';
+ ulElement.removeAttribute('mobile');
this.requestUpdate();
@@ -806,6 +810,7 @@ export class Paginator extends ScopedElementsMixin(LitElement) {
buttonPrev.style.display = 'none';
buttonNext.style.display = 'none';
selectWrapper.style.display = '';
+ ulElement.setAttribute('mobile', '');
// TODO: maybe select-wrapper display block?
this.requestUpdate();
return;
diff --git a/packages/components/paginator/src/visible-items.scss b/packages/components/paginator/src/visible-items.scss
index e6b5b2d34..526979499 100644
--- a/packages/components/paginator/src/visible-items.scss
+++ b/packages/components/paginator/src/visible-items.scss
@@ -1,7 +1,5 @@
:host {
display: block;
- //padding-block: 8px;
- //padding-inline: 0;
padding: 0;
text-wrap: nowrap;
}
diff --git a/packages/components/shared/src/data-source/array-data-source.ts b/packages/components/shared/src/data-source/array-data-source.ts
index 78fc52700..95f5a8bd2 100644
--- a/packages/components/shared/src/data-source/array-data-source.ts
+++ b/packages/components/shared/src/data-source/array-data-source.ts
@@ -46,6 +46,7 @@ export class ArrayDataSource extends DataSource {
// Filter the items
for (const filter of this.filters.values()) {
+ console.log('in filters update', filter, this.filteredItems);
if ('filter' in filter && filter.filter) {
items = items.filter(filter.filter);
} else if ('path' in filter && filter.path) {
@@ -115,27 +116,36 @@ export class ArrayDataSource extends DataSource {
});
}
+ // const previouslyFilteredItems1 = items;
+
// if (this.paginatedItems) {
// items = this.paginatedItems;
// }
- console.log('items before paginated, but should be filtered if filtered', items);
+ console.log('items before paginated, but should be filtered if filtered', items, this.filters, this.filters.size > 0, this.filters.values());
this.#paginatedItems = items;
+ // paginate items
if (this.paginateItems) {
console.log('this.paginateItems', this.paginateItems);
// const pagination = {pageNumber: pageNumber, pageSize: pageSize};
// console.log('pagination in paginate', pagination);
- const startIndex = (this.paginateItems.pageNumber - 1) * this.paginateItems.pageSize;
+ // const pageNumber = /*filtersChanged /!*this.filters.size > 0*!/ ? 1 :*/ this.paginateItems.pageNumber;
+ // this.paginateItems.pageNumber = pageNumber;
+ // this.paginate(10, pageNumber);
+ // this.paginateItems.pageNumber = pageNumber;
+
+ const startIndex = (this.paginateItems.pageNumber /*pageNumber*/ - 1) * this.paginateItems.pageSize;
const endIndex = startIndex + this.paginateItems.pageSize;
+ // console.log('pageNumber in array data source', pageNumber, filtersChanged, startIndex);
// Get the items for the current page
/*const paginatedItems*/items = /*this.*/items.slice(startIndex, endIndex);
// console.log('paginated data', paginatedItems);
// Update this.items with the paginated items
// this.paginatedItems/*items*/ = paginatedItems;
- console.log('updated items', this.items, this.paginatedItems, items);
+ // console.log('updated items', this.items, this.paginatedItems, items);
}
// TODO: I need to have amount of all filtered data for total to show in the paginator...
@@ -145,8 +155,13 @@ export class ArrayDataSource extends DataSource {
// TODO: pagination needs to work with filteredItems as well
+ // TODO: detect whether filter values have changed and then activePage = 1 in the paginator?
+
// this.#paginatedItems = this.paginatedItems;
+ // console.log('filtereditems1', this.#filteredItems);
+ // const previouslyFilteredItems = this.#filteredItems;
+
this.#filteredItems = items; // TODO: maybe needs to be before pagination?
this.dispatchEvent(new CustomEvent('sl-update'));
}
diff --git a/packages/components/shared/src/data-source/data-source.ts b/packages/components/shared/src/data-source/data-source.ts
index 5947a4eee..1f67bb205 100644
--- a/packages/components/shared/src/data-source/data-source.ts
+++ b/packages/components/shared/src/data-source/data-source.ts
@@ -77,7 +77,7 @@ export abstract class DataSource extends EventTarget {
/** Total number of items in this data source. */
abstract readonly size: number;
- /** Updates the list of items using filter and sorting if available. */
+ /** Updates the list of items using filter, sorting and pagination if available. */
abstract update(): void;
addFilter>(
@@ -85,12 +85,13 @@ export abstract class DataSource extends EventTarget {
pathOrFilter: U,
value?: string | string[]
): void {
+ console.log('value in addFilter', value);
if (typeof pathOrFilter === 'string') {
this.#filters.set(id, { path: pathOrFilter, value: value ?? '' });
} else {
this.#filters.set(id, { filter: pathOrFilter, value });
}
- }
+ } // TODO: maybe here emit an event?
removeFilter(id: string): void {
this.#filters.delete(id);
@@ -158,32 +159,9 @@ export abstract class DataSource extends EventTarget {
/**
* Use to get the paginated data for usage with the sl-paginator component.
* */
- paginate(/*data: T[], */pageSize: number, pageNumber: number): void {
- // // const items = /*data ? data :*/ this.items;
- // console.log('in paginate', this.items);
- // const startIndex = (pageNumber - 1) * pageSize;
- // console.log('paginated data', this.items.slice(startIndex, startIndex + pageSize), this.items);
- // console.log('in paginate2', this.items);
- // // Get the items for the current page
- // /*return*/ // items.slice(startIndex, startIndex + pageSize);
- // this.update();
- // this.#allItems = this.items;
-
- // console.log('all items in paginated data', this.#allItems);
-
+ paginate(pageNumber: number, pageSize: number): void {
this.#paginateItems = { pageNumber: pageNumber, pageSize: pageSize};
- // const pagination = {pageNumber: pageNumber, pageSize: pageSize};
- // console.log('pagination in paginate', pagination);
- //
- // const startIndex = (pageNumber - 1) * pageSize;
- // const endIndex = startIndex + pageSize;
- // // Get the items for the current page
- // const paginatedItems = this.items.slice(startIndex, endIndex);
- // console.log('paginated data', paginatedItems);
- // // Update this.items with the paginated items
- // this.paginatedItems/*items*/ = paginatedItems;
- // console.log('updated items', this.items, this.paginatedItems);
this.update();
}