svelte-tably 1.1.2 → 1.3.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Via the amazing capabilities braught to us by Svelte 5 — a performant, dynamic, flexible, feature rich table. It's as simple, or as flexible as you need it to be.
4
4
 
5
- Simple example on [Svelte 5 Playground](https://svelte.dev/playground/f79124e8473546d29433a95a68440d6d?version=5.16.0)
5
+ Simple example on [Svelte 5 Playground](https://svelte.dev/playground/f79124e8473546d29433a95a68440d6d?version=5)
6
6
  <br>
7
7
  Fledged out example on [Svelte 5 Playground](https://svelte.dev/playground/a16d71c97445455e80a55b77ec1cf915?version=5)
8
8
 
@@ -51,7 +51,7 @@ On top of that, the library API is extensive, so the table can meet your needs.
51
51
  <Table auto {data} resizeable={false} filters={[...]} />
52
52
 
53
53
  <Table {data} panel={activePanel} select bind:selected>
54
- {#snippet content({ Column, Panel, Expandable, Row, state, table })}
54
+ {#snippet content({ Column, Panel, Expandable, Row, table })}
55
55
  <Column id='name' sticky sort value={r => r.name} filter={v => v.includes('Giraffe')}>
56
56
  {#snippet header(ctx)}
57
57
  Name
@@ -92,6 +92,13 @@ On top of that, the library API is extensive, so the table can meet your needs.
92
92
  </Table>
93
93
  ```
94
94
 
95
+ > [!NOTE]
96
+ > Animations (panel/expandable) respect `prefers-reduced-motion`.
97
+
98
+ > [!TIP]
99
+ > To export CSV, you can either `bind:table` to get the `TableState` instance (which exposes `table.toCSV(...)`),
100
+ > or `bind:this` and call the component export `toCSV(...)`.
101
+
95
102
  ### Styling
96
103
 
97
104
  For quick styling
@@ -248,6 +255,7 @@ This component can add a context-menu on the side of each row, as well as provid
248
255
  | - | - | - |
249
256
  | hover? | Only show when hovering? | `boolean` |
250
257
  | width? | The width for the context-column | `string` |
258
+ | alignHeaderToRows? | If enabled, the header and row context cells share the same measured width | `boolean` |
251
259
 
252
260
  <br>
253
261
 
@@ -23,7 +23,7 @@
23
23
  import { fromProps, snippetLiteral } from '../utility.svelte.js'
24
24
  import { ColumnState, type ColumnProps, type HeaderCtx, type ColumnSnippets } from './column-state.svelte.js'
25
25
 
26
- type T = $$Generic<Record<PropertyKey, any>>
26
+ type T = $$Generic
27
27
  type V = $$Generic
28
28
 
29
29
  let {...props}: ColumnProps<T, V> = $props()
@@ -1,6 +1,6 @@
1
1
  export declare function getDefaultHeader<T, V>(title: string): () => any;
2
2
  import { type HeaderCtx } from './column-state.svelte.js';
3
- declare class __sveltets_Render<T extends Record<PropertyKey, any>, V> {
3
+ declare class __sveltets_Render<T, V> {
4
4
  props(): {
5
5
  id: string;
6
6
  table?: import("../index.js").TableState<T> | undefined;
@@ -19,7 +19,7 @@ declare class __sveltets_Render<T extends Record<PropertyKey, any>, V> {
19
19
  style?: string | undefined;
20
20
  class?: string | undefined;
21
21
  onclick?: ((event: MouseEvent, rowColumnCtx: import("./column-state.svelte.js").RowColumnCtx<T, V>) => void) | undefined;
22
- pad?: "row" | "header" | "both" | undefined;
22
+ pad?: "row" | "header" | "statusbar" | "both" | undefined;
23
23
  };
24
24
  events(): {};
25
25
  slots(): {};
@@ -27,10 +27,10 @@ declare class __sveltets_Render<T extends Record<PropertyKey, any>, V> {
27
27
  exports(): {};
28
28
  }
29
29
  interface $$IsomorphicComponent {
30
- new <T extends Record<PropertyKey, any>, V>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T, V>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T, V>['props']>, ReturnType<__sveltets_Render<T, V>['events']>, ReturnType<__sveltets_Render<T, V>['slots']>> & {
30
+ new <T, V>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T, V>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T, V>['props']>, ReturnType<__sveltets_Render<T, V>['events']>, ReturnType<__sveltets_Render<T, V>['slots']>> & {
31
31
  $$bindings?: ReturnType<__sveltets_Render<T, V>['bindings']>;
32
32
  } & ReturnType<__sveltets_Render<T, V>['exports']>;
33
- <T extends Record<PropertyKey, any>, V>(internal: unknown, props: ReturnType<__sveltets_Render<T, V>['props']> & {}): ReturnType<__sveltets_Render<T, V>['exports']>;
33
+ <T, V>(internal: unknown, props: ReturnType<__sveltets_Render<T, V>['props']> & {}): ReturnType<__sveltets_Render<T, V>['exports']>;
34
34
  z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
35
35
  }
36
36
  /**
@@ -41,5 +41,5 @@ interface $$IsomorphicComponent {
41
41
  * <Component />
42
42
  */
43
43
  declare const Column: $$IsomorphicComponent;
44
- type Column<T extends Record<PropertyKey, any>, V> = InstanceType<typeof Column<T, V>>;
44
+ type Column<T, V> = InstanceType<typeof Column<T, V>>;
45
45
  export default Column;
@@ -92,7 +92,7 @@ type ColumnOptions<T, V> = {
92
92
  * This ensures the child element "fills" the whole column.
93
93
  * Ex. good if you want to make the column an anchor link; `<a href='...'>`
94
94
  */
95
- pad?: 'row' | 'header' | 'both';
95
+ pad?: 'row' | 'header' | 'statusbar' | 'both';
96
96
  };
97
97
  export declare class ColumnState<T = any, V = any> {
98
98
  #private;
@@ -130,6 +130,7 @@ export declare class ColumnState<T = any, V = any> {
130
130
  onclick: ((event: MouseEvent, rowColumnCtx: RowColumnCtx<T, V>) => void) | undefined;
131
131
  padRow: boolean;
132
132
  padHeader: boolean;
133
+ padStatusbar: boolean;
133
134
  };
134
135
  toggleVisiblity(): void;
135
136
  constructor(props: ColumnProps<T, V>);
@@ -43,7 +43,8 @@ export class ColumnState {
43
43
  class: this.#props.class,
44
44
  onclick: this.#props.onclick,
45
45
  padRow: this.#props.pad === 'row' || this.#props.pad === 'both',
46
- padHeader: this.#props.pad === 'header' || this.#props.pad === 'both'
46
+ padHeader: this.#props.pad === 'header' || this.#props.pad === 'both',
47
+ padStatusbar: this.#props.pad === 'statusbar'
47
48
  });
48
49
  toggleVisiblity() {
49
50
  const index = this.table.positions.hidden.indexOf(this);
@@ -11,10 +11,9 @@
11
11
  <script lang='ts'>
12
12
 
13
13
  import { ExpandableState, type ExpandableProps } from './expandable-state.svelte.js'
14
- import type { AnyRecord } from '../utility.svelte.js'
15
14
  import { fromProps } from '../utility.svelte.js'
16
15
 
17
- type T = $$Generic<AnyRecord>
16
+ type T = $$Generic
18
17
 
19
18
  let { ...restProps }: ExpandableProps<T> = $props()
20
19
 
@@ -1,6 +1,5 @@
1
1
  import { type ExpandableProps } from './expandable-state.svelte.js';
2
- import type { AnyRecord } from '../utility.svelte.js';
3
- declare class __sveltets_Render<T extends AnyRecord> {
2
+ declare class __sveltets_Render<T> {
4
3
  props(): ExpandableProps<T>;
5
4
  events(): {};
6
5
  slots(): {};
@@ -8,10 +7,10 @@ declare class __sveltets_Render<T extends AnyRecord> {
8
7
  exports(): {};
9
8
  }
10
9
  interface $$IsomorphicComponent {
11
- new <T extends AnyRecord>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
10
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
12
11
  $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
13
12
  } & ReturnType<__sveltets_Render<T>['exports']>;
14
- <T extends AnyRecord>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
13
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
15
14
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
16
15
  }
17
16
  /**
@@ -22,5 +21,5 @@ interface $$IsomorphicComponent {
22
21
  * <Component />
23
22
  */
24
23
  declare const Expandable: $$IsomorphicComponent;
25
- type Expandable<T extends AnyRecord> = InstanceType<typeof Expandable<T>>;
24
+ type Expandable<T> = InstanceType<typeof Expandable<T>>;
26
25
  export default Expandable;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import Table from './table/Table.svelte';
2
2
  import type { TableState, TableProps } from './table/table-state.svelte.js';
3
+ import type { ContentCtx as TableContentCtx, ContentSnippet as TableContentSnippet } from './table/Table.svelte';
3
4
  declare namespace Table {
4
5
  type State<T = unknown> = TableState<T>;
5
6
  type Props<T = unknown> = TableProps<T>;
7
+ type ContentCtx<T = unknown> = TableContentCtx<T>;
8
+ type ContentSnippet<T = unknown> = TableContentSnippet<T>;
6
9
  }
7
10
  export default Table;
8
11
  export { default as Panel } from './panel/Panel.svelte';
@@ -10,6 +13,7 @@ export { default as Column } from './column/Column.svelte';
10
13
  export { default as Row } from './row/Row.svelte';
11
14
  export { default as Expandable } from './expandable/Expandable.svelte';
12
15
  export type { TableState, TableProps } from './table/table-state.svelte.js';
16
+ export type { ContentCtx, ContentSnippet } from './table/Table.svelte';
13
17
  export type { RowState, RowProps } from './row/row-state.svelte.js';
14
18
  export type { ColumnState, ColumnProps } from './column/column-state.svelte.js';
15
19
  export type { ExpandableState, ExpandableProps } from './expandable/expandable-state.svelte.js';
@@ -8,7 +8,7 @@
8
8
 
9
9
  -->
10
10
 
11
- <script lang='ts' generics='T extends Record<PropertyKey, unknown>'>
11
+ <script lang='ts' generics='T'>
12
12
 
13
13
  import { PanelState, type PanelProps } from './panel-state.svelte.js'
14
14
  import { fromProps } from '../utility.svelte.js'
@@ -1,5 +1,5 @@
1
1
  import { type PanelProps } from './panel-state.svelte.js';
2
- declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
2
+ declare class __sveltets_Render<T> {
3
3
  props(): PanelProps<T>;
4
4
  events(): {};
5
5
  slots(): {};
@@ -7,10 +7,10 @@ declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
7
7
  exports(): {};
8
8
  }
9
9
  interface $$IsomorphicComponent {
10
- new <T extends Record<PropertyKey, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
10
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
11
11
  $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
12
12
  } & ReturnType<__sveltets_Render<T>['exports']>;
13
- <T extends Record<PropertyKey, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
13
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
14
14
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
15
15
  }
16
16
  /**
@@ -21,5 +21,5 @@ interface $$IsomorphicComponent {
21
21
  * <Component />
22
22
  */
23
23
  declare const Panel: $$IsomorphicComponent;
24
- type Panel<T extends Record<PropertyKey, unknown>> = InstanceType<typeof Panel<T>>;
24
+ type Panel<T> = InstanceType<typeof Panel<T>>;
25
25
  export default Panel;
@@ -11,10 +11,9 @@
11
11
  <script lang='ts'>
12
12
 
13
13
  import { RowState, type RowProps } from './row-state.svelte.js'
14
- import type { AnyRecord } from '../utility.svelte.js'
15
14
  import { fromProps } from '../utility.svelte.js'
16
15
 
17
- type T = $$Generic<AnyRecord>
16
+ type T = $$Generic
18
17
 
19
18
  let { ...restProps }: RowProps<T> = $props()
20
19
 
@@ -1,6 +1,5 @@
1
1
  import { type RowProps } from './row-state.svelte.js';
2
- import type { AnyRecord } from '../utility.svelte.js';
3
- declare class __sveltets_Render<T extends AnyRecord> {
2
+ declare class __sveltets_Render<T> {
4
3
  props(): RowProps<T>;
5
4
  events(): {};
6
5
  slots(): {};
@@ -8,10 +7,10 @@ declare class __sveltets_Render<T extends AnyRecord> {
8
7
  exports(): {};
9
8
  }
10
9
  interface $$IsomorphicComponent {
11
- new <T extends AnyRecord>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
10
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
12
11
  $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
13
12
  } & ReturnType<__sveltets_Render<T>['exports']>;
14
- <T extends AnyRecord>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
13
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
15
14
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
16
15
  }
17
16
  /**
@@ -22,5 +21,5 @@ interface $$IsomorphicComponent {
22
21
  * <Component />
23
22
  */
24
23
  declare const Row: $$IsomorphicComponent;
25
- type Row<T extends AnyRecord> = InstanceType<typeof Row<T>>;
24
+ type Row<T> = InstanceType<typeof Row<T>>;
26
25
  export default Row;
@@ -2,14 +2,25 @@ import { type RowCtx } from '../table/table-state.svelte.js';
2
2
  import type { Snippet } from 'svelte';
3
3
  type ContextOptions<T> = {
4
4
  /**
5
- * Only show when hovering the row?
5
+ * Only show the context *content* when hovering the row?
6
+ *
7
+ * Note: the context column still reserves its width in the grid.
8
+ * Hover mode only hides the contents / disables interaction.
6
9
  * @default true
7
10
  */
8
11
  hover?: boolean;
9
12
  /**
10
- * @defualt 'max-content'
13
+ * @default 'max-content'
11
14
  */
12
15
  width?: string;
16
+ /**
17
+ * Align the header context cell (if any) with the row context cell.
18
+ *
19
+ * When enabled, the table measures the rendered context cell width
20
+ * (from header and rows) and uses a shared fixed width so they line up.
21
+ * @default false
22
+ */
23
+ alignHeaderToRows?: boolean;
13
24
  };
14
25
  export interface RowProps<T> {
15
26
  /**
@@ -35,6 +46,7 @@ export declare class RowState<T> {
35
46
  context: {
36
47
  hover: boolean;
37
48
  width: string;
49
+ alignHeaderToRows: boolean;
38
50
  };
39
51
  };
40
52
  constructor(props: RowProps<T>);
@@ -13,14 +13,15 @@ export class RowState {
13
13
  options = $derived({
14
14
  context: {
15
15
  hover: this.#props.contextOptions?.hover ?? true,
16
- width: this.#props.contextOptions?.width ?? 'max-content'
16
+ width: this.#props.contextOptions?.width ?? 'max-content',
17
+ alignHeaderToRows: this.#props.contextOptions?.alignHeaderToRows ?? false
17
18
  }
18
19
  });
19
20
  constructor(props) {
20
21
  this.#props = props;
21
22
  this.#table = TableState.getContext();
22
23
  if (!this.#table) {
23
- throw new Error('svelte-tably: Expandable must be associated with a Table');
24
+ throw new Error('svelte-tably: Row must be associated with a Table');
24
25
  }
25
26
  this.#table.row = this;
26
27
  $effect(() => () => this.#table.row === this && (this.#table.row = undefined));
@@ -1,6 +1,13 @@
1
1
  import { untrack } from 'svelte';
2
2
  import { sineInOut } from 'svelte/easing';
3
3
  import { Tween } from 'svelte/motion';
4
+ const prefersReducedMotion = () => {
5
+ if (typeof window === 'undefined')
6
+ return false;
7
+ if (!('matchMedia' in window))
8
+ return false;
9
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
10
+ };
4
11
  export class SizeTween {
5
12
  #tweenOptions = { duration: 300, easing: sineInOut };
6
13
  #tween = new Tween(0, this.#tweenOptions);
@@ -10,7 +17,8 @@ export class SizeTween {
10
17
  size = $state(0);
11
18
  set target(value) {
12
19
  this.transitioning = true;
13
- this.#tween.set(value, this.#tweenOptions).then(() => this.transitioning = false);
20
+ const duration = prefersReducedMotion() ? 0 : this.#tweenOptions.duration;
21
+ this.#tween.set(value, { ...this.#tweenOptions, duration }).then(() => this.transitioning = false);
14
22
  }
15
23
  constructor(cb, opts = {}) {
16
24
  if ('duration' in opts) {