Skip to content

Commit

Permalink
doc: editable table
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryan Lee committed Jul 29, 2022
1 parent 6c8d737 commit 78ef1a5
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 8 deletions.
14 changes: 7 additions & 7 deletions docs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"shiki": "^0.10.1",
"svelte": "^3.44.0",
"svelte-check": "^2.2.6",
"svelte-headless-table": "^0.11.0",
"svelte-headless-table": "^0.12.2",
"svelte-preprocess": "^4.10.5",
"tailwindcss": "^3.0.24",
"tslib": "^2.3.1",
Expand Down
18 changes: 18 additions & 0 deletions docs/src/routes/docs/[...4]examples/[...2]editable-table.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Editable Table
description: An example with editable cells.
---

# {$frontmatter.title}

A table with editable cells that updates the data source.

:::admonition type="info"
Source code available on the [REPL](https://svelte.dev/repl/ff202b82d9a84aec8f8b97c215ce8737?version=3.49.0).
:::

<script>
import Editable from './_Editable.svelte';
</script>

<Editable />
130 changes: 130 additions & 0 deletions docs/src/routes/docs/[...4]examples/_Editable.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<script lang="ts">
import { writable } from 'svelte/store';
import { Render, Subscribe, createTable, createRender, type DataLabel } from 'svelte-headless-table';
import { createSamples, type Sample } from '$lib/utils/createSamples';
import EditableCell from './_EditableCell.svelte';
const data = writable(createSamples(100));
const updateData = (rowDataId: string, columnId: string, newValue: any) => {
if (['age', 'visits', 'progress'].includes(columnId)) {
newValue = parseInt(newValue);
if (isNaN(newValue)) {
// Refresh data to reset invalid values.
$data = $data;
return;
}
}
if (columnId === 'status') {
if (!['relationship', 'single', 'complicated'].includes(newValue)) {
// Refresh data to reset invalid values.
$data = $data;
return;
}
}
// In this case, the dataId of each item is its index in $data.
// You can also handle any server-synchronization necessary here.
const idx = parseInt(rowDataId);
const currentItem = $data[idx];
const key = columnId as keyof Sample;
const newItem = {...currentItem, [key]: newValue};
console.log(newItem);
$data[idx] = newItem;
$data = $data;
// Handle any server-synchronization.
}
const table = createTable(data);
const EditableCellLabel: DataLabel<Sample> = ({ column, row, value }) =>
createRender(EditableCell, {
row,
column,
value,
onUpdateValue: updateData,
});
const columns = table.createColumns([
table.group({
header: 'Name',
columns: [
table.column({
header: 'First Name',
cell: EditableCellLabel,
accessor: 'firstName',
}),
table.column({
header: () => 'Last Name',
cell: EditableCellLabel,
accessor: 'lastName',
}),
],
}),
table.group({
header: 'Info',
columns: [
table.column({
header: 'Age',
cell: EditableCellLabel,
accessor: 'age',
}),
table.column({
header: 'Status',
cell: EditableCellLabel,
id: 'status',
accessor: (item) => item.status,
}),
table.column({
header: 'Visits',
cell: EditableCellLabel,
accessor: 'visits',
}),
table.column({
header: 'Profile Progress',
cell: EditableCellLabel,
accessor: 'progress',
}),
],
}),
]);
const { headerRows, pageRows, tableAttrs, tableBodyAttrs } =
table.createViewModel(columns);
</script>

<div class="overflow-x-auto">
<table {...$tableAttrs} class="demo">
<thead>
{#each $headerRows as headerRow (headerRow.id)}
<Subscribe attrs={headerRow.attrs()} let:attrs>
<tr {...attrs}>
{#each headerRow.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} let:attrs>
<th {...attrs}>
<div>
<Render of={cell.render()} />
</div>
</th>
</Subscribe>
{/each}
</tr>
</Subscribe>
{/each}
</thead>
<tbody {...$tableBodyAttrs}>
{#each $pageRows as row (row.id)}
<Subscribe attrs={row.attrs()} let:attrs>
<tr {...attrs}>
{#each row.cells as cell (cell.id)}
<Subscribe attrs={cell.attrs()} let:attrs>
<td {...attrs}>
<Render of={cell.render()} />
</td>
</Subscribe>
{/each}
</tr>
</Subscribe>
{/each}
</tbody>
</table>
</div>
48 changes: 48 additions & 0 deletions docs/src/routes/docs/[...4]examples/_EditableCell.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import { DataBodyRow, DataColumn, type BodyRow } from "svelte-headless-table";
type Item = $$Generic;
export let row: BodyRow<Item>;
export let column: DataColumn<Item>;
export let value: unknown;
export let onUpdateValue: (rowDataId: string, columnId: string, newValue: unknown) => void;
let isEditing = false;
let inputElement: HTMLInputElement | undefined;
$: if (isEditing) {
inputElement?.focus();
}
const handleCancel = () => {
isEditing = false;
};
const handleSubmit = () => {
isEditing = false;
if (row instanceof DataBodyRow) {
onUpdateValue(row.dataId, column.id, value);
}
};
</script>

<div>
{#if !isEditing}
<span on:click={() => (isEditing = true)}>
{value}
</span>
{:else}
<form on:submit|preventDefault={handleSubmit}>
<input bind:this={inputElement} type="text" bind:value/>
<button type="submit">✅</button>
<button on:click={handleCancel}>❌</button>
</form>
{/if}
</div>

<style>
form {
display: flex;
gap: 0.5rem;
}
</style>

1 comment on commit 78ef1a5

@vercel
Copy link

@vercel vercel bot commented on 78ef1a5 Jul 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.