Skip to content

Commit 7b22b4c

Browse files
committed
feat: sticky tables
1 parent afeab9d commit 7b22b4c

File tree

7 files changed

+57
-14
lines changed

7 files changed

+57
-14
lines changed

example/src/stories/Table/Table.stories.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ export default {
2424
description:
2525
'Whether the table should take up the full width of the container',
2626
},
27+
sticky: {
28+
control: {
29+
type: 'string',
30+
},
31+
description: 'Whether the table should be sticky',
32+
},
2733
},
2834
} as ComponentMeta<typeof Table>
2935

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solved-ac/ui-react",
3-
"version": "0.0.1-alpha.33",
3+
"version": "0.0.1-alpha.34",
44
"description": "React component library used by solved.ac",
55
"author": "shiftpsh",
66
"license": "MIT",

src/components/Table/Cell.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { ElementType, useContext } from 'react'
2-
import styled from 'styled-components'
2+
import styled, { css } from 'styled-components'
33
import { PC, PP, PR } from '../../types/PolymorphicElementProps'
44
import { TableContext } from './TableContext'
55
import { TableRowGroupContext } from './TableRowGroupContext'
@@ -14,18 +14,26 @@ const paddingMap = {
1414
interface CellContainerProps {
1515
padding: 'none' | 'dense' | 'normal' | 'wide'
1616
numeric: boolean
17+
header: boolean
1718
}
1819

20+
const whenHeader = css`
21+
text-align: center;
22+
font-weight: 700;
23+
`
24+
1925
const CellContainer = styled.td<CellContainerProps>`
2026
display: table-cell;
2127
border-bottom: ${({ theme }) => theme.styles.border()};
2228
${({ padding }) => paddingMap[padding]}
2329
${({ numeric }) =>
2430
numeric && "text-align: right; font-feature-settings: 'tnum';"}
31+
${({ header }) => header && whenHeader}
2532
`
2633

2734
export interface CellProps {
2835
padding?: 'none' | 'dense' | 'normal' | 'wide'
36+
header?: boolean
2937
numeric?: boolean
3038
}
3139

@@ -35,17 +43,21 @@ export const Cell: PC<'td', CellProps> = React.forwardRef(
3543
const tableRowGroupContext = useContext(TableRowGroupContext)
3644
const {
3745
padding = tableContext.padding,
38-
as = tableRowGroupContext.header ? 'th' : 'td',
46+
header = tableRowGroupContext.header,
47+
as,
3948
numeric = false,
4049
...rest
4150
} = props
4251

52+
const calculatedAs = as || (header ? 'th' : 'td')
53+
4354
return (
4455
<CellContainer
4556
padding={padding}
4657
numeric={numeric}
58+
header={header}
4759
ref={ref}
48-
as={as}
60+
as={calculatedAs}
4961
{...rest}
5062
/>
5163
)

src/components/Table/Row.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const Row: PC<'tr', RowProps> = React.forwardRef(
2828
} = props
2929

3030
return (
31-
<TableContext.Provider value={{ padding }}>
31+
<TableContext.Provider value={{ ...tableContext, padding }}>
3232
<RowContainer header={header} ref={ref} as={as} {...rest} />
3333
</TableContext.Provider>
3434
)

src/components/Table/Table.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const TableContainer = styled.table<TableContainerProps>`
1515

1616
export interface TableProps {
1717
fullWidth?: boolean
18+
sticky?: boolean | number | string
1819
padding?: 'none' | 'dense' | 'normal' | 'wide'
1920
}
2021

@@ -23,12 +24,13 @@ export const Table: PC<'table', TableProps> = React.forwardRef(
2324
const {
2425
fullWidth = false,
2526
padding = 'normal',
27+
sticky = false,
2628
as = 'table',
2729
...rest
2830
} = props
2931

3032
return (
31-
<TableContext.Provider value={{ padding }}>
33+
<TableContext.Provider value={{ padding, sticky }}>
3234
<TableRowGroupContext.Provider value={{ header: false }}>
3335
<TableContainer fullWidth={fullWidth} ref={ref} as={as} {...rest} />
3436
</TableRowGroupContext.Provider>

src/components/Table/TableContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import React from 'react'
22

33
export interface TableContextProps {
44
padding: 'none' | 'dense' | 'normal' | 'wide'
5+
sticky: boolean | number | string
56
}
67

78
export const TableContext = React.createContext<TableContextProps>({
89
padding: 'normal',
10+
sticky: false,
911
})

src/components/Table/TableHead.tsx

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,42 @@
1-
import React, { ElementType } from 'react'
1+
import React, { ElementType, useContext } from 'react'
22
import styled from 'styled-components'
33
import { PC, PP, PR } from '../../types/PolymorphicElementProps'
4+
import { TableContext } from './TableContext'
45
import { TableRowGroupContext } from './TableRowGroupContext'
56

6-
const TableHeadContainer = styled.thead`
7+
export interface TableHeadContainerProps {
8+
sticky: boolean | number | string
9+
}
10+
11+
const getStickyValue = (sticky: boolean | number | string): string => {
12+
if (typeof sticky === 'number') {
13+
return `${sticky}px`
14+
}
15+
if (typeof sticky === 'string') {
16+
return sticky
17+
}
18+
return '0'
19+
}
20+
21+
const TableHeadContainer = styled.thead<TableHeadContainerProps>`
722
display: table-header-group;
8-
text-align: center;
9-
font-weight: 700;
23+
${({ sticky }) =>
24+
(typeof sticky !== 'boolean' || sticky === true) &&
25+
`position: sticky; top: ${getStickyValue(sticky)};`}
1026
`
1127

12-
export const TableHead: PC<'thead'> = React.forwardRef(
13-
<T extends ElementType>(props: PP<T>, ref?: PR<T>) => {
14-
const { as = 'thead', ...rest } = props
28+
export interface TableHeadProps {
29+
sticky?: boolean | number | string
30+
}
31+
32+
export const TableHead: PC<'thead', TableHeadProps> = React.forwardRef(
33+
<T extends ElementType>(props: PP<T, TableHeadProps>, ref?: PR<T>) => {
34+
const tableContext = useContext(TableContext)
35+
const { sticky = tableContext.sticky, as = 'thead', ...rest } = props
1536

1637
return (
1738
<TableRowGroupContext.Provider value={{ header: true }}>
18-
<TableHeadContainer ref={ref} as={as} {...rest} />
39+
<TableHeadContainer sticky={sticky} ref={ref} as={as} {...rest} />
1940
</TableRowGroupContext.Provider>
2041
)
2142
}

0 commit comments

Comments
 (0)