├── .npmrc
├── src
├── routes
│ ├── +page.svelte
│ └── examples
│ │ ├── IRow.ts
│ │ ├── +page.svelte
│ │ ├── reset.css
│ │ ├── server.ts
│ │ ├── LocalTable.svelte
│ │ └── RemoteTable.svelte
├── lib
│ ├── filter.ts
│ ├── functions.ts
│ ├── index.ts
│ ├── constants.ts
│ ├── Row.svelte
│ ├── Sort.svelte
│ ├── interfaces.ts
│ ├── Search.svelte
│ ├── sort.ts
│ ├── Pagination.svelte
│ ├── tableStore.ts
│ └── Table.svelte
├── app.html
└── app.d.ts
├── static
└── favicon.png
├── .gitignore
├── vite.config.ts
├── .eslintignore
├── .prettierignore
├── playwright.config.ts
├── .prettierrc
├── svelte.config.js
├── .eslintrc.cjs
├── tsconfig.json
├── README.md
└── package.json
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 | Examples
2 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fabiohvp/svelte-table/HEAD/static/favicon.png
--------------------------------------------------------------------------------
/src/routes/examples/IRow.ts:
--------------------------------------------------------------------------------
1 | export interface IRow {
2 | name: string;
3 | lastName: string;
4 | age: number;
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 | vite.config.js.timestamp-*
10 | vite.config.ts.timestamp-*
11 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import type { UserConfig } from 'vite';
3 |
4 | const config: UserConfig = {
5 | plugins: [sveltekit()]
6 | };
7 |
8 | export default config;
9 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Ignore files for PNPM, NPM and YARN
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Ignore files for PNPM, NPM and YARN
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
--------------------------------------------------------------------------------
/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import type { PlaywrightTestConfig } from '@playwright/test';
2 |
3 | const config: PlaywrightTestConfig = {
4 | webServer: {
5 | command: 'npm run build && npm run preview',
6 | port: 4173
7 | }
8 | };
9 |
10 | export default config;
11 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": true,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 100,
6 | "plugins": ["prettier-plugin-svelte"],
7 | "pluginSearchDirs": ["."],
8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/filter.ts:
--------------------------------------------------------------------------------
1 | export function filter(row: any, text: string) {
2 | text = text.toLocaleLowerCase();
3 | const keys = Object.keys(row);
4 |
5 | for (let k of keys) {
6 | if ((row[k] || '').toString().toLocaleLowerCase().indexOf(text) > -1) {
7 | return true;
8 | }
9 | }
10 | return false;
11 | }
12 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/lib/functions.ts:
--------------------------------------------------------------------------------
1 | export function getPaginationBoundaries(page: number, pageSize: number) {
2 | const start = page * pageSize;
3 | return {
4 | start,
5 | end: start + pageSize
6 | };
7 | }
8 |
9 | export function getPaginationRowIndex(index: number, page: number, pageSize: number) {
10 | return page * pageSize + index;
11 | }
12 |
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | // See https://kit.svelte.dev/docs/types#app
4 | // for information about these interfaces
5 | // and what to do when importing types
6 | declare namespace App {
7 | // interface Locals {}
8 | // interface PageData {}
9 | // interface Error {}
10 | // interface Platform {}
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | export * from '$lib/Pagination.svelte';
2 | export * from '$lib/Row.svelte';
3 | export * from '$lib/Search.svelte';
4 | export * from '$lib/Sort.svelte';
5 | export * from '$lib/Table.svelte';
6 | export * from '$lib/constants';
7 | export * from '$lib/filter';
8 | export * from '$lib/functions';
9 | export * from '$lib/interfaces';
10 | export * from '$lib/sort';
11 | export * from '$lib/tableStore';
12 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-auto';
2 | import preprocess from 'svelte-preprocess';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://github.com/sveltejs/svelte-preprocess
7 | // for more information about preprocessors
8 | preprocess: preprocess(),
9 |
10 | kit: {
11 | adapter: adapter()
12 | }
13 | };
14 |
15 | export default config;
16 |
--------------------------------------------------------------------------------
/src/routes/examples/+page.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
Client side processing
9 |
10 |
11 |
12 |
Server side processing
13 |
14 |
15 |
16 |
23 |
--------------------------------------------------------------------------------
/src/lib/constants.ts:
--------------------------------------------------------------------------------
1 | export const DEFAULT_PAGINATION_LABELS = {
2 | first: 'First',
3 | last: 'Last',
4 | next: 'Next',
5 | previous: 'Previous'
6 | };
7 | export const DEFAULT_SEARCH_LABELS = {
8 | placeholder: 'Search'
9 | };
10 | export const DEFAULT_SORT_LABELS = {
11 | asc: { title: 'Ascending', html: '↑' },
12 | desc: { title: 'Desceding', html: '↓' },
13 | unsorted: { title: 'Unsorted', html: '⇅' }
14 | };
15 | export const DEFAULT_TABLE_LABELS = {
16 | empty: 'No records available',
17 | loading: 'Loading data'
18 | };
19 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
5 | plugins: ['svelte3', '@typescript-eslint'],
6 | ignorePatterns: ['*.cjs'],
7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
8 | settings: {
9 | 'svelte3/typescript': () => require('typescript')
10 | },
11 | parserOptions: {
12 | sourceType: 'module',
13 | ecmaVersion: 2020
14 | },
15 | env: {
16 | browser: true,
17 | es2017: true,
18 | node: true
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true
12 | }
13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
14 | //
15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
16 | // from the referenced tsconfig.json - TypeScript does not merge them in
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/Row.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
24 |
25 |
26 |
27 |
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Svelte-table
2 |
3 | Make your tables using HTML and leave the javascript only for user interaction (pagination/search/sort);
4 |
5 | `npm install @fabiohvp/svelte-table`
6 | or
7 | `yarn add @fabiohvp/svelte-table`
8 |
9 | ## Examples
10 |
11 | You can see the examples in [Sveltelab.dev](https://www.sveltelab.dev/vs33nnuign7coeb)
12 |
13 | PS:. examples are using tableStore to manage table data but it can be managed with local variables
14 |
15 | ## Advanced
16 |
17 | - You can add components to the top or bottom slots.
18 | - Adding top/bottom slot will override the default content (Search/Pagination) but you can still use it by importing and adding them inside your custom slot.
19 | - You can change the default search method by adding an on:search event on Search component.
20 | - Row component is optional and only serves to render odd/even row, you can use instead.
21 | - Sort component expect "key" and you need to implement your own sorting method (see the example below).
22 |
23 | ## Roadmap
24 |
25 | - Add tests
--------------------------------------------------------------------------------
/src/lib/Sort.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 | {@html selected?.html}
30 |
31 |
32 |
41 |
--------------------------------------------------------------------------------
/src/lib/interfaces.ts:
--------------------------------------------------------------------------------
1 | export interface PaginationEventArgs {
2 | originalEvent: MouseEvent;
3 | page: number;
4 | pageSize: number;
5 | }
6 |
7 | export interface PaginationLabels {
8 | first: string;
9 | last: string;
10 | next: string;
11 | previous: string;
12 | }
13 |
14 | export interface RowEventArgs {
15 | originalEvent: MouseEvent;
16 | index: number;
17 | }
18 |
19 | export interface SearchEventArgs {
20 | originalEvent: KeyboardEvent;
21 | index: number;
22 | text: string;
23 | type: string;
24 | }
25 |
26 | export interface SearchLabels {
27 | placeholder: string;
28 | }
29 |
30 | export type SortDirection = 'asc' | 'desc';
31 |
32 | export interface SortEventArgs {
33 | originalEvent: MouseEvent;
34 | key: string;
35 | dir: SortDirection;
36 | type: string;
37 | }
38 |
39 | export interface SortLabels {
40 | asc: { title: string; html: string };
41 | desc: { title: string; html: string };
42 | unsorted: { title: string; html: string };
43 | }
44 |
45 | export interface SortParams {
46 | key: string;
47 | dir: SortDirection;
48 | }
49 |
50 | export interface TableLabels {
51 | empty: string;
52 | loading: string;
53 | }
54 |
--------------------------------------------------------------------------------
/src/lib/Search.svelte:
--------------------------------------------------------------------------------
1 |
23 |
24 |
33 |
34 |
54 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@fabiohvp/svelte-table",
3 | "description": "Svelte-table - a simple way to render your tables",
4 | "version": "0.2.5",
5 | "keywords": [
6 | "svelte",
7 | "table"
8 | ],
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/fabiohvp/svelte-table.git"
12 | },
13 | "author": "https://github.com/fabiohvp",
14 | "license": "MIT",
15 | "bugs": {
16 | "url": "https://github.com/fabiohvp/svelte-table/issues"
17 | },
18 | "homepage": "https://github.com/fabiohvp/svelte-table#readme",
19 | "type": "module",
20 | "scripts": {
21 | "dev": "vite dev",
22 | "build": "svelte-kit sync && svelte-package",
23 | "prepublishOnly": "echo 'Did you mean to publish `./package/`, instead of `./`?' && exit 1",
24 | "test": "playwright test",
25 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
26 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
27 | "lint": "prettier --plugin-search-dir . --check . && eslint .",
28 | "format": "prettier --plugin-search-dir . --write ."
29 | },
30 | "devDependencies": {
31 | "@playwright/test": "1.25.0",
32 | "@sveltejs/adapter-auto": "next",
33 | "@sveltejs/kit": "next",
34 | "@sveltejs/package": "next",
35 | "@typescript-eslint/eslint-plugin": "^5.27.0",
36 | "@typescript-eslint/parser": "^5.27.0",
37 | "eslint": "^8.16.0",
38 | "eslint-config-prettier": "^8.3.0",
39 | "eslint-plugin-svelte3": "^4.0.0",
40 | "prettier": "^2.6.2",
41 | "prettier-plugin-svelte": "^2.7.0",
42 | "svelte": "^3.44.0",
43 | "svelte-check": "^2.7.1",
44 | "svelte-preprocess": "^4.10.6",
45 | "tslib": "^2.3.1",
46 | "typescript": "^4.7.4",
47 | "vite": "^3.1.0"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/routes/examples/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html,
7 | body,
8 | div,
9 | span,
10 | applet,
11 | object,
12 | iframe,
13 | h1,
14 | h2,
15 | h3,
16 | h4,
17 | h5,
18 | h6,
19 | p,
20 | blockquote,
21 | pre,
22 | a,
23 | abbr,
24 | acronym,
25 | address,
26 | big,
27 | cite,
28 | code,
29 | del,
30 | dfn,
31 | em,
32 | img,
33 | ins,
34 | kbd,
35 | q,
36 | s,
37 | samp,
38 | small,
39 | strike,
40 | strong,
41 | sub,
42 | sup,
43 | tt,
44 | var,
45 | b,
46 | u,
47 | i,
48 | center,
49 | dl,
50 | dt,
51 | dd,
52 | ol,
53 | ul,
54 | li,
55 | fieldset,
56 | form,
57 | label,
58 | legend,
59 | table,
60 | caption,
61 | tbody,
62 | tfoot,
63 | thead,
64 | tr,
65 | th,
66 | td,
67 | article,
68 | aside,
69 | canvas,
70 | details,
71 | embed,
72 | figure,
73 | figcaption,
74 | footer,
75 | header,
76 | hgroup,
77 | menu,
78 | nav,
79 | output,
80 | ruby,
81 | section,
82 | summary,
83 | time,
84 | mark,
85 | audio,
86 | video {
87 | margin: 0;
88 | padding: 0;
89 | border: 0;
90 | font-size: 100%;
91 | font: inherit;
92 | vertical-align: baseline;
93 | }
94 |
95 | /* HTML5 display-role reset for older browsers */
96 | article,
97 | aside,
98 | details,
99 | figcaption,
100 | figure,
101 | footer,
102 | header,
103 | hgroup,
104 | menu,
105 | nav,
106 | section {
107 | display: block;
108 | }
109 |
110 | body {
111 | line-height: 1;
112 | }
113 |
114 | ol,
115 | ul {
116 | list-style: none;
117 | }
118 |
119 | blockquote,
120 | q {
121 | quotes: none;
122 | }
123 |
124 | blockquote:before,
125 | blockquote:after,
126 | q:before,
127 | q:after {
128 | content: '';
129 | content: none;
130 | }
131 |
132 | table {
133 | border-collapse: collapse;
134 | border-spacing: 0;
135 | }
136 |
--------------------------------------------------------------------------------
/src/routes/examples/server.ts:
--------------------------------------------------------------------------------
1 | import { filter } from '$lib/filter';
2 | import { sortDateByKey, sortNumberByKey, type SortDirection } from '$lib/sort';
3 | import type { IRow } from './IRow';
4 |
5 | const originalData: IRow[] = [
6 | { name: 'a', lastName: 'o', age: 1 },
7 | { name: 'b', lastName: 'n', age: 2 },
8 | { name: 'c', lastName: 'm', age: 23 },
9 | { name: 'd', lastName: 'l', age: 11 },
10 | { name: 'e', lastName: 'k', age: 132 },
11 | { name: 'f', lastName: 'j', age: 152 },
12 | { name: 'g', lastName: 'i', age: 4 },
13 | { name: 'h', lastName: 'h', age: 432 },
14 | { name: 'i', lastName: 'g', age: 41 },
15 | { name: 'k', lastName: 'f', age: 432 },
16 | { name: 'l', lastName: 'e', age: 552 }
17 | ];
18 |
19 | export function getAll(): Promise {
20 | return new Promise((resolve, reject) => {
21 | setTimeout(function () {
22 | resolve(originalData);
23 | }, 250);
24 | });
25 | }
26 |
27 | export function getData(
28 | page: number,
29 | pageSize: number,
30 | text: string,
31 | sorting: { dir: SortDirection; key: string }
32 | ): Promise<{ rows: IRow[]; rowsCount: number }> {
33 | let data: IRow[] = [...originalData];
34 |
35 | if (sorting) {
36 | if (sorting.key === 'age') {
37 | data = sortNumberByKey(data, sorting.key, sorting.dir);
38 | } else {
39 | data = sortDateByKey(data, sorting.key, sorting.dir);
40 | }
41 | }
42 |
43 | return new Promise((resolve, _reject) => {
44 | setTimeout(function () {
45 | let rows = [];
46 | let rowsCount = data.length;
47 |
48 | if (text && text.length > 0) {
49 | rows = data.filter((row) => filter(row, text));
50 | rowsCount = rows.length; //need to count before slice
51 | } else {
52 | rows = data;
53 | }
54 |
55 | const pageIndex = page * pageSize;
56 | resolve({
57 | rows: rows.slice(pageIndex, pageIndex + pageSize),
58 | rowsCount
59 | });
60 | }, 250);
61 | });
62 | }
63 |
--------------------------------------------------------------------------------
/src/lib/sort.ts:
--------------------------------------------------------------------------------
1 | import type { SortDirection, SortEventArgs } from './interfaces';
2 |
3 | type SortNumberMethod = (a: number, b: number) => number;
4 | type SortStringMethod = (a: string, b: string) => number;
5 |
6 | const sortNumberDict: { asc: SortNumberMethod; desc: SortNumberMethod } = {
7 | asc: (a: number, b: number) => (a > b ? 1 : -1),
8 | desc: (a: number, b: number) => (a > b ? -1 : 1)
9 | };
10 |
11 | const sortStringDict: { asc: SortStringMethod; desc: SortStringMethod } = {
12 | asc: (a: string, b: string) => a?.localeCompare(b),
13 | desc: (a: string, b: string) => b?.localeCompare(a)
14 | };
15 |
16 | export type SortFunction = (rows: T[], key: string, dir: SortDirection) => T[];
17 |
18 | export function getSortAttributes(key: string, currentSorting: SortEventArgs) {
19 | return {
20 | key,
21 | dir: (currentSorting?.key === key ? currentSorting.dir : 'none') as SortDirection
22 | };
23 | }
24 |
25 | export function sortDateBy(rows: T[], getValue: (row: T) => Date, dir: SortDirection) {
26 | const sortMethod = sortNumberDict[dir ?? 'asc'];
27 | return rows.sort((a, b) => sortMethod(getValue(a).getTime(), getValue(b).getTime()));
28 | }
29 |
30 | export function sortNumberBy(rows: T[], getValue: (row: T) => number, dir: SortDirection) {
31 | const sortMethod = sortNumberDict[dir ?? 'asc'];
32 | return rows.sort((a, b) => sortMethod(getValue(a), getValue(b)));
33 | }
34 |
35 | export function sortStringBy(rows: T[], getValue: (row: T) => string, dir: SortDirection) {
36 | const sortMethod = sortStringDict[dir ?? 'asc'];
37 | return rows.sort((a, b) => sortMethod(getValue(a), getValue(b)));
38 | }
39 |
40 | export function sortDateByKey(rows: any[], key: string, dir: SortDirection) {
41 | const sortMethod = sortNumberDict[dir ?? 'asc'];
42 | return rows.sort((a, b) => sortMethod(a[key], b[key]));
43 | }
44 |
45 | export function sortNumberByKey(rows: any[], key: string, dir: SortDirection) {
46 | const sortMethod = sortNumberDict[dir ?? 'asc'];
47 | return rows.sort((a, b) => sortMethod(a[key], b[key]));
48 | }
49 |
50 | export function sortStringByKey(rows: any[], key: string, dir: SortDirection) {
51 | const sortMethod = sortStringDict[dir ?? 'asc'];
52 | return rows.sort((a, b) => sortMethod(a[key], b[key]));
53 | }
54 |
--------------------------------------------------------------------------------
/src/routes/examples/LocalTable.svelte:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
52 |
53 |
54 | Name
55 |
56 |
57 |
58 | Lastname
59 |
60 |
61 |
62 | Age
63 |
64 |
65 |
66 |
67 |
68 | {#each visibleRows as row, index (row)}
69 | onCellClick(row)}>
70 | {row.name}
71 | {row.lastName}
72 | {row.age}
73 |
74 | {/each}
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/lib/Pagination.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 |
62 |
63 |
95 |
--------------------------------------------------------------------------------
/src/routes/examples/RemoteTable.svelte:
--------------------------------------------------------------------------------
1 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | Name
59 |
60 |
61 |
62 | Lastname
63 |
64 |
65 |
66 | Age
67 |
68 |
69 |
70 |
71 |
72 | {#each visibleRows as row, index (row)}
73 | onCellClick(row)}>
74 | {row.name}
75 | {row.lastName}
76 | {row.age}
77 |
78 | {/each}
79 |
80 |
83 |
84 |
--------------------------------------------------------------------------------
/src/lib/tableStore.ts:
--------------------------------------------------------------------------------
1 | import { filter } from '$lib/filter';
2 | import { getPaginationBoundaries, getPaginationRowIndex } from '$lib/functions';
3 | import type { SortDirection } from '$lib/interfaces';
4 | import { sortNumberByKey, sortStringByKey, type SortFunction } from '$lib/sort';
5 | import { writable, type Readable } from 'svelte/store';
6 |
7 | export type TableData = {
8 | loading: boolean;
9 | local: boolean;
10 | page: number;
11 | pageSize: number;
12 | rows: T[];
13 | rowsCount: number;
14 | };
15 |
16 | export type TableStore = Readable> & ReturnType>;
17 |
18 | export function createTableStore(initialState: Partial> = {}) {
19 | const { update, subscribe } = writable({
20 | loading: false,
21 | local: true,
22 | page: 0,
23 | pageSize: 10,
24 | rows: [],
25 | rowsCount: 0,
26 | ...initialState
27 | });
28 |
29 | return {
30 | subscribe,
31 | update,
32 |
33 | getPaginationBoundaries: () => {
34 | let page = 0;
35 | let pageSize = 0;
36 | subscribe((s) => {
37 | (page = s.page), (pageSize = s.pageSize);
38 | })();
39 | return getPaginationBoundaries(page, pageSize);
40 | },
41 |
42 | getPaginationRowIndex: (index: number) => {
43 | let page = 0;
44 | let pageSize = 0;
45 | subscribe((s) => {
46 | (page = s.page), (pageSize = s.pageSize);
47 | })();
48 | return getPaginationRowIndex(index, page, pageSize);
49 | },
50 |
51 | paginate: (page: number, pageSize?: number) => {
52 | update((s) => ({
53 | ...s,
54 | page,
55 | pageSize: pageSize ?? s.pageSize
56 | }));
57 | },
58 |
59 | search: (text: string) => {
60 | update((s) => ({
61 | ...s,
62 | page: 0,
63 | rows: s.rows.filter((row) => filter(row, text))
64 | }));
65 | },
66 |
67 | setLoading: (loading: boolean) => {
68 | update((s) => ({
69 | ...s,
70 | loading
71 | }));
72 | },
73 |
74 | setRows: (rows: T[], rowsCount: number | undefined = undefined, loading = false, page = 0) => {
75 | update((s) => ({
76 | ...s,
77 | loading,
78 | page,
79 | rows,
80 | rowsCount: rowsCount ?? rows.length
81 | }));
82 | },
83 |
84 | sort: (
85 | key: string,
86 | dir: SortDirection,
87 | typeOrFn: 'string' | 'number' | string | SortFunction = 'string'
88 | ) => {
89 | if (typeof typeOrFn === 'function') {
90 | update((s) => ({
91 | ...s,
92 | rows: typeOrFn(s.rows, key, dir)
93 | }));
94 | } else if (typeOrFn === 'string') {
95 | update((s) => ({
96 | ...s,
97 | rows: sortStringByKey(s.rows, key, dir)
98 | }));
99 | } else if (typeOrFn === 'number') {
100 | update((s) => ({
101 | ...s,
102 | rows: sortNumberByKey(s.rows, key, dir)
103 | }));
104 | } else {
105 | throw Error('Sorting type or function is undefined');
106 | }
107 | },
108 |
109 | updateRow: (data: T, index: number) => {
110 | update((s) => {
111 | s.rows[index] = data;
112 | return s;
113 | });
114 | }
115 | };
116 | }
117 |
--------------------------------------------------------------------------------
/src/lib/Table.svelte:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {#if loading}
50 |
51 |
52 |
53 |
54 | {@html labels.loading}
55 |
56 |
57 |
58 |
59 | {:else if visibleRows.length === 0}
60 |
61 |
62 |
63 |
64 | {@html labels.empty}
65 |
66 |
67 |
68 |
69 | {:else}
70 |
71 | {/if}
72 |
73 |
74 |
75 |
76 |
77 |
84 |
85 |
86 |
87 |
172 |
--------------------------------------------------------------------------------