svelte-tably 1.0.2-next.1 → 1.1.0

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.
@@ -2,6 +2,7 @@ import { SvelteComponent } from "svelte";
2
2
  import { type Snippet } from 'svelte';
3
3
  import { TableState, type TableProps } from './table-state.svelte.js';
4
4
  import { type RowColumnCtx } from '../column/column-state.svelte.js';
5
+ import type { CSVOptions } from './csv.js';
5
6
  declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
6
7
  props(): TableProps<T> & {
7
8
  content?: Snippet<[context: {
@@ -94,14 +95,9 @@ declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
94
95
  };
95
96
  events(): {};
96
97
  slots(): {};
97
- bindings(): "selected" | "panel" | "data";
98
+ bindings(): "table" | "selected" | "panel" | "data";
98
99
  exports(): {
99
- toCSV: (opts?: {
100
- /** Semi-colons as separator? */
101
- semicolon?: boolean;
102
- /** Only selected rows */
103
- selected?: boolean;
104
- }) => Promise<string>;
100
+ toCSV: (options?: CSVOptions<T>) => Promise<string>;
105
101
  };
106
102
  }
107
103
  interface $$IsomorphicComponent {
@@ -0,0 +1,28 @@
1
+ export interface CSVOptions<T> {
2
+ /**
3
+ * Semi-colons as separator?
4
+ * @default false
5
+ */
6
+ semicolon?: boolean;
7
+ /**
8
+ * Export only selected rows in the visible data
9
+ * @default false
10
+ */
11
+ selected?: boolean;
12
+ /**
13
+ * Filters to apply to the data.
14
+ * - `true` to apply current filters e.g. currently visible content
15
+ * - `false` to ignore filters, export all data
16
+ * - Array of functions to filter data manually
17
+ * @default true
18
+ */
19
+ filters?: true | false | ((item: T) => boolean)[];
20
+ /**
21
+ * Columns to export. By default exports all visible columns.
22
+ * - `true` to export all columns
23
+ * - `false` to export only visible columns
24
+ * - Array of column IDs to export specific columns
25
+ * @default false
26
+ */
27
+ columns?: true | false | string[];
28
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { TableProps, TableState } from './table-state.svelte.js';
2
- export declare class Data<T extends Record<PropertyKey, unknown>> {
2
+ export declare class Data<T> {
3
3
  #private;
4
4
  origin: T[];
5
5
  sorted: T[];
@@ -2,11 +2,11 @@ import { type Snippet } from 'svelte';
2
2
  import { ColumnState, type RowColumnCtx } from '../column/column-state.svelte.js';
3
3
  import { PanelState } from '../panel/panel-state.svelte.js';
4
4
  import { Data } from './data.svelte.js';
5
- import { type AnyRecord } from '../utility.svelte.js';
6
5
  import type { ExpandableState } from '../expandable/expandable-state.svelte.js';
7
6
  import type { ItemState } from 'runic-reorder';
8
7
  import type { RowState } from '../row/row-state.svelte.js';
9
- export type HeaderSelectCtx<T extends AnyRecord = any> = {
8
+ import { CSVOptions } from "./csv.js";
9
+ export type HeaderSelectCtx<T = any> = {
10
10
  isSelected: boolean;
11
11
  /** The list of selected items */
12
12
  readonly selected: T[];
@@ -15,20 +15,20 @@ export type HeaderSelectCtx<T extends AnyRecord = any> = {
15
15
  */
16
16
  readonly indeterminate: boolean;
17
17
  };
18
- export type RowSelectCtx<T extends AnyRecord = any> = {
18
+ export type RowSelectCtx<T extends any = any> = {
19
19
  readonly item: T;
20
20
  readonly row: RowColumnCtx<T, unknown>;
21
21
  data: T[];
22
22
  isSelected: boolean;
23
23
  };
24
- export interface RowCtx<T extends AnyRecord> {
24
+ export interface RowCtx<T extends any> {
25
25
  readonly rowHovered: boolean;
26
26
  readonly index: number;
27
27
  readonly itemState: ItemState<T> | undefined;
28
28
  selected: boolean;
29
29
  expanded: boolean;
30
30
  }
31
- type SelectOptions<T extends AnyRecord> = {
31
+ type SelectOptions<T extends any> = {
32
32
  /**
33
33
  * The style, in which the selection is shown
34
34
  *
@@ -49,8 +49,10 @@ type SelectOptions<T extends AnyRecord> = {
49
49
  headerSnippet?: Snippet<[context: HeaderSelectCtx]>;
50
50
  rowSnippet?: Snippet<[context: RowSelectCtx<T>]>;
51
51
  };
52
- export type TableProps<T extends AnyRecord> = {
52
+ export type TableProps<T extends any> = {
53
53
  id?: string;
54
+ /** Bindable to TableState; `bind:table` */
55
+ table?: TableState<T>;
54
56
  data: T[];
55
57
  selected?: T[];
56
58
  /** Current visible panel */
@@ -72,9 +74,10 @@ export type TableProps<T extends AnyRecord> = {
72
74
  /** Create missing columns automatically. */
73
75
  auto?: boolean;
74
76
  };
75
- export declare class TableState<T extends AnyRecord> {
77
+ export declare class TableState<T> {
76
78
  #private;
77
- id: string;
79
+ id: string | undefined;
80
+ cssId: string;
78
81
  dataState: Data<T>;
79
82
  data: T[];
80
83
  columns: Record<string, ColumnState<T, any>>;
@@ -101,7 +104,10 @@ export declare class TableState<T extends AnyRecord> {
101
104
  auto: boolean;
102
105
  };
103
106
  add(state: ColumnState<T, any> | PanelState<T>): (() => void) | undefined;
104
- static getContext<T extends AnyRecord>(): TableState<T> | undefined;
107
+ static getContext<T>(): TableState<T> | undefined;
108
+ /** Width of each column */
109
+ columnWidths: Record<string, number>;
110
+ toCSV(options?: CSVOptions<T>): Promise<string>;
105
111
  constructor(tableProps: TableProps<T>);
106
112
  }
107
113
  export {};
@@ -5,6 +5,7 @@ import { Data } from './data.svelte.js';
5
5
  export class TableState {
6
6
  #props = {};
7
7
  id = $state();
8
+ cssId = $state();
8
9
  dataState = $state({});
9
10
  data = $derived(this.dataState.current ?? []);
10
11
  columns = $state({});
@@ -14,6 +15,13 @@ export class TableState {
14
15
  /** Currently selected items */
15
16
  get selected() { return this.#props.selected ??= []; }
16
17
  set selected(items) { this.#props.selected = items; }
18
+ /** Saved positions */
19
+ #positions = $state({
20
+ fixed: [],
21
+ sticky: [],
22
+ hidden: [],
23
+ scroll: []
24
+ });
17
25
  /** Column positions based on column ids */
18
26
  positions = $state({
19
27
  fixed: [],
@@ -41,16 +49,27 @@ export class TableState {
41
49
  this.positions.scroll = this.positions.scroll.filter((column) => column !== state);
42
50
  this.positions.hidden = this.positions.hidden.filter((column) => column !== state);
43
51
  };
44
- if (state.defaults.sortby)
52
+ if (state.defaults.sortby && !this.dataState.sortby) {
45
53
  this.dataState.sortBy(key);
46
- if (state.options.fixed) {
54
+ }
55
+ const saved = {
56
+ fixed: this.#positions.fixed.includes(key),
57
+ sticky: this.#positions.sticky.includes(key),
58
+ hidden: this.#positions.hidden.includes(key),
59
+ scroll: this.#positions.scroll.includes(key)
60
+ };
61
+ const isSaved = Object.values(saved).some(v => v);
62
+ if ((!isSaved && state.options.fixed)
63
+ || saved.fixed) {
47
64
  this.positions.fixed.push(state);
48
65
  return clean;
49
66
  }
50
- if (state.defaults.show === false) {
67
+ if ((!isSaved && state.defaults.show === false)
68
+ || saved.hidden) {
51
69
  this.positions.hidden.push(state);
52
70
  }
53
- if (state.defaults.sticky) {
71
+ if ((!isSaved && state.defaults.sticky)
72
+ || saved.sticky) {
54
73
  this.positions.sticky.push(state);
55
74
  }
56
75
  else {
@@ -67,10 +86,77 @@ export class TableState {
67
86
  static getContext() {
68
87
  return getContext('svelte-tably');
69
88
  }
89
+ /** Width of each column */
90
+ columnWidths = $state({});
91
+ #save() {
92
+ const content = {
93
+ columnWidths: this.columnWidths,
94
+ positions: {
95
+ fixed: this.positions.fixed.map(c => c.id),
96
+ sticky: this.positions.sticky.map(c => c.id),
97
+ hidden: this.positions.hidden.map(c => c.id),
98
+ scroll: this.positions.scroll.map(c => c.id)
99
+ },
100
+ sortby: this.dataState.sortby,
101
+ sortReverse: this.dataState.sortReverse
102
+ };
103
+ localStorage.setItem(`svelte-tably:${this.id}`, JSON.stringify(content));
104
+ }
105
+ #saving = false;
106
+ #scheduleSave() {
107
+ if (this.#saving)
108
+ return;
109
+ if (typeof localStorage === 'undefined')
110
+ return;
111
+ this.#saving = true;
112
+ setTimeout(() => {
113
+ this.#saving = false;
114
+ this.#save();
115
+ }, 1000);
116
+ }
117
+ #load() {
118
+ if (typeof localStorage === 'undefined')
119
+ return null;
120
+ const item = JSON.parse(localStorage.getItem(`svelte-tably:${this.id}`) || '{}');
121
+ item.columnWidths ??= {};
122
+ item.positions ??= {};
123
+ item.positions.fixed ??= [];
124
+ item.positions.sticky ??= [];
125
+ item.positions.hidden ??= [];
126
+ item.positions.scroll ??= [];
127
+ item.sortby ??= undefined;
128
+ item.sortReverse ??= false;
129
+ return item;
130
+ }
131
+ async toCSV(options = {}) {
132
+ options;
133
+ return '';
134
+ }
70
135
  constructor(tableProps) {
71
136
  this.#props = tableProps;
72
- this.id = tableProps.id ?? Array.from({ length: 12 }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('');
137
+ this.id = tableProps.id;
138
+ this.cssId = Array.from({ length: 12 }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('');
73
139
  this.dataState = new Data(this, tableProps);
140
+ if (this.id) {
141
+ // fetch from localstorage
142
+ const saved = this.#load();
143
+ if (saved) {
144
+ this.columnWidths = saved.columnWidths;
145
+ this.#positions = saved.positions;
146
+ this.dataState.sortby = saved.sortby;
147
+ this.dataState.sortReverse = saved.sortReverse;
148
+ }
149
+ }
150
+ if (typeof window !== 'undefined') {
151
+ window.addEventListener('beforeunload', () => this.#save());
152
+ }
153
+ $effect(() => {
154
+ Object.keys(this.columnWidths);
155
+ Object.values(this.positions).map(v => v.length);
156
+ this.dataState.sortby;
157
+ this.dataState.sortReverse;
158
+ this.#scheduleSave();
159
+ });
74
160
  setContext('svelte-tably', this);
75
161
  }
76
162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-tably",
3
- "version": "1.0.2-next.1",
3
+ "version": "1.1.0",
4
4
  "description": "A high performant dynamic table for Svelte 5",
5
5
  "license": "MIT",
6
6
  "repository": {