镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/mosaic-styled-table-primitive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/mosaic': minor
---

Rebuild `Table` on the headless Table primitive. `Table.Root` now owns row selection, tree expansion and sort state, and adds keyboard navigation between rows and cells. `Table.Body` renders rows from `items` with a render function and shows `renderEmptyState` when there are none. `Table.Column` replaces `Table.HeaderCell`, `Table.ColumnGroup` and the old `<col>` `Table.Column`, and takes `width`, `sortable` and `rowHeader`. `Table.SelectionColumn`, `Table.SelectionCell` and `Table.ExpandButton` replace `Table.SelectAllCell` and `Table.SelectCell`, and need an `aria-label`. `Table.Empty` is removed. Sorting goes ascending, then flips, and no longer clears on a third activation. Row selection no longer clears when the page, search or sort changes. Rows with an action now carry `data-actionable` instead of `data-interactive`.

Remove `useDataTable` and `useServerDataTable`. In the members table, rows for members you can't manage, including your own, are now marked `aria-disabled`. The API keys table no longer accepts `sort` or `onSortChange`.
1 change: 0 additions & 1 deletion packages/mosaic/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ Most problems a feature hits already have a shared answer. Find the row for your
| Current time for display labels | `useNow` + `MosaicProvider` ([#10098](https://github.com/clerk/javascript/pull/10098), once available) |
| Whether enterprise SSO permits adding another identification | `allowsIdentificationCreation` (`src/utils/allows-identification-creation.ts`) |
| An inline message row that animates open and closed | `useHeldMessage`, `useMessageHeight`, `FeedbackBody` (`src/utils/feedback.tsx`) + `styles/feedback.styles.ts` |
| A table whose sorting, paging and search are done by the server | `useServerDataTable` (`src/hooks/`) |
| Data read from a Clerk resource that should be cached across mounts | A query hook in `src/queries/`, called from the model (`use-user-sessions-query.ts`) |
| An item changed in place in an infinite list, kept until the next reload | `replaceInPages` (`src/utils/infinite-pages.ts`), passed to the list's `setData` |
| Siblings that slide when an item is added or removed | `useLayoutAnimation` (`src/primitives/hooks/`) |
Expand Down
2 changes: 1 addition & 1 deletion packages/mosaic/bundlewatch.config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"files": [
{ "path": "./dist/index.js", "maxSize": "95KB" },
{ "path": "./dist/styles.css", "maxSize": "16KB" }
{ "path": "./dist/styles.css", "maxSize": "17KB" }
]
}
11 changes: 5 additions & 6 deletions packages/mosaic/src/components/table/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ export type {
TableAlign,
TableBodyProps,
TableCellProps,
TableColumnGroupProps,
TableColumnProps,
TableEmptyProps,
TableHeaderCellProps,
TableExpandButtonProps,
TableHeaderProps,
TableLayout,
TableProps,
TableRootProps,
TableRowProps,
TableSearchProps,
TableSelectAllCellProps,
TableSelectCellProps,
TableSelectionCellProps,
TableSelectionColumnProps,
TableSelectionMode,
TableSort,
TableSticky,
TableToolbarProps,
Expand Down
25 changes: 12 additions & 13 deletions packages/mosaic/src/components/table/table.feature.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@ function renderNarrowTable(minWidth: string) {
layout='fixed'
minWidth={minWidth}
>
<Table.ColumnGroup>
<Table.Column />
<Table.Column width='9rem' />
</Table.ColumnGroup>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>Created</Table.HeaderCell>
</Table.Row>
<Table.Column>Name</Table.Column>
<Table.Column width='9rem'>Created</Table.Column>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>Alpha</Table.Cell>
<Table.Cell>Today</Table.Cell>
</Table.Row>
<Table.Body
items={['alpha']}
itemToStringValue={item => item}
>
{() => (
<Table.Row>
<Table.Cell>Alpha</Table.Cell>
<Table.Cell>Today</Table.Cell>
</Table.Row>
)}
</Table.Body>
</Table.Root>
</div>
Expand Down
3 changes: 3 additions & 0 deletions packages/mosaic/src/components/table/table.markers.stylex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as stylex from '@stylexjs/stylex';

export const tableStateMarker = stylex.defineMarker();
110 changes: 87 additions & 23 deletions packages/mosaic/src/components/table/table.styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import * as stylex from '@stylexjs/stylex';

import { colorVars, fontWeightVars, radiusVars, scrollFadeVars, space, typeScaleVars } from '../../tokens.stylex';
import {
colorVars,
durationVars,
focusVars,
fontWeightVars,
radiusVars,
scrollFadeVars,
space,
typeScaleVars,
} from '../../tokens.stylex';
import { tableStateMarker } from './table.markers.stylex';

const surface = 'var(--_cl-table-surface)';
const tint = 'var(--_cl-table-row-tint)';
Expand Down Expand Up @@ -45,50 +55,60 @@ export const styles = stylex.create({
'--_cl-table-surface': colorVars['--cl-color-background-subtle'],
backgroundColor: colorVars['--cl-color-background-subtle'],
},
bodyRow: {
borderBlockStartColor: colorVars['--cl-color-border'],
borderBlockStartStyle: 'solid',
borderBlockStartWidth: '1px',
},
interactiveRow: {
row: {
'--_cl-table-row-tint': {
default: null,
'@media (hover: hover)': { ':hover': colorVars['--cl-color-background-subtle'] },
':where([data-selected])': colorVars['--cl-color-neutral-alpha-100'],
'@media (hover: hover)': {
default: null,
':where([data-actionable]:not([data-selected]):hover)': colorVars['--cl-color-background-subtle'],
},
},
backgroundColor: {
default: null,
'@media (hover: hover)': { ':hover': colorVars['--cl-color-background-subtle'] },
':where([data-selected])': colorVars['--cl-color-neutral-alpha-100'],
'@media (hover: hover)': {
default: null,
':where([data-actionable]:not([data-selected]):hover)': colorVars['--cl-color-background-subtle'],
},
},
cursor: 'pointer',
},
selectedRow: {
'--_cl-table-row-tint': colorVars['--cl-color-neutral-alpha-100'],
backgroundColor: colorVars['--cl-color-neutral-alpha-100'],
borderBlockStartColor: colorVars['--cl-color-border'],
borderBlockStartStyle: 'solid',
borderBlockStartWidth: '1px',
cursor: { default: null, ':where([data-actionable])': 'pointer' },
position: 'relative',
},
headerCell: {
column: {
paddingBlock: space['2.5'],
paddingInline: space['4'],
color: colorVars['--cl-color-foreground-secondary'],
fontSize: typeScaleVars['--cl-text-xs-size'],
fontWeight: fontWeightVars['--cl-font-medium'],
lineHeight: typeScaleVars['--cl-text-xs-leading'],
position: 'relative',
verticalAlign: 'middle',
whiteSpace: 'nowrap',
},
sortableHeaderCell: {
paddingBlock: space['1.5'],
paddingInline: space['2'],
sortableColumn: {
color: {
default: colorVars['--cl-color-foreground-secondary'],
'@media (hover: hover)': { default: null, ':hover': colorVars['--cl-color-foreground'] },
},
cursor: 'pointer',
userSelect: 'none',
},
sortButton: {
color: 'inherit',
fontWeight: 'inherit',
sortLabel: {
gap: space['1'],
alignItems: 'center',
display: 'inline-flex',
},
cell: {
paddingBlock: space['3'],
paddingInline: space['4'],
color: colorVars['--cl-color-foreground'],
fontSize: typeScaleVars['--cl-text-sm-size'],
lineHeight: typeScaleVars['--cl-text-sm-leading'],
position: 'relative',
verticalAlign: 'middle',
},
selectCell: {
Expand All @@ -103,7 +123,7 @@ export const styles = stylex.create({
backgroundColor: surface,
backgroundImage: `linear-gradient(${tint}, ${tint})`,
position: 'sticky',
zIndex: 1,
zIndex: { default: 1, ':focus-visible': 2 },
'::before': {
insetBlock: 0,
content: '""',
Expand All @@ -112,9 +132,53 @@ export const styles = stylex.create({
width: scrollFadeVars['--cl-scroll-fade-size'],
},
},
emptyCell: {
focusRing: {
outlineOffset: { default: null, ':focus-visible': `calc(-1 * ${focusVars['--cl-focus-outline-width']})` },
zIndex: { default: null, ':focus-visible': 2 },
},
empty: {
textAlign: 'center',
},
expandButton: {
borderRadius: radiusVars['--cl-radius-sm'],
alignItems: 'center',
color: colorVars['--cl-color-foreground-secondary'],
cursor: 'pointer',
display: 'inline-flex',
justifyContent: 'center',
marginInlineEnd: space['1'],
verticalAlign: 'middle',
},
expandIcon: {
transform: {
default: null,
[stylex.when.ancestor('[data-expanded]', tableStateMarker)]: 'rotate(90deg)',
':dir(rtl)': 'scaleX(-1)',
},
transitionDuration: durationVars['--cl-duration-fast'],
transitionProperty: 'transform',
},
});

export const sortIcons = stylex.create({
none: {
display: {
default: 'block',
[stylex.when.ancestor('[data-sort-direction]', tableStateMarker)]: 'none',
},
},
ascending: {
display: {
default: 'none',
[stylex.when.ancestor('[data-sort-direction="ascending"]', tableStateMarker)]: 'block',
},
},
descending: {
display: {
default: 'none',
[stylex.when.ancestor('[data-sort-direction="descending"]', tableStateMarker)]: 'block',
},
},
});

export const layouts = stylex.create({
Expand Down
Loading
Loading