1. Data View Package
  2. 📊 What is Data View?

Data View Package

📊 What is Data View?

TypeScript NPM Version Repo Bitbucket Bitbucket open pull requests NPM License

Introduction

The data view package provides a basic way for creating your generic table view with some opinionated features. The library consists of store and component libraries. Each can be used independently.

Store

This provides factory functions for creating writable store filters that are common with data views. It automatically writes to the url query/searchParams in order to persist between pages.

NOTE! This does sync bi-directionally with the url. If the URL search parameters is changed manually or programatically, it will NOT update the store values.

Basic Usage

A convinience function has been provided for quick intialization.

When using this, make sure to initialize them as high up the component tree as possible, the +page.ts is a good place to use these. This is because it automatically sets the context via the setContext svelte api.

        
<script lang="ts">
  import { initFilterContext } from '@tanglemedia/svelte-starter-data-view';

  initFilterContext({
    /**
     * Setup the intial values. Note that these are all optional
     */
    initialValues: {
      limit: 25,
      sort: 'name',
      searchTerm: 'Default search term',
      pagination: 1,
      filter: {}
    },
    // This will prefix all the arguments in the url
    scope: 'my-prefix',
    // optionally override the encoder
    // encoderProvider: () => myEncoder,
    // optionally override the storage provider
    // storageProvider: () => myStorageProvider,
    // optional custom configuration for each store,
    configure: {
      // ... todo
    }
	});
</script>
<!-- My component -->

      

Somewhere down the component tree

        
<script lang="ts">
  import { getLimitFilter, getSortFilter, getSearchTermFilter, getSearchFilter, getPaginationFilter } from '@tanglemedia/svelte-starter-data-view';

  /** Your typical writable store */
  const limit = getLimitFilter();
  const sort = getSortFilter();
  const query = getSearchTermFilter();
  const filter = getSearchFilter();
  const page = getPaginationFilter();

  /** You can access or edit these values like so */
  const onPage = () => $page = $page + 1;
  $: console.log($limit, $sort, $query, $filter, $page)

</script>

<button on:click={onPage}>Next page</button>


      

Data View

This component renders your basic table. Here are the configurable property definitions.

Columns

Note that the base columns extends @tanstack/svelte-table column def, so you may specify the columns as such.

        import type { ColumnDef } from '@tanstack/svelte-table';
import type { SvelteComponent } from 'svelte';

type BaseColDef<T extends object> = Omit<ColumnDef<T>, 'columns'>;

/**
 * These are keys with arguments that map to predefined functions that will format/decorate the column value.
 * Use the formatter property on the data view for further configurations and ways to add custom formatters
 * todo: Handle ":" options
 */
export type DataViewColumnFormatter = 'currency';

export type ActionComponent = typeof SvelteComponent;

export type ActionItem = {
	href: string;
	text?: string | (() => ActionComponent | string);
	target?: string;
};

export type ActionExtend = {
	type?: 'action';
	actions?: ActionItem[];
	// accessorKey: string | undefined;
};

/**
 * We don't want to drift too far from the undelying package, so we attempt to extend this.
 */
export type DataViewColumnDef<
	T extends object,
	U extends object = Record<string, unknown>
> = BaseColDef<T> & {
	/**
	 *
	 */
	// accessorKey?: string;
	columns?: DataViewColumnDef<T>[];

	/**
	 * A list of predefined formatters
	 */
	formatters?: DataViewColumnFormatter[];

	/**
	 * Tailwind classes which will be added to the cell container
	 */
	class?: string;

	/**
	 * Defaults to accessor to indicate this column is meant to diplay data by accessing the datasource.
	 * options:
	 *  - accessor
	 *  - display
	 *  - group (not supported yet)
	 */
	type?: string | 'accessor' | 'display' | 'action';
} & U;

/**
 * Allow a definition to be a string for the simpliest definition.
 */
export type DataViewColumn<T extends object, U extends object = Record<string, unknown>> =
	| string
	| (DataViewColumnDef<T, U> & ActionExtend);

      

Data view

These relate to the props you can pass to the data view component

        import type { DataViewColumn } from './column.type';
import type { FormatterConfiguration } from './formatter.type';

export interface DataViewPaginationProps {
	pagination?: boolean;
	// pageOptions?: {};
}

export interface DataSource<T extends object> {
	data: T[];
	meta?: {
		pagination?: {
			total: number;
		};
	};
}

export interface DataSourceContext {
	page?: {
		limit?: number;
		offset?: number;
	};
}

export type DataSourceProvider<T extends object> = (
	filter?: DataSourceContext
) => Promise<DataSource<T>>;

export interface DataViewProps<T extends object> extends DataViewPaginationProps {
	/**
	 * Defined the method to fetch the data
	 */
	dataSource: DataSourceProvider<T>;
	/**
	 * Used as the query key for refetching and cache invalidation
	 */
	key?: string;

	/**
	 * Column definition
	 */
	columns: DataViewColumn<T>[];

	formatters?: FormatterConfiguration;

	filterScope?: string;
}

      

Basic Usage

On version 1 onwards, the states have been lifted up to an object that is passed to the DataView components. This provides you access and abitlity to control the states within your component.

        <script lang="ts">
  import {
		createDataView,
		DataView,
	} from '@tanglemedia/svelte-starter-data-view';

  const dataSource: DataSourceProvider<Specie> = async (filter) => {
    // imagine make data provides data with id, name, amount
		const data = await makeData(1000);

    // provide the total as meta information to handle pagination
		return { data, meta: { pagination: { total: 1000 } } };
	};

  // using the createDataView provides helper functions for creating columns.
  const dataview = createDataView<Drug>(({ checkmark, action, selection }) => ({
    dataSource: source,
		enableRowSelection: true,
    columns: [
      selection(true),
      // string definitions indicate you want to display the
      // value as is, without any modifiers
      'id',
      'name',
      // Display the amount but also format it as currency and disable the sorting
      { accessorKey: 'amount', formatters: ['currency'], enableSorting: false },
      checkmark('boolean_field'),
      action(({ row: { original } }) => [{
        text: 'Edit',
        href: `/library/drugs/${original.id}/edit`
      }])
    ]
  });
</script>

<DataView striped {dataview} />

      

Basic Usage (Legacy < v1)

        <script lang="ts">

	import {
		DataView,
		type DataSourceProvider,
		type DataViewColumn
	} from '@tanglemedia/svelte-starter-data-view';

	const dataSource: DataSourceProvider<Specie> = async (filter) => {
    // imagine make data provides data with id, name, amount
		const data = await makeData(1000);

    // provide the total as meta information to handle pagination
		return { data, meta: { pagination: { total: 1000 } } };
	};

	const cols: DataViewColumn<Specie>[] = [
    // string definitions indicate you want to display the
    // value as is, without any modifiers
		'id',
		'name',
    // Display the amount but also format it as currency and disable the sorting
		{ accessorKey: 'amount', formatters: ['currency'], enableSorting: false },
    // draws a dropdown with "Edit" as the url
		{
			type: 'action',
			actions: [
				{
					href: '#',
					text: 'Edit'
				}
			]
		}
	];
</script>

<DataView filterScope={'my-app'} {dataSource} columns={cols}>
   <!-- Add your own custom filter -->
    <span slot="filter-right">
      Custom right filter
    </span>
</DataView>