@reuters-graphics/graphics-components 0.0.31 → 0.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@types/components/@types/global.d.ts +7 -0
- package/dist/@types/components/Table/LeftArrow.svelte.d.ts +19 -0
- package/dist/@types/components/Table/MagnifyingGlass.svelte.d.ts +19 -0
- package/dist/@types/components/Table/Pagination.svelte.d.ts +31 -0
- package/dist/@types/components/Table/RightArrow.svelte.d.ts +19 -0
- package/dist/@types/components/Table/Search.svelte.d.ts +21 -0
- package/dist/@types/components/Table/Select.svelte.d.ts +26 -0
- package/dist/@types/components/Table/SortArrow.svelte.d.ts +20 -0
- package/dist/@types/components/Table/Table.svelte.d.ts +93 -0
- package/dist/@types/components/Table/X.svelte.d.ts +19 -0
- package/dist/@types/components/Table/utils.d.ts +5 -0
- package/dist/@types/index.d.ts +1 -0
- package/dist/components/Article/Article.svelte +0 -1
- package/dist/components/Table/LeftArrow.svelte +17 -0
- package/dist/components/Table/MagnifyingGlass.svelte +16 -0
- package/dist/components/Table/Pagination.svelte +118 -0
- package/dist/components/Table/RightArrow.svelte +17 -0
- package/dist/components/Table/Search.svelte +76 -0
- package/dist/components/Table/Select.svelte +69 -0
- package/dist/components/Table/SortArrow.svelte +36 -0
- package/dist/components/Table/Table.svelte +418 -0
- package/dist/components/Table/X.svelte +21 -0
- package/dist/components/Table/utils.js +36 -0
- package/dist/index.js +1 -0
- package/package.json +11 -1
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { ComponentType } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Used for the list of <option> tags nested in a <select> input.
|
|
4
|
+
*/
|
|
5
|
+
export declare type Option = {
|
|
6
|
+
value: string;
|
|
7
|
+
text: string;
|
|
8
|
+
};
|
|
2
9
|
/**
|
|
3
10
|
* Used for any props that restrict width of a container to one of pre-fab widths.
|
|
4
11
|
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} LeftArrowProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} LeftArrowEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} LeftArrowSlots */
|
|
4
|
+
export default class LeftArrow extends SvelteComponentTyped<{}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> {
|
|
7
|
+
}
|
|
8
|
+
export type LeftArrowProps = typeof __propDef.props;
|
|
9
|
+
export type LeftArrowEvents = typeof __propDef.events;
|
|
10
|
+
export type LeftArrowSlots = typeof __propDef.slots;
|
|
11
|
+
import { SvelteComponentTyped } from "svelte";
|
|
12
|
+
declare const __propDef: {
|
|
13
|
+
props: {};
|
|
14
|
+
events: {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
};
|
|
17
|
+
slots: {};
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} MagnifyingGlassProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} MagnifyingGlassEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} MagnifyingGlassSlots */
|
|
4
|
+
export default class MagnifyingGlass extends SvelteComponentTyped<{}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> {
|
|
7
|
+
}
|
|
8
|
+
export type MagnifyingGlassProps = typeof __propDef.props;
|
|
9
|
+
export type MagnifyingGlassEvents = typeof __propDef.events;
|
|
10
|
+
export type MagnifyingGlassSlots = typeof __propDef.slots;
|
|
11
|
+
import { SvelteComponentTyped } from "svelte";
|
|
12
|
+
declare const __propDef: {
|
|
13
|
+
props: {};
|
|
14
|
+
events: {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
};
|
|
17
|
+
slots: {};
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
/**
|
|
5
|
+
* The current page number.
|
|
6
|
+
* @type {number}
|
|
7
|
+
*/ pageNumber?: number;
|
|
8
|
+
/**
|
|
9
|
+
* The default page size.
|
|
10
|
+
* @type {number}
|
|
11
|
+
*/ pageSize?: number;
|
|
12
|
+
/**
|
|
13
|
+
* The number of records in the current page.
|
|
14
|
+
* @type {number}
|
|
15
|
+
*/ pageLength?: number;
|
|
16
|
+
/**
|
|
17
|
+
* The total number of records in the data set.
|
|
18
|
+
* @type {number}
|
|
19
|
+
*/ n?: number;
|
|
20
|
+
};
|
|
21
|
+
events: {
|
|
22
|
+
[evt: string]: CustomEvent<any>;
|
|
23
|
+
};
|
|
24
|
+
slots: {};
|
|
25
|
+
};
|
|
26
|
+
export declare type PaginationProps = typeof __propDef.props;
|
|
27
|
+
export declare type PaginationEvents = typeof __propDef.events;
|
|
28
|
+
export declare type PaginationSlots = typeof __propDef.slots;
|
|
29
|
+
export default class Pagination extends SvelteComponentTyped<PaginationProps, PaginationEvents, PaginationSlots> {
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} RightArrowProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} RightArrowEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} RightArrowSlots */
|
|
4
|
+
export default class RightArrow extends SvelteComponentTyped<{}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> {
|
|
7
|
+
}
|
|
8
|
+
export type RightArrowProps = typeof __propDef.props;
|
|
9
|
+
export type RightArrowEvents = typeof __propDef.events;
|
|
10
|
+
export type RightArrowSlots = typeof __propDef.slots;
|
|
11
|
+
import { SvelteComponentTyped } from "svelte";
|
|
12
|
+
declare const __propDef: {
|
|
13
|
+
props: {};
|
|
14
|
+
events: {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
};
|
|
17
|
+
slots: {};
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
/**
|
|
5
|
+
* The placeholder text that appears in the search box.
|
|
6
|
+
* @type {string}
|
|
7
|
+
*/ searchPlaceholder?: string;
|
|
8
|
+
};
|
|
9
|
+
events: {
|
|
10
|
+
search: CustomEvent<any>;
|
|
11
|
+
} & {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
};
|
|
14
|
+
slots: {};
|
|
15
|
+
};
|
|
16
|
+
export declare type SearchProps = typeof __propDef.props;
|
|
17
|
+
export declare type SearchEvents = typeof __propDef.events;
|
|
18
|
+
export declare type SearchSlots = typeof __propDef.slots;
|
|
19
|
+
export default class Search extends SvelteComponentTyped<SearchProps, SearchEvents, SearchSlots> {
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { Option } from '../@types/global';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
/**
|
|
6
|
+
* The label that appears above the select input.
|
|
7
|
+
* @type {string}
|
|
8
|
+
*/ label?: string;
|
|
9
|
+
/**
|
|
10
|
+
* The label that appears above the select input.
|
|
11
|
+
* @type {Array}
|
|
12
|
+
*/ options?: Option[];
|
|
13
|
+
};
|
|
14
|
+
events: {
|
|
15
|
+
select: CustomEvent<any>;
|
|
16
|
+
} & {
|
|
17
|
+
[evt: string]: CustomEvent<any>;
|
|
18
|
+
};
|
|
19
|
+
slots: {};
|
|
20
|
+
};
|
|
21
|
+
export declare type SelectProps = typeof __propDef.props;
|
|
22
|
+
export declare type SelectEvents = typeof __propDef.events;
|
|
23
|
+
export declare type SelectSlots = typeof __propDef.slots;
|
|
24
|
+
export default class Select extends SvelteComponentTyped<SelectProps, SelectEvents, SelectSlots> {
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
sortDirection?: "ascending" | "descending";
|
|
5
|
+
/**
|
|
6
|
+
* Whether or not this arrow is currently sorting. It is false by default.
|
|
7
|
+
* @type {boolean}
|
|
8
|
+
*/ active?: boolean;
|
|
9
|
+
};
|
|
10
|
+
events: {
|
|
11
|
+
[evt: string]: CustomEvent<any>;
|
|
12
|
+
};
|
|
13
|
+
slots: {};
|
|
14
|
+
};
|
|
15
|
+
export declare type SortArrowProps = typeof __propDef.props;
|
|
16
|
+
export declare type SortArrowEvents = typeof __propDef.events;
|
|
17
|
+
export declare type SortArrowSlots = typeof __propDef.slots;
|
|
18
|
+
export default class SortArrow extends SvelteComponentTyped<SortArrowProps, SortArrowEvents, SortArrowSlots> {
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
/**
|
|
5
|
+
* A source for the data.
|
|
6
|
+
* @type []
|
|
7
|
+
* @required
|
|
8
|
+
*/ data: [];
|
|
9
|
+
/**
|
|
10
|
+
* A title that runs above the table.
|
|
11
|
+
* @type {string}
|
|
12
|
+
*/ title?: string | null;
|
|
13
|
+
/**
|
|
14
|
+
* A block of text that runs above the table.
|
|
15
|
+
* @type {string}
|
|
16
|
+
*/ dek?: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* A footnote that runs below the table.
|
|
19
|
+
* @type {string}
|
|
20
|
+
*/ notes?: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* A source line that runs below the table.
|
|
23
|
+
* @type {string}
|
|
24
|
+
*/ source?: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* list of the fields to include in the table. By default everything goes.
|
|
27
|
+
* @type []
|
|
28
|
+
*/ includedFields?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Whether or not the table is cutoff after a set number of rows.
|
|
31
|
+
* @type {boolean}
|
|
32
|
+
*/ truncated?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* If the table is truncated, how many rows to allow before the cutoff.
|
|
35
|
+
* @type {number}
|
|
36
|
+
*/ truncateLength?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Whether or not the table is paginated after a set number of rows.
|
|
39
|
+
* @type {boolean}
|
|
40
|
+
*/ paginated?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The default page size.
|
|
43
|
+
* @type {number}
|
|
44
|
+
*/ pageSize?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Whether or not searches are allowed.
|
|
47
|
+
* @type {boolean}
|
|
48
|
+
*/ searchable?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* The placeholder text that appears in the search box.
|
|
51
|
+
* @type {string}
|
|
52
|
+
*/ searchPlaceholder?: string;
|
|
53
|
+
/**
|
|
54
|
+
* A field to offer uses as an interactive filter.
|
|
55
|
+
* @type {string}
|
|
56
|
+
*/ filterField: string;
|
|
57
|
+
/**
|
|
58
|
+
* The label to place above the filter box
|
|
59
|
+
* @type {string}
|
|
60
|
+
*/ filterLabel: string;
|
|
61
|
+
/**
|
|
62
|
+
* Whether or not sorts are allowed.
|
|
63
|
+
* @type {boolean}
|
|
64
|
+
*/ sortable?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* The column to sort by. By default it's the first header.
|
|
67
|
+
* @type {string}
|
|
68
|
+
*/ sortField?: string;
|
|
69
|
+
/**
|
|
70
|
+
* The columns that are allowed to sort. It's all of them by default.
|
|
71
|
+
* @type {string}
|
|
72
|
+
*/ sortableFields?: string[];
|
|
73
|
+
sortDirection?: "ascending" | "descending";
|
|
74
|
+
/**
|
|
75
|
+
* Custom field formatting functions. Should be keyed to the name of the field.
|
|
76
|
+
* @type {object}
|
|
77
|
+
*/ fieldFormatters?: object;
|
|
78
|
+
width?: "normal" | "wide" | "wider" | "widest" | "fluid";
|
|
79
|
+
/** Add an ID to target with SCSS. */ id?: string;
|
|
80
|
+
/** Add a class to target with SCSS. */ cls?: string;
|
|
81
|
+
};
|
|
82
|
+
events: {
|
|
83
|
+
[evt: string]: CustomEvent<any>;
|
|
84
|
+
};
|
|
85
|
+
slots: {};
|
|
86
|
+
};
|
|
87
|
+
export declare type TableProps = typeof __propDef.props;
|
|
88
|
+
export declare type TableEvents = typeof __propDef.events;
|
|
89
|
+
export declare type TableSlots = typeof __propDef.slots;
|
|
90
|
+
/** `Table` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-Table--default) */
|
|
91
|
+
export default class Table extends SvelteComponentTyped<TableProps, TableEvents, TableSlots> {
|
|
92
|
+
}
|
|
93
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} XProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} XEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} XSlots */
|
|
4
|
+
export default class X extends SvelteComponentTyped<{}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> {
|
|
7
|
+
}
|
|
8
|
+
export type XProps = typeof __propDef.props;
|
|
9
|
+
export type XEvents = typeof __propDef.events;
|
|
10
|
+
export type XSlots = typeof __propDef.slots;
|
|
11
|
+
import { SvelteComponentTyped } from "svelte";
|
|
12
|
+
declare const __propDef: {
|
|
13
|
+
props: {};
|
|
14
|
+
events: {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
};
|
|
17
|
+
slots: {};
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function filterArray(data: any, searchText: any, filterField: any, filterValue: any): any;
|
|
2
|
+
export function paginateArray(array: any, pageSize: any, pageNumber: any): any;
|
|
3
|
+
export function uniqueAttr(array: any, attr: any): any;
|
|
4
|
+
export function unique(value: any, index: any, array: any): boolean;
|
|
5
|
+
export function getOptions(data: any, attr: any): any;
|
package/dist/@types/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export { default as SiteFooter } from "./components/SiteFooter/SiteFooter.svelte
|
|
|
27
27
|
export { default as SiteHeader } from "./components/SiteHeader/SiteHeader.svelte";
|
|
28
28
|
export { default as SiteHeadline } from "./components/SiteHeadline/SiteHeadline.svelte";
|
|
29
29
|
export { default as Spinner } from "./components/Spinner/Spinner.svelte";
|
|
30
|
+
export { default as Table } from "./components/Table/Table.svelte";
|
|
30
31
|
export { default as ToolsHeader } from "./components/ToolsHeader/ToolsHeader.svelte";
|
|
31
32
|
export { default as Video } from "./components/Video/Video.svelte";
|
|
32
33
|
export { default as Visible } from "./components/Visible/Visible.svelte";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
class="icon"
|
|
3
|
+
aria-hidden="true"
|
|
4
|
+
focusable="false"
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
viewBox="0 0 6 11"
|
|
7
|
+
><path
|
|
8
|
+
d="m1.76 5.134 3.887-3.887a.71.71 0 0 0 0-1.027.709.709 0 0 0-1.027 0l-4.4 4.4a.71.71 0 0 0 0 1.027l4.4 4.4c.147.147.367.22.513.22a.79.79 0 0 0 .513-.22.71.71 0 0 0 0-1.027L1.76 5.133Z"
|
|
9
|
+
></path></svg
|
|
10
|
+
>
|
|
11
|
+
|
|
12
|
+
<style>
|
|
13
|
+
.icon {
|
|
14
|
+
height: 1rem;
|
|
15
|
+
width: 1rem;
|
|
16
|
+
fill: currentColor;
|
|
17
|
+
}</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
width="18"
|
|
3
|
+
height="18"
|
|
4
|
+
viewBox="0 0 18 18"
|
|
5
|
+
fill="none"
|
|
6
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
d="M3.41069 12.0711C2.83695 11.5053 2.38137 10.8311 2.07042 10.0878C1.75947 9.3444 1.59934 8.54666 1.59934 7.74088C1.59934 6.9351 1.75947 6.13735 2.07042 5.39399C2.38137 4.65063 2.83695 3.97647 3.41069 3.41069C3.97647 2.83695 4.65063 2.38137 5.39399 2.07042C6.13735 1.75947 6.9351 1.59934 7.74088 1.59934C8.54666 1.59934 9.3444 1.75947 10.0878 2.07042C10.8311 2.38137 11.5053 2.83695 12.0711 3.41069C12.6448 3.97647 13.1004 4.65063 13.4113 5.39399C13.7223 6.13735 13.8824 6.9351 13.8824 7.74088C13.8824 8.54666 13.7223 9.3444 13.4113 10.0878C13.1004 10.8311 12.6448 11.5053 12.0711 12.0711C11.5053 12.6448 10.8311 13.1004 10.0878 13.4113C9.3444 13.7223 8.54666 13.8824 7.74088 13.8824C6.9351 13.8824 6.13735 13.7223 5.39399 13.4113C4.65063 13.1004 3.97647 12.6448 3.41069 12.0711ZM17.8254 16.6899L13.7454 12.6099C14.9941 11.0703 15.6041 9.11021 15.4497 7.13395C15.2953 5.1577 14.3882 3.3161 12.9156 1.98914C11.4429 0.662179 9.51715 -0.0489011 7.53554 0.00261584C5.55393 0.0541328 3.66769 0.864316 2.266 2.266C0.864316 3.66769 0.0541328 5.55393 0.00261584 7.53554C-0.0489011 9.51715 0.662179 11.4429 1.98914 12.9156C3.3161 14.3882 5.1577 15.2953 7.13395 15.4497C9.11021 15.6041 11.0703 14.9941 12.6099 13.7454L16.6899 17.8254C16.8453 17.9485 17.0405 18.0101 17.2384 17.9986C17.4363 17.9872 17.6231 17.9034 17.7633 17.7633C17.9034 17.6231 17.9872 17.4363 17.9986 17.2384C18.0101 17.0405 17.9485 16.8453 17.8254 16.6899Z"
|
|
10
|
+
></path>
|
|
11
|
+
</svg>
|
|
12
|
+
|
|
13
|
+
<style>
|
|
14
|
+
svg path {
|
|
15
|
+
fill: var(--theme-colour-text-secondary);
|
|
16
|
+
}</style>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script>import { intcomma } from 'journalize';
|
|
2
|
+
import LeftArrow from './LeftArrow.svelte';
|
|
3
|
+
import RightArrow from './RightArrow.svelte';
|
|
4
|
+
/**
|
|
5
|
+
* The current page number.
|
|
6
|
+
* @type {number}
|
|
7
|
+
*/
|
|
8
|
+
export let pageNumber = 1;
|
|
9
|
+
/**
|
|
10
|
+
* The default page size.
|
|
11
|
+
* @type {number}
|
|
12
|
+
*/
|
|
13
|
+
export let pageSize = 25;
|
|
14
|
+
/**
|
|
15
|
+
* The number of records in the current page.
|
|
16
|
+
* @type {number}
|
|
17
|
+
*/
|
|
18
|
+
export let pageLength = null;
|
|
19
|
+
/**
|
|
20
|
+
* The total number of records in the data set.
|
|
21
|
+
* @type {number}
|
|
22
|
+
*/
|
|
23
|
+
export let n = null;
|
|
24
|
+
$: minRow = pageNumber * pageSize - pageSize + 1;
|
|
25
|
+
$: maxRow = pageNumber * pageSize - pageSize + pageLength;
|
|
26
|
+
$: numPages = Math.ceil(n / pageSize);
|
|
27
|
+
function goToPreviousPage() {
|
|
28
|
+
if (pageNumber > 1) {
|
|
29
|
+
pageNumber -= 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function goToNextPage() {
|
|
33
|
+
if (pageNumber < numPages) {
|
|
34
|
+
pageNumber += 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<nav aria-label="pagination" class="pagination">
|
|
40
|
+
<button on:click="{goToPreviousPage}" disabled="{pageNumber === 1}"
|
|
41
|
+
><div class="icon-wrapper">
|
|
42
|
+
<LeftArrow />
|
|
43
|
+
<span class="visually-hidden">Previous page</span>
|
|
44
|
+
</div></button
|
|
45
|
+
>
|
|
46
|
+
<div class="label" aria-label="page {pageNumber}" aria-current="page">
|
|
47
|
+
<div class="records">{minRow}-{maxRow} of {intcomma(n)}</div>
|
|
48
|
+
</div>
|
|
49
|
+
<button
|
|
50
|
+
on:click="{goToNextPage}"
|
|
51
|
+
disabled="{pageNumber === Math.ceil(n / pageSize)}"
|
|
52
|
+
><div class="icon-wrapper">
|
|
53
|
+
<RightArrow />
|
|
54
|
+
<span class="visually-hidden">Next page</span>
|
|
55
|
+
</div></button
|
|
56
|
+
>
|
|
57
|
+
</nav>
|
|
58
|
+
|
|
59
|
+
<style>nav.pagination {
|
|
60
|
+
display: flex;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
align-items: center;
|
|
63
|
+
margin-top: 1rem;
|
|
64
|
+
}
|
|
65
|
+
nav.pagination button {
|
|
66
|
+
border: 1px solid var(--theme-colour-text-secondary, #afafaf);
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
background: var(--theme-color-background);
|
|
69
|
+
color: var(--theme-colour-text-secondary, #afafaf);
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
width: 35px;
|
|
72
|
+
height: 35px;
|
|
73
|
+
}
|
|
74
|
+
nav.pagination button:disabled {
|
|
75
|
+
cursor: default;
|
|
76
|
+
color: var(--theme-colour-brand-rules);
|
|
77
|
+
border-color: var(--theme-colour-brand-rules);
|
|
78
|
+
}
|
|
79
|
+
nav.pagination button:disabled .icon-wrapper:hover {
|
|
80
|
+
color: var(--theme-colour-brand-rules);
|
|
81
|
+
border-color: var(--theme-colour-brand-rules);
|
|
82
|
+
}
|
|
83
|
+
nav.pagination button .icon-wrapper {
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: center;
|
|
86
|
+
justify-content: center;
|
|
87
|
+
white-space: nowrap;
|
|
88
|
+
}
|
|
89
|
+
nav.pagination button .icon-wrapper:hover {
|
|
90
|
+
color: var(--theme-colour-text-primary, #666666);
|
|
91
|
+
border-color: var(--theme-colour-text-primary, #666666);
|
|
92
|
+
}
|
|
93
|
+
nav.pagination .label {
|
|
94
|
+
display: flex;
|
|
95
|
+
align-items: center;
|
|
96
|
+
flex-direction: column;
|
|
97
|
+
width: auto;
|
|
98
|
+
min-width: 110px;
|
|
99
|
+
margin: 0 0.5rem;
|
|
100
|
+
}
|
|
101
|
+
nav.pagination .label .records {
|
|
102
|
+
font-size: 0.8rem;
|
|
103
|
+
font-family: var(--theme-font-family-hed, "Knowledge", "Source Sans Pro", Arial, sans-serif);
|
|
104
|
+
font-weight: 300;
|
|
105
|
+
margin: 0 1rem;
|
|
106
|
+
color: var(--theme-colour-text-primary, #666666);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.visually-hidden {
|
|
110
|
+
clip: rect(0 0 0 0);
|
|
111
|
+
-webkit-clip-path: inset(50%);
|
|
112
|
+
clip-path: inset(50%);
|
|
113
|
+
height: 1px;
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
position: absolute;
|
|
116
|
+
white-space: nowrap;
|
|
117
|
+
width: 1px;
|
|
118
|
+
}</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
class="icon"
|
|
3
|
+
aria-hidden="true"
|
|
4
|
+
focusable="false"
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
viewBox="0 0 7 11"
|
|
7
|
+
><path
|
|
8
|
+
d="m6.013 4.987-4.4-4.4a.71.71 0 0 0-1.027 0 .709.709 0 0 0 0 1.027L4.473 5.5.586 9.387a.71.71 0 0 0 0 1.027c.147.147.293.22.513.22.22 0 .367-.073.514-.22l4.4-4.4a.71.71 0 0 0 0-1.027Z"
|
|
9
|
+
></path>
|
|
10
|
+
</svg>
|
|
11
|
+
|
|
12
|
+
<style>
|
|
13
|
+
.icon {
|
|
14
|
+
height: 1rem;
|
|
15
|
+
width: 1rem;
|
|
16
|
+
fill: currentColor;
|
|
17
|
+
}</style>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script>import { createEventDispatcher } from 'svelte';
|
|
2
|
+
import MagnifyingGlass from './MagnifyingGlass.svelte';
|
|
3
|
+
import X from './X.svelte';
|
|
4
|
+
/**
|
|
5
|
+
* The placeholder text that appears in the search box.
|
|
6
|
+
* @type {string}
|
|
7
|
+
*/
|
|
8
|
+
export let searchPlaceholder = 'Search in table';
|
|
9
|
+
let value = '';
|
|
10
|
+
$: active = value !== '';
|
|
11
|
+
const dispatch = createEventDispatcher();
|
|
12
|
+
function input(event) {
|
|
13
|
+
value = event.target.value;
|
|
14
|
+
dispatch('search', { value });
|
|
15
|
+
}
|
|
16
|
+
function clear() {
|
|
17
|
+
value = '';
|
|
18
|
+
dispatch('search', { value: '' });
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class="search" class:active>
|
|
23
|
+
<div class="search--icon">
|
|
24
|
+
<MagnifyingGlass />
|
|
25
|
+
</div>
|
|
26
|
+
<input
|
|
27
|
+
id="search--input"
|
|
28
|
+
class="search--input"
|
|
29
|
+
type="text"
|
|
30
|
+
placeholder="{searchPlaceholder}"
|
|
31
|
+
on:input="{input}"
|
|
32
|
+
bind:value
|
|
33
|
+
/>
|
|
34
|
+
<div class="search--x" class:invisible="{!active}" on:click="{clear}">
|
|
35
|
+
<X />
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<style>.search {
|
|
40
|
+
position: relative;
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
width: 256px;
|
|
44
|
+
padding: 0 0 0 0.1rem;
|
|
45
|
+
}
|
|
46
|
+
.search .search--icon {
|
|
47
|
+
position: absolute;
|
|
48
|
+
left: 0.5rem;
|
|
49
|
+
top: 0.15rem;
|
|
50
|
+
width: 1.5rem;
|
|
51
|
+
height: 1.5rem;
|
|
52
|
+
fill: var(--theme-colour-brand-rules, #d0d0d0);
|
|
53
|
+
}
|
|
54
|
+
.search .search--input {
|
|
55
|
+
font-family: var(--theme-font-family-hed, "Knowledge", "Source Sans Pro", Arial, sans-serif);
|
|
56
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
57
|
+
padding: 0 0 0 2rem;
|
|
58
|
+
font-size: 0.8rem;
|
|
59
|
+
height: 33px;
|
|
60
|
+
border: 1px solid var(--theme-colour-brand-rules, #d0d0d0);
|
|
61
|
+
background: transparent;
|
|
62
|
+
border-radius: 6px;
|
|
63
|
+
width: 100%;
|
|
64
|
+
}
|
|
65
|
+
.search .search--x {
|
|
66
|
+
position: absolute;
|
|
67
|
+
right: 0;
|
|
68
|
+
top: 0.15rem;
|
|
69
|
+
width: 1.5rem;
|
|
70
|
+
height: 1.5rem;
|
|
71
|
+
fill: var(--theme-colour-text-primary, #666666);
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
}
|
|
74
|
+
.search .search--x.invisible {
|
|
75
|
+
display: none;
|
|
76
|
+
}</style>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script>import { createEventDispatcher } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* The label that appears above the select input.
|
|
4
|
+
* @type {string}
|
|
5
|
+
*/
|
|
6
|
+
export let label = '';
|
|
7
|
+
/**
|
|
8
|
+
* The label that appears above the select input.
|
|
9
|
+
* @type {Array}
|
|
10
|
+
*/
|
|
11
|
+
export let options = [];
|
|
12
|
+
const dispatch = createEventDispatcher();
|
|
13
|
+
function input(event) {
|
|
14
|
+
const value = event.target.value;
|
|
15
|
+
dispatch('select', { value });
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<div class="select">
|
|
20
|
+
{#if label}
|
|
21
|
+
<label for="select--input">{label}</label>
|
|
22
|
+
{/if}
|
|
23
|
+
<select
|
|
24
|
+
class="select--input"
|
|
25
|
+
name="select--input"
|
|
26
|
+
id="select--input"
|
|
27
|
+
on:input="{input}"
|
|
28
|
+
>
|
|
29
|
+
{#each options as obj}
|
|
30
|
+
<option value="{obj.value}">{obj.text}</option>
|
|
31
|
+
{/each}
|
|
32
|
+
</select>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<style>.select {
|
|
36
|
+
width: 256px;
|
|
37
|
+
font-family: var(--theme-font-family-hed, "Knowledge", "Source Sans Pro", Arial, sans-serif);
|
|
38
|
+
}
|
|
39
|
+
.select label {
|
|
40
|
+
display: block;
|
|
41
|
+
font-size: 0.8rem;
|
|
42
|
+
font-weight: 300;
|
|
43
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
44
|
+
padding: 0 0 0.125rem 0;
|
|
45
|
+
}
|
|
46
|
+
.select .select--input {
|
|
47
|
+
position: relative;
|
|
48
|
+
font-size: 0.8rem;
|
|
49
|
+
font-weight: 400;
|
|
50
|
+
line-height: 1;
|
|
51
|
+
height: 33px;
|
|
52
|
+
border: 1px solid var(--theme-colour-brand-rules, #d0d0d0);
|
|
53
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
54
|
+
border-radius: 6px;
|
|
55
|
+
width: 100%;
|
|
56
|
+
padding: 0.5rem;
|
|
57
|
+
-moz-appearance: none; /* Firefox */
|
|
58
|
+
-webkit-appearance: none; /* Safari and Chrome */
|
|
59
|
+
appearance: none; /* Remove the default arrow */
|
|
60
|
+
padding-right: 20px; /* Add some padding to make room for a custom arrow */
|
|
61
|
+
background: transparent;
|
|
62
|
+
background-image: url('data:image/svg+xml;utf8,<svg width="15" height="9" viewBox="0 0 15 9" xmlns="http://www.w3.org/2000/svg"><path d="M6.76474 8.30466L0.236082 1.54523C-0.0786943 1.21934 -0.0786943 0.69069 0.236082 0.364804C0.550521 0.0392666 1.19794 0.0403099 1.51305 0.364804L7.33483 6.49522L12.9249 0.475171C13.3549 0.0451683 14.1195 0.0396141 14.4339 0.365152C14.7487 0.691037 14.7487 1.21969 14.4339 1.54557L7.90492 8.30466C7.59015 8.63054 7.07952 8.63054 6.76474 8.30466Z" fill="gray"/></svg>');
|
|
63
|
+
background-repeat: no-repeat;
|
|
64
|
+
background-position-x: 235px;
|
|
65
|
+
background-position-y: 55%;
|
|
66
|
+
}
|
|
67
|
+
.select .select--input::-ms-expand {
|
|
68
|
+
display: none; /* Remove the default arrow in Internet Explorer 11 */
|
|
69
|
+
}</style>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script>export let sortDirection = 'ascending';
|
|
2
|
+
/**
|
|
3
|
+
* Whether or not this arrow is currently sorting. It is false by default.
|
|
4
|
+
* @type {boolean}
|
|
5
|
+
*/
|
|
6
|
+
export let active = false;
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<svg
|
|
10
|
+
width="15"
|
|
11
|
+
height="21"
|
|
12
|
+
viewBox="0 0 15 21"
|
|
13
|
+
fill="none"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
+
class="avoid-clicks"
|
|
16
|
+
>
|
|
17
|
+
<path
|
|
18
|
+
class:active="{sortDirection === 'descending' && active}"
|
|
19
|
+
d="M6.76474 20.2244L0.236082 13.4649C-0.0786943 13.139 -0.0786943 12.6104 0.236082 12.2845C0.550521 11.959 1.19794 11.96 1.51305 12.2845L7.33483 12.2845L13 12.2845C13.43 11.8545 14.1195 11.9593 14.4339 12.2849C14.7487 12.6107 14.7487 13.1394 14.4339 13.4653L7.90492 20.2244C7.59015 20.5503 7.07952 20.5503 6.76474 20.2244Z"
|
|
20
|
+
></path>
|
|
21
|
+
<path
|
|
22
|
+
class:active="{sortDirection === 'ascending' && active}"
|
|
23
|
+
d="M7.90518 0.244414L14.4338 7.00385C14.7486 7.32973 14.7486 7.85838 14.4338 8.18427C14.1194 8.50981 13.472 8.50876 13.1569 8.18427L7.33509 8.18427L1.66992 8.18427C1.23992 8.61427 0.550443 8.50946 0.236003 8.18392C-0.0787725 7.85803 -0.0787725 7.32938 0.236003 7.0035L6.765 0.244414C7.07978 -0.0814713 7.5904 -0.0814713 7.90518 0.244414Z"
|
|
24
|
+
></path>
|
|
25
|
+
</svg>
|
|
26
|
+
|
|
27
|
+
<style>.avoid-clicks {
|
|
28
|
+
pointer-events: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
path {
|
|
32
|
+
fill: var(--theme-colour-brand-rules, #d0d0d0);
|
|
33
|
+
}
|
|
34
|
+
path.active {
|
|
35
|
+
fill: var(--theme-colour-text-primary, #404040);
|
|
36
|
+
}</style>
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
<!-- @component `Table` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-Table--default) -->
|
|
2
|
+
<script>import { onMount } from 'svelte';
|
|
3
|
+
/**
|
|
4
|
+
* A source for the data.
|
|
5
|
+
* @type []
|
|
6
|
+
* @required
|
|
7
|
+
*/
|
|
8
|
+
export let data;
|
|
9
|
+
/**
|
|
10
|
+
* A title that runs above the table.
|
|
11
|
+
* @type {string}
|
|
12
|
+
*/
|
|
13
|
+
export let title = null;
|
|
14
|
+
/**
|
|
15
|
+
* A block of text that runs above the table.
|
|
16
|
+
* @type {string}
|
|
17
|
+
*/
|
|
18
|
+
export let dek = null;
|
|
19
|
+
/**
|
|
20
|
+
* A footnote that runs below the table.
|
|
21
|
+
* @type {string}
|
|
22
|
+
*/
|
|
23
|
+
export let notes = null;
|
|
24
|
+
/**
|
|
25
|
+
* A source line that runs below the table.
|
|
26
|
+
* @type {string}
|
|
27
|
+
*/
|
|
28
|
+
export let source = null;
|
|
29
|
+
/**
|
|
30
|
+
* list of the fields to include in the table. By default everything goes.
|
|
31
|
+
* @type []
|
|
32
|
+
*/
|
|
33
|
+
export let includedFields = Object.keys(data[0]).filter((f) => f !== 'searchStr');
|
|
34
|
+
/**
|
|
35
|
+
* Whether or not the table is cutoff after a set number of rows.
|
|
36
|
+
* @type {boolean}
|
|
37
|
+
*/
|
|
38
|
+
export let truncated = false;
|
|
39
|
+
/**
|
|
40
|
+
* If the table is truncated, how many rows to allow before the cutoff.
|
|
41
|
+
* @type {number}
|
|
42
|
+
*/
|
|
43
|
+
export let truncateLength = 5;
|
|
44
|
+
/**
|
|
45
|
+
* Whether or not the table is paginated after a set number of rows.
|
|
46
|
+
* @type {boolean}
|
|
47
|
+
*/
|
|
48
|
+
export let paginated = false;
|
|
49
|
+
/**
|
|
50
|
+
* The default page size.
|
|
51
|
+
* @type {number}
|
|
52
|
+
*/
|
|
53
|
+
export let pageSize = 25;
|
|
54
|
+
/**
|
|
55
|
+
* Whether or not searches are allowed.
|
|
56
|
+
* @type {boolean}
|
|
57
|
+
*/
|
|
58
|
+
export let searchable = false;
|
|
59
|
+
/**
|
|
60
|
+
* The placeholder text that appears in the search box.
|
|
61
|
+
* @type {string}
|
|
62
|
+
*/
|
|
63
|
+
export let searchPlaceholder = 'Search in table';
|
|
64
|
+
/**
|
|
65
|
+
* A field to offer uses as an interactive filter.
|
|
66
|
+
* @type {string}
|
|
67
|
+
*/
|
|
68
|
+
export let filterField;
|
|
69
|
+
/**
|
|
70
|
+
* The label to place above the filter box
|
|
71
|
+
* @type {string}
|
|
72
|
+
*/
|
|
73
|
+
export let filterLabel;
|
|
74
|
+
/**
|
|
75
|
+
* Whether or not sorts are allowed.
|
|
76
|
+
* @type {boolean}
|
|
77
|
+
*/
|
|
78
|
+
export let sortable = false;
|
|
79
|
+
/**
|
|
80
|
+
* The column to sort by. By default it's the first header.
|
|
81
|
+
* @type {string}
|
|
82
|
+
*/
|
|
83
|
+
export let sortField = Object.keys(data[0])[0];
|
|
84
|
+
/**
|
|
85
|
+
* The columns that are allowed to sort. It's all of them by default.
|
|
86
|
+
* @type {string}
|
|
87
|
+
*/
|
|
88
|
+
export let sortableFields = Object.keys(data[0]).filter((f) => f !== 'searchStr');
|
|
89
|
+
export let sortDirection = 'ascending';
|
|
90
|
+
/**
|
|
91
|
+
* Custom field formatting functions. Should be keyed to the name of the field.
|
|
92
|
+
* @type {object}
|
|
93
|
+
*/
|
|
94
|
+
export let fieldFormatters = {};
|
|
95
|
+
export let width = 'normal';
|
|
96
|
+
/** Add an ID to target with SCSS. */
|
|
97
|
+
export let id = '';
|
|
98
|
+
/** Add a class to target with SCSS. */
|
|
99
|
+
export let cls = '';
|
|
100
|
+
/** Import local helpers */
|
|
101
|
+
import Block from '../Block/Block.svelte';
|
|
102
|
+
import Pagination from './Pagination.svelte';
|
|
103
|
+
import Search from './Search.svelte';
|
|
104
|
+
import Select from './Select.svelte';
|
|
105
|
+
import SortArrow from './SortArrow.svelte';
|
|
106
|
+
import { filterArray, paginateArray, getOptions } from './utils.js';
|
|
107
|
+
/** Set truncate, filtering and pagination configuration */
|
|
108
|
+
let showAll = false;
|
|
109
|
+
let pageNumber = 1;
|
|
110
|
+
let searchText = '';
|
|
111
|
+
const filterList = filterField ? getOptions(data, filterField) : undefined;
|
|
112
|
+
let filterValue = '';
|
|
113
|
+
$: filteredData = filterArray(data, searchText, filterField, filterValue);
|
|
114
|
+
$: sortedData = sortArray(filteredData, sortField, sortDirection);
|
|
115
|
+
$: currentPageData = truncated
|
|
116
|
+
? showAll
|
|
117
|
+
? sortedData
|
|
118
|
+
: sortedData.slice(0, truncateLength + 1)
|
|
119
|
+
: paginated
|
|
120
|
+
? paginateArray(sortedData, pageSize, pageNumber)
|
|
121
|
+
: sortedData;
|
|
122
|
+
//* * Handle show all, search, filter, sort and pagination events */
|
|
123
|
+
function toggleTruncate(event) {
|
|
124
|
+
showAll = !showAll;
|
|
125
|
+
}
|
|
126
|
+
function handleSearchInput(event) {
|
|
127
|
+
searchText = event.detail.value;
|
|
128
|
+
pageNumber = 1;
|
|
129
|
+
}
|
|
130
|
+
function handleFilterInput(event) {
|
|
131
|
+
const value = event.detail.value;
|
|
132
|
+
filterValue = value === 'All' ? '' : value;
|
|
133
|
+
pageNumber = 1;
|
|
134
|
+
}
|
|
135
|
+
function handleSort(event) {
|
|
136
|
+
if (!sortable)
|
|
137
|
+
return;
|
|
138
|
+
sortField = event.target.getAttribute('data-field');
|
|
139
|
+
sortDirection = sortDirection === 'ascending' ? 'descending' : 'ascending';
|
|
140
|
+
}
|
|
141
|
+
function sortArray(array, column, direction) {
|
|
142
|
+
if (!sortable)
|
|
143
|
+
return array;
|
|
144
|
+
return array.sort((a, b) => {
|
|
145
|
+
if (a[column] < b[column]) {
|
|
146
|
+
return direction === 'ascending' ? -1 : 1;
|
|
147
|
+
}
|
|
148
|
+
else if (a[column] > b[column]) {
|
|
149
|
+
return direction === 'ascending' ? 1 : -1;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function formatValue(item, field) {
|
|
157
|
+
const value = item[field];
|
|
158
|
+
if (field in fieldFormatters) {
|
|
159
|
+
const func = fieldFormatters[field];
|
|
160
|
+
return func(value);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** Boot it up. */
|
|
167
|
+
onMount(() => {
|
|
168
|
+
data.forEach((d) => {
|
|
169
|
+
// Compose the string we will allow users to search
|
|
170
|
+
d.searchStr = includedFields
|
|
171
|
+
.map((field) => d[field])
|
|
172
|
+
.join(' ')
|
|
173
|
+
.toLowerCase();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<Block width="{width}" id="{id}" cls="{cls}">
|
|
179
|
+
<article class="table-wrapper">
|
|
180
|
+
{#if title || dek || searchable || filterList}
|
|
181
|
+
<header class="table--header">
|
|
182
|
+
{#if title}
|
|
183
|
+
<h2 class="table--header--title">{@html title}</h2>
|
|
184
|
+
{/if}
|
|
185
|
+
{#if dek}
|
|
186
|
+
<p class="table--header--dek">{@html dek}</p>
|
|
187
|
+
{/if}
|
|
188
|
+
{#if searchable || filterList}
|
|
189
|
+
<nav class="input">
|
|
190
|
+
{#if filterList}
|
|
191
|
+
<div class="table--header--filter">
|
|
192
|
+
<Select
|
|
193
|
+
label="{filterLabel || filterField}"
|
|
194
|
+
options="{filterList}"
|
|
195
|
+
on:select="{handleFilterInput}"
|
|
196
|
+
/>
|
|
197
|
+
</div>
|
|
198
|
+
{/if}
|
|
199
|
+
{#if searchable}
|
|
200
|
+
<div class="table--header--search">
|
|
201
|
+
<Search
|
|
202
|
+
bind:searchPlaceholder
|
|
203
|
+
on:search="{handleSearchInput}"
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
{/if}
|
|
207
|
+
</nav>
|
|
208
|
+
{/if}
|
|
209
|
+
</header>
|
|
210
|
+
{/if}
|
|
211
|
+
<section class="table">
|
|
212
|
+
<table
|
|
213
|
+
class:paginated
|
|
214
|
+
class:truncated="{truncated &&
|
|
215
|
+
!showAll &&
|
|
216
|
+
data.length > truncateLength}"
|
|
217
|
+
>
|
|
218
|
+
<thead class="table--thead">
|
|
219
|
+
<tr>
|
|
220
|
+
{#each includedFields as field}
|
|
221
|
+
<th
|
|
222
|
+
scope="col"
|
|
223
|
+
class="table--thead--th"
|
|
224
|
+
class:sortable="{sortable && sortableFields.includes(field)}"
|
|
225
|
+
class:sort-ascending="{sortable &&
|
|
226
|
+
sortField === field &&
|
|
227
|
+
sortDirection === 'ascending'}"
|
|
228
|
+
class:sort-descending="{sortable &&
|
|
229
|
+
sortField === field &&
|
|
230
|
+
sortDirection === 'descending'}"
|
|
231
|
+
data-field="{field}"
|
|
232
|
+
on:click="{handleSort}"
|
|
233
|
+
>
|
|
234
|
+
{field}
|
|
235
|
+
{#if sortable && sortableFields.includes(field)}
|
|
236
|
+
<div class="table--thead--sortarrow avoid-clicks">
|
|
237
|
+
<SortArrow
|
|
238
|
+
bind:sortDirection
|
|
239
|
+
active="{sortField === field}"
|
|
240
|
+
/>
|
|
241
|
+
</div>
|
|
242
|
+
{/if}
|
|
243
|
+
</th>
|
|
244
|
+
{/each}
|
|
245
|
+
</tr>
|
|
246
|
+
</thead>
|
|
247
|
+
<tbody class="table--tbody">
|
|
248
|
+
{#each currentPageData as item, idx}
|
|
249
|
+
<tr data-row-index="{idx}">
|
|
250
|
+
{#each includedFields as field}
|
|
251
|
+
<td
|
|
252
|
+
data-row-index="{idx}"
|
|
253
|
+
data-field="{field}"
|
|
254
|
+
data-value="{item[field]}"
|
|
255
|
+
>
|
|
256
|
+
{@html formatValue(item, field)}
|
|
257
|
+
</td>
|
|
258
|
+
{/each}
|
|
259
|
+
</tr>
|
|
260
|
+
{/each}
|
|
261
|
+
{#if searchable && searchText && currentPageData.length === 0}
|
|
262
|
+
<tr>
|
|
263
|
+
<td class="no-results" colspan="{includedFields.length}">
|
|
264
|
+
No results found for "{searchText}"
|
|
265
|
+
</td>
|
|
266
|
+
</tr>
|
|
267
|
+
{/if}
|
|
268
|
+
</tbody>
|
|
269
|
+
{#if notes || source}
|
|
270
|
+
<tfoot class="table--tfoot">
|
|
271
|
+
{#if notes}
|
|
272
|
+
<tr>
|
|
273
|
+
<td colspan="{includedFields.length}">{@html notes}</td>
|
|
274
|
+
</tr>
|
|
275
|
+
{/if}
|
|
276
|
+
{#if source}
|
|
277
|
+
<tr>
|
|
278
|
+
<td colspan="{includedFields.length}">{@html source}</td>
|
|
279
|
+
</tr>
|
|
280
|
+
{/if}
|
|
281
|
+
</tfoot>
|
|
282
|
+
{/if}
|
|
283
|
+
</table>
|
|
284
|
+
</section>
|
|
285
|
+
{#if truncated && data.length > truncateLength}
|
|
286
|
+
<nav aria-label="Show all button" class="show-all">
|
|
287
|
+
<button on:click="{toggleTruncate}"
|
|
288
|
+
>{#if showAll}Show fewer rows{:else}Show {data.length -
|
|
289
|
+
truncateLength} more rows{/if}</button
|
|
290
|
+
>
|
|
291
|
+
</nav>
|
|
292
|
+
{/if}
|
|
293
|
+
{#if paginated}
|
|
294
|
+
<Pagination
|
|
295
|
+
bind:pageNumber
|
|
296
|
+
bind:pageSize
|
|
297
|
+
bind:pageLength="{currentPageData.length}"
|
|
298
|
+
bind:n="{sortedData.length}"
|
|
299
|
+
/>{/if}
|
|
300
|
+
</article>
|
|
301
|
+
</Block>
|
|
302
|
+
|
|
303
|
+
<style>.table-wrapper {
|
|
304
|
+
font-size: 1rem;
|
|
305
|
+
font-family: var(--theme-font-family-hed, "Knowledge", "Source Sans Pro", Arial, sans-serif);
|
|
306
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.table--header {
|
|
310
|
+
width: 100%;
|
|
311
|
+
}
|
|
312
|
+
.table--header h2.table--header--title {
|
|
313
|
+
font-weight: 500;
|
|
314
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
315
|
+
font-size: 1.33rem;
|
|
316
|
+
padding: 0;
|
|
317
|
+
margin: 0.5rem 0;
|
|
318
|
+
}
|
|
319
|
+
.table--header p.table--header--dek {
|
|
320
|
+
font-family: var(--theme-font-family-hed, "Knowledge", "Source Sans Pro", Arial, sans-serif);
|
|
321
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
322
|
+
font-size: 1rem;
|
|
323
|
+
font-weight: 300;
|
|
324
|
+
line-height: 1.4;
|
|
325
|
+
padding: 0;
|
|
326
|
+
margin: 0.5rem 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
section.table {
|
|
330
|
+
overflow-x: auto;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
section.table table {
|
|
334
|
+
background-color: transparent;
|
|
335
|
+
border-collapse: separate;
|
|
336
|
+
border-spacing: 0;
|
|
337
|
+
width: 100%;
|
|
338
|
+
}
|
|
339
|
+
section.table table thead tr th {
|
|
340
|
+
border-bottom: 1px solid var(--theme-colour-text-primary, #666666);
|
|
341
|
+
color: var(--theme-colour-text-primary, #666666);
|
|
342
|
+
background-color: var(--theme-colour-background, #fff);
|
|
343
|
+
font-size: 0.85rem;
|
|
344
|
+
font-weight: 500;
|
|
345
|
+
text-transform: uppercase;
|
|
346
|
+
letter-spacing: 0.06rem;
|
|
347
|
+
line-height: 1.4;
|
|
348
|
+
padding: 0.5rem 0.25rem 0.5rem 0;
|
|
349
|
+
}
|
|
350
|
+
section.table table thead tr th.sortable {
|
|
351
|
+
cursor: pointer;
|
|
352
|
+
}
|
|
353
|
+
section.table table thead tr th .table--thead--sortarrow {
|
|
354
|
+
display: inline-block;
|
|
355
|
+
margin: 0 0 0 0.125rem;
|
|
356
|
+
}
|
|
357
|
+
section.table table tbody td {
|
|
358
|
+
font-size: 1rem;
|
|
359
|
+
font-weight: 300;
|
|
360
|
+
padding: 0.5rem 0.25rem 0.5rem 0;
|
|
361
|
+
vertical-align: top;
|
|
362
|
+
border-bottom: 1px solid var(--theme-colour-brand-rules, #d0d0d0);
|
|
363
|
+
}
|
|
364
|
+
section.table table tbody td.no-results {
|
|
365
|
+
color: var(--theme-colour-text-secondary, #d0d0d0);
|
|
366
|
+
}
|
|
367
|
+
section.table table tfoot.table--tfoot {
|
|
368
|
+
display: table-row;
|
|
369
|
+
}
|
|
370
|
+
section.table table tfoot.table--tfoot tr {
|
|
371
|
+
border-bottom: 0;
|
|
372
|
+
}
|
|
373
|
+
section.table table tfoot.table--tfoot td {
|
|
374
|
+
font-weight: 300;
|
|
375
|
+
color: var(--theme-colour-text-primary, #404040);
|
|
376
|
+
font-size: 0.8rem;
|
|
377
|
+
padding: 0.5rem 0 0 0;
|
|
378
|
+
}
|
|
379
|
+
section.table table.truncated tbody tr:last-child:not(:first-child) {
|
|
380
|
+
border-bottom: none;
|
|
381
|
+
mask-image: linear-gradient(to bottom, var(--theme-colour-text-primary) 0%, transparent 100%);
|
|
382
|
+
-webkit-mask-image: linear-gradient(to bottom, var(--theme-colour-text-primary) 0%, transparent 100%);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.avoid-clicks {
|
|
386
|
+
pointer-events: none;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
nav.input {
|
|
390
|
+
margin: 0.5rem 0;
|
|
391
|
+
padding: 0;
|
|
392
|
+
width: 100%;
|
|
393
|
+
display: flex;
|
|
394
|
+
justify-content: flex-start;
|
|
395
|
+
align-items: flex-end;
|
|
396
|
+
flex-direction: row;
|
|
397
|
+
flex-wrap: wrap;
|
|
398
|
+
gap: 1rem;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
nav.show-all {
|
|
402
|
+
display: flex;
|
|
403
|
+
justify-content: center;
|
|
404
|
+
align-items: center;
|
|
405
|
+
margin-top: 1rem;
|
|
406
|
+
}
|
|
407
|
+
nav.show-all button {
|
|
408
|
+
font-size: 0.8rem;
|
|
409
|
+
font-family: var(--theme-font-family-hed, "Knowledge", "Source Sans Pro", Arial, sans-serif);
|
|
410
|
+
font-weight: 500;
|
|
411
|
+
min-width: 175px;
|
|
412
|
+
padding: 0.33rem 0.5rem;
|
|
413
|
+
border: 1px solid var(--theme-colour-brand-rules, #d0d0d0);
|
|
414
|
+
border-radius: 4px;
|
|
415
|
+
background: var(--theme-colour-background);
|
|
416
|
+
color: var(--theme-colour-text-primary, #666666);
|
|
417
|
+
cursor: pointer;
|
|
418
|
+
}</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
width="14"
|
|
3
|
+
height="14"
|
|
4
|
+
viewBox="0 0 14 14"
|
|
5
|
+
fill="none"
|
|
6
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
+
>
|
|
8
|
+
<g clip-path="url(#clip0_25_237)">
|
|
9
|
+
<path
|
|
10
|
+
fill-rule="evenodd"
|
|
11
|
+
clip-rule="evenodd"
|
|
12
|
+
d="M0.300421 0.292131C0.392053 0.199685 0.50109 0.126304 0.621235 0.0762269C0.741381 0.0261493 0.870256 0.000366211 1.00042 0.000366211C1.13059 0.000366211 1.25946 0.0261493 1.37961 0.0762269C1.49975 0.126304 1.60879 0.199685 1.70042 0.292131L7.00082 5.45346L12.3012 0.292131C12.3929 0.199685 12.5019 0.126304 12.622 0.0762269C12.7422 0.0261493 12.8711 0.000366211 13.0012 0.000366211C13.1314 0.000366211 13.2603 0.0261493 13.3804 0.0762269C13.5006 0.126304 13.6096 0.199685 13.7012 0.292131C13.7954 0.378994 13.8706 0.48445 13.922 0.601837C13.9734 0.719225 13.9999 0.845993 13.9998 0.974136C13.9997 1.10228 13.973 1.22901 13.9215 1.34633C13.8699 1.46364 13.7946 1.569 13.7003 1.65573L8.21229 6.99906L13.7003 12.3443C14.0708 12.7064 14.0979 13.2365 13.7796 13.622L13.6994 13.7079C13.6077 13.8003 13.4987 13.8737 13.3785 13.9238C13.2584 13.9738 13.1295 13.9996 12.9994 13.9996C12.8692 13.9996 12.7403 13.9738 12.6202 13.9238C12.5 13.8737 12.391 13.8003 12.2994 13.7079L6.99895 8.54653L1.69855 13.7079C1.60692 13.8003 1.49789 13.8737 1.37774 13.9238C1.25759 13.9738 1.12872 13.9996 0.998554 13.9996C0.86839 13.9996 0.739515 13.9738 0.619369 13.9238C0.499223 13.8737 0.390186 13.8003 0.298554 13.7079C0.204346 13.621 0.129174 13.5155 0.0777863 13.3982C0.0263988 13.2808 -8.74916e-05 13.154 2.17122e-07 13.0259C8.79258e-05 12.8977 0.0267478 12.771 0.0782959 12.6537C0.129844 12.5364 0.20516 12.431 0.299488 12.3443L5.78655 7L0.300421 1.65573C-0.0710458 1.2936 -0.0981124 0.763464 0.220154 0.377998L0.300421 0.292131Z"
|
|
13
|
+
fill="var(--theme-colour-text-secondary)"></path>
|
|
14
|
+
</g>
|
|
15
|
+
<defs>
|
|
16
|
+
<clipPath id="clip0_25_237">
|
|
17
|
+
<rect width="14" height="14" fill="var(--theme-colour-background, white)"
|
|
18
|
+
></rect>
|
|
19
|
+
</clipPath>
|
|
20
|
+
</defs>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function filterArray(data, searchText, filterField, filterValue) {
|
|
2
|
+
if (searchText) {
|
|
3
|
+
data = data.filter((item) => {
|
|
4
|
+
return item.searchStr.includes(searchText.toLowerCase());
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
if (filterValue && filterValue) {
|
|
8
|
+
data = data.filter((item) => {
|
|
9
|
+
return item[filterField] === filterValue;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function paginateArray(array, pageSize, pageNumber) {
|
|
16
|
+
return array.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function uniqueAttr(array, attr) {
|
|
20
|
+
return array.map((e) => e[attr]).filter(unique);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function unique(value, index, array) {
|
|
24
|
+
return array.indexOf(value) === index;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getOptions(data, attr) {
|
|
28
|
+
// Get all the unique values in the provided field. Sort it.
|
|
29
|
+
const attrList = uniqueAttr(data, attr).sort((a, b) => a.localeCompare(b));
|
|
30
|
+
|
|
31
|
+
// Tack 'All' as the front as the first option.
|
|
32
|
+
attrList.unshift('All');
|
|
33
|
+
|
|
34
|
+
// Convert the list into Option typed objects ready for our Select component
|
|
35
|
+
return attrList.map((a) => ({ text: a, value: a }));
|
|
36
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export { default as SiteFooter } from './components/SiteFooter/SiteFooter.svelte
|
|
|
28
28
|
export { default as SiteHeader } from './components/SiteHeader/SiteHeader.svelte';
|
|
29
29
|
export { default as SiteHeadline } from './components/SiteHeadline/SiteHeadline.svelte';
|
|
30
30
|
export { default as Spinner } from './components/Spinner/Spinner.svelte';
|
|
31
|
+
export { default as Table } from './components/Table/Table.svelte';
|
|
31
32
|
export {
|
|
32
33
|
default as Theme,
|
|
33
34
|
// @ts-ignore
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reuters-graphics/graphics-components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.34",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://reuters-graphics.github.io/graphics-components",
|
|
@@ -186,6 +186,16 @@
|
|
|
186
186
|
"./components/SiteHeader/svgs/Menu.svelte": "./dist/components/SiteHeader/svgs/Menu.svelte",
|
|
187
187
|
"./components/SiteHeadline/SiteHeadline.svelte": "./dist/components/SiteHeadline/SiteHeadline.svelte",
|
|
188
188
|
"./components/Spinner/Spinner.svelte": "./dist/components/Spinner/Spinner.svelte",
|
|
189
|
+
"./components/Table/LeftArrow.svelte": "./dist/components/Table/LeftArrow.svelte",
|
|
190
|
+
"./components/Table/MagnifyingGlass.svelte": "./dist/components/Table/MagnifyingGlass.svelte",
|
|
191
|
+
"./components/Table/Pagination.svelte": "./dist/components/Table/Pagination.svelte",
|
|
192
|
+
"./components/Table/RightArrow.svelte": "./dist/components/Table/RightArrow.svelte",
|
|
193
|
+
"./components/Table/Search.svelte": "./dist/components/Table/Search.svelte",
|
|
194
|
+
"./components/Table/Select.svelte": "./dist/components/Table/Select.svelte",
|
|
195
|
+
"./components/Table/SortArrow.svelte": "./dist/components/Table/SortArrow.svelte",
|
|
196
|
+
"./components/Table/Table.svelte": "./dist/components/Table/Table.svelte",
|
|
197
|
+
"./components/Table/X.svelte": "./dist/components/Table/X.svelte",
|
|
198
|
+
"./components/Table/utils": "./dist/components/Table/utils.js",
|
|
189
199
|
"./components/Theme/@types/component.ts": "./dist/components/Theme/@types/component.ts",
|
|
190
200
|
"./components/Theme/Theme.svelte": "./dist/components/Theme/Theme.svelte",
|
|
191
201
|
"./components/Theme/themes/dark": "./dist/components/Theme/themes/dark.js",
|