Skip to content

Commit

Permalink
feat: add lit sticky column example
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewgallo committed Sep 23, 2024
1 parent 45a4399 commit 64aad6c
Show file tree
Hide file tree
Showing 12 changed files with 1,050 additions and 0 deletions.
24 changes: 24 additions & 0 deletions web-components/sticky-columns/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
6 changes: 6 additions & 0 deletions web-components/sticky-columns/.sassrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"includePaths": [
"node_modules",
"../../node_modules"
]
}
15 changes: 15 additions & 0 deletions web-components/sticky-columns/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Lit + TS</title>
<link rel="stylesheet" href="https://1.www.s81c.com/common/carbon-for-ibm-dotcom/tag/v1/latest/plex.css" />
<link rel="stylesheet" href="./src/index.scss" />
<script type="module" src="/src/basic.ts"></script>
</head>
<body>
<basic-tanstack-table></basic-tanstack-table>
</body>
</html>
22 changes: 22 additions & 0 deletions web-components/sticky-columns/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "sticky-columns",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@carbon/styles": "^1.34.0",
"@carbon/web-components": "latest",
"@tanstack/lit-table": "^8.20.5",
"sass": "^1.64.1",
"lit": "^3.2.0"
},
"devDependencies": {
"typescript": "^5.5.3",
"vite": "^5.4.1"
}
}
1 change: 1 addition & 0 deletions web-components/sticky-columns/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
186 changes: 186 additions & 0 deletions web-components/sticky-columns/src/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { LitElement, css, html } from 'lit'
import { customElement } from 'lit/decorators.js'
import { repeat } from 'lit/directives/repeat.js'
import {
Column,
createColumnHelper,
flexRender,
getCoreRowModel,
TableController,
} from '@tanstack/lit-table'
import '@carbon/web-components/es/components/data-table/index.js';
import TrashCan from '@carbon/web-components/es/icons/trash-can/16';
import Edit from '@carbon/web-components/es/icons/edit/16';
import { makeData } from './makeData';
import { styleMap } from 'lit/directives/style-map.js';


type Resource = {
id: string
name: string
rule: string
status: string
other: string
example: string
}

const columnHelper = createColumnHelper<Resource>()

const columns = [
columnHelper.accessor(row => row.name, {
id: 'name',
cell: info => html`<i>${info.getValue()}</i>`,
header: () => html`<span>Name</span>`,
}),
columnHelper.accessor('rule', {
header: () => 'Rule',
cell: info => info.renderValue(),
}),
columnHelper.accessor('status', {
header: () => html`<span>Status</span>`,
}),
columnHelper.accessor('other', {
header: 'Other',
}),
columnHelper.accessor('example', {
header: 'Example',
}),
{
header: 'Actions',
id: 'actions',
cell: () => {
return html`<div className='flex'>
<cds-button tooltip-position="bottom" tooltip-text="Delete"
>${TrashCan({ slot: 'icon' })}</cds-button
>
<cds-button tooltip-position="bottom" tooltip-text="Edit"
>${Edit({ slot: 'icon' })}</cds-button
>
</div>`
}
}
]

const data: Resource[] = makeData(10);

const getCommonPinningStyles = (column: Column<Resource>) => {
const isPinned = column.getIsPinned()
const isLastLeftPinnedColumn =
isPinned === 'left' && column.getIsLastColumn('left')
const isFirstRightPinnedColumn =
isPinned === 'right' && column.getIsFirstColumn('right')

console.log(column.getSize());
return {
borderRight: isLastLeftPinnedColumn ? '1px solid var(--cds-border-subtle)' : 0,
borderLeft: isFirstRightPinnedColumn ? '1px solid var(--cds-border-subtle)' : 0,
left: isPinned === 'left' ? `${column.getStart('left')}px` : undefined,
right: isPinned === 'right' ? `${column.getAfter('right')}px` : undefined,
opacity: isPinned ? 0.95 : 1,
position: isPinned ? 'sticky' : 'relative',
width: `${column.getSize()}px`,
zIndex: isPinned ? 1 : 0,
backgroundColor: 'var(--cds-layer)',
display: 'flex',
alignItems: 'center'
}
}

/**
* An example table using `@tanstack/lit-table` and `@carbon/web-components` DataTable.
*
*/

@customElement('basic-tanstack-table')
export class MyBasicTable extends LitElement {
private tableController = new TableController<Resource>(this);

render() {
const table = this.tableController.table({
columns,
data,
getCoreRowModel: getCoreRowModel(),
initialState: {
columnPinning: {
left: ['name'],
right: ['actions'],
},
}
})

return html`
<div class='sticky-container' style=${styleMap({
width: `${620}px`,
})}>
<cds-table>
<cds-table-head>
${repeat(
table.getHeaderGroups(),
headerGroup => headerGroup.id,
headerGroup =>
html`<cds-table-header-row>
${repeat(
headerGroup.headers,
header => header.id,
header =>
html` <cds-table-header-cell style=${styleMap({...getCommonPinningStyles(header.column)})}>
${header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</cds-table-header-cell>`
)}</cds-table-header-row>`
)}
</cds-table-head>
<cds-table-body>
${repeat(
table.getRowModel().rows,
row => row.id,
row => html`
<cds-table-row>
${repeat(
row.getVisibleCells(),
cell => cell.id,
cell =>
html` <cds-table-cell style=${styleMap({ ...getCommonPinningStyles(cell.column) })}>
${flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</cds-table-cell>`
)}
</cds-table-row>
`
)}
</cds-table-body>
</cds-table>
</div>
`
}

static styles = css`
:host {
margin: 0 auto;
padding: 2rem;
display: flex;
place-items: center;
}
cds-table-row,
cds-table-header-row {
display: flex;
}
.sticky-container {
overflow: auto;
}
`
}

declare global {
interface HTMLElementTagNameMap {
'basic-tanstack-table': MyBasicTable
}
}
3 changes: 3 additions & 0 deletions web-components/sticky-columns/src/customTypings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

declare module "@carbon/web-components/es/icons/trash-can/16"
declare module "@carbon/web-components/es/icons/edit/16"
9 changes: 9 additions & 0 deletions web-components/sticky-columns/src/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@use '@carbon/styles/scss/reset';
@use '@carbon/styles/scss/theme';
@use '@carbon/styles/scss/themes';

:root {
@include theme.theme(themes.$white);
background-color: var(--cds-background);
color: var(--cds-text-primary);
}
76 changes: 76 additions & 0 deletions web-components/sticky-columns/src/makeData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { faker } from '@faker-js/faker'

export type Resource = {
id: string
name: string
rule: string
status: string
other: string
example: string
subRows?: Resource[]
}

const range = (len: number) => {
const arr: number[] = []
for (let i = 0; i < len; i++) {
arr.push(i)
}
return arr
}

const newResource = (id: string, index: number): Resource => {
return {
id,
name: `Load balancer ${index}`,
rule: faker.helpers.shuffle<Resource['rule']>([
'DNS delegation',
'Round Robin'
])[0],
status: faker.helpers.shuffle<Resource['status']>([
'starting',
'active',
'disabled',
])[0]!,
other: 'Test',
example: faker.number.int(1000).toString(),
}
}

export function makeData(...lens: number[]) {
const makeDataLevel = (depth = 0): Resource[] => {
const len = lens[depth]!
return range(len).map((index): Resource => {
return {
...newResource(`load-balancer-${index}`, index),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}

return makeDataLevel()
}

//simulates a backend api
const data = makeData(1000)
export const fetchData = async (
start: number,
size: number,
) => {

//simulate a backend api
await new Promise(resolve => setTimeout(resolve, 2000))

return {
data: data.slice(start, start + size),
meta: {
totalRowCount: data.length,
},
}
}

export type ResourceApiResponse = {
data: Resource[]
meta: {
totalRowCount: number
}
}
1 change: 1 addition & 0 deletions web-components/sticky-columns/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
24 changes: 24 additions & 0 deletions web-components/sticky-columns/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2020",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
Loading

0 comments on commit 64aad6c

Please sign in to comment.