Prefer tailwind

This commit is contained in:
Peter White
2026-03-23 09:15:10 +01:00
parent cd48a074f7
commit 21520e38f2
5 changed files with 76 additions and 80 deletions
@@ -5,7 +5,6 @@ import { tcls } from '@/lib/tailwind';
import { RecordColumnValue } from './RecordColumnValue';
import type { TableRecordKV, TableViewProps } from './Table';
import { getColumnWidth } from './layout';
import styles from './table.module.css';
import { getColumnVerticalAlignment } from './utils';
export function RecordRow(
@@ -18,7 +17,15 @@ export function RecordRow(
const { view, autoSizedColumns, fixedColumns, block, context } = props;
return (
<div className={styles.row} role="row">
<div
className={tcls(
'flex',
'border-tint-subtle',
'transition-colors',
'hover:bg-tint-hover'
)}
role="row"
>
{view.columns.map((column) => {
const columnWidth = getColumnWidth({
column,
@@ -33,7 +40,10 @@ export function RecordRow(
<div
key={column}
role="cell"
className={tcls(styles.cell)}
className={tcls(
'relative flex flex-1 border-r px-3 py-2 align-middle text-sm last:border-r-0',
'border-tint-subtle'
)}
style={{
width: columnWidth,
minWidth: columnWidth || '100px',
@@ -1,6 +1,7 @@
'use client';
import { useScrollListener } from '@/components/hooks/useScrollListener';
import { tcls } from '@/lib/tailwind';
import { type ReactNode, useCallback, useLayoutEffect, useRef } from 'react';
import { type ReactNode, useCallback, useEffect, useLayoutEffect, useRef } from 'react';
import styles from './table.module.css';
@@ -50,9 +51,14 @@ export function StickyViewGrid({ className, header, children }: StickyViewGridPr
bodyScrollElement.scrollWidth > bodyScrollElement.clientWidth + 1
}`;
}, []);
useLayoutEffect(() => {
syncStickyLayout();
}, [syncStickyLayout]);
useScrollListener(syncStickyLayout, bodyScrollRef);
useEffect(() => {
const elements = [bodyScrollRef.current, bodyTableRef.current].filter(
(element): element is HTMLDivElement => Boolean(element)
);
@@ -70,10 +76,28 @@ export function StickyViewGrid({ className, header, children }: StickyViewGridPr
return (
<div className={className}>
<div ref={rootRef} className={styles.stickyTableRoot} data-scrollable="false">
<div className={styles.stickyHeaderLayer} onWheel={onStickyHeaderWheel}>
<div
ref={rootRef}
className={tcls(
'group/table relative flex w-full min-w-0 max-w-full flex-col rounded-lg border-tint-subtle',
'data-[scrollable=true]:border'
)}
data-scrollable="false"
>
<div
className={tcls(
'-mx-px sticky z-10 w-full min-w-0 max-w-full overflow-hidden px-px',
'[top:calc(var(--toc-top-offset,var(--outline-top-offset,0px))+8px)]'
)}
onWheel={onStickyHeaderWheel}
>
<div
className={tcls('flex', 'flex-col', 'w-fit', styles.stickyHeaderTable)}
className={tcls(
'flex',
'flex-col',
'w-fit',
'[transform:translateX(var(--table-sticky-scroll-left,0px))]'
)}
style={{ width: 'var(--table-sticky-table-width)' }}
>
{header}
@@ -82,8 +106,12 @@ export function StickyViewGrid({ className, header, children }: StickyViewGridPr
<div
ref={bodyScrollRef}
className={styles.tableScrollArea}
onScroll={syncStickyLayout}
className={tcls(
styles.tableScrollArea,
'w-full min-w-0 overflow-x-auto overflow-y-hidden border-tint-subtle',
'group-data-[scrollable=true]/table:border-0',
'group-data-[scrollable=true]/table:rounded-none'
)}
>
<div ref={bodyTableRef} className={tcls('flex', 'flex-col', 'w-fit')}>
{children}
@@ -51,12 +51,20 @@ export function Table(props: BlockProps<DocumentBlockTable>) {
if (withStickyHeader) {
return (
<StickyViewGrid
className={tcls(style, styles.tableWrapper)}
className={tcls(style, 'relative mx-auto grid w-full min-w-0')}
header={
<div aria-hidden="true">
<ViewGridHeader
{...gridProps}
className={styles.stickyHeaderRowGroup}
className={tcls(
'mb-0 rounded-b-none border-t border-r border-l',
'group-data-[scrollable=false]/table:mb-1',
'group-data-[scrollable=false]/table:rounded-b-lg',
'group-data-[scrollable=true]/table:border-t-0',
'group-data-[scrollable=true]/table:border-r-0',
'group-data-[scrollable=true]/table:border-l-0',
'group-data-[scrollable=true]/table:rounded-t-none'
)}
/>
</div>
}
@@ -67,8 +75,13 @@ export function Table(props: BlockProps<DocumentBlockTable>) {
}
return (
<div className={tcls(style, styles.tableWrapper)}>
<div className={styles.tableScrollArea}>
<div className={tcls(style, 'relative mx-auto grid w-full min-w-0')}>
<div
className={tcls(
styles.tableScrollArea,
'w-full min-w-0 overflow-x-auto overflow-y-hidden border-tint-subtle'
)}
>
<ViewGrid {...gridProps} />
</div>
</div>
@@ -5,7 +5,6 @@ import { tcls } from '@/lib/tailwind';
import { RecordRow } from './RecordRow';
import type { TableViewProps } from './Table';
import { getColumnWidth, getViewGridLayout } from './layout';
import styles from './table.module.css';
import { getColumnAlignment } from './utils';
export function ViewGridHeader(
@@ -19,7 +18,14 @@ export function ViewGridHeader(
});
return (
<div role="rowgroup" className={tcls(tableWidth, styles.rowGroup, className)}>
<div
role="rowgroup"
className={tcls(
tableWidth,
'mb-1 flex flex-col rounded-lg border border-tint-subtle bg-tint',
className
)}
>
<div role="row" className={tcls('flex', 'w-full')}>
{view.columns.map((column) => {
const definition = block.data.definition[column];
@@ -31,7 +37,10 @@ export function ViewGridHeader(
<div
key={column}
role="columnheader"
className={tcls(styles.columnHeader, getColumnAlignment(definition))}
className={tcls(
'px-3 py-2 font-medium text-sm text-tint-strong',
getColumnAlignment(definition)
)}
style={{
width: getColumnWidth({
column,
@@ -21,68 +21,4 @@
--border-width-if-can-scroll: var(--can-scroll) 1px;
--border-width-if-cant-scroll: 0;
border-width: var(--border-width-if-can-scroll, var(--border-width-if-cant-scroll));
@apply w-full min-w-0 overflow-x-auto overflow-y-hidden border-tint-subtle;
}
.tableWrapper {
@apply relative grid w-full min-w-0 mx-auto;
}
.stickyTableRoot {
@apply relative flex w-full min-w-0 max-w-full flex-col;
}
.stickyHeaderLayer {
top: var(--toc-top-offset, var(--outline-top-offset, 0px));
@apply sticky z-10 w-full min-w-0 max-w-full overflow-hidden -mx-px px-px;
}
.stickyHeaderTable {
transform: translateX(var(--table-sticky-scroll-left, 0px));
}
.columnHeader {
@apply text-sm font-medium py-2 px-3 text-tint-strong;
}
.row {
@apply flex border-tint-subtle hover:bg-tint-hover transition-colors;
}
.rowGroup {
@apply flex flex-col border rounded-lg bg-tint border-tint-subtle mb-1;
}
.stickyHeaderRowGroup {
@apply mb-0 rounded-b-none border-t border-l border-r;
}
.stickyTableRoot[data-scrollable='false'] .stickyHeaderRowGroup {
@apply mb-1 rounded-b-lg;
}
.stickyTableRoot[data-scrollable='true'] {
@apply rounded-lg border border-tint-subtle;
}
.stickyTableRoot[data-scrollable='true'] .tableScrollArea {
border-width: 0;
border-radius: 0;
}
.stickyTableRoot[data-scrollable='true'] .stickyHeaderRowGroup {
border-top-width: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
border-left-width: 0;
border-right-width: 0;
}
.cell {
@apply flex-1 flex align-middle border-tint-subtle py-2 px-3 text-sm relative;
}
.cell:not(:last-child) {
@apply border-r;
}