From b060dd35f501798433b421def3c5988ae1fe86d3 Mon Sep 17 00:00:00 2001 From: austincalvelage Date: Wed, 23 Sep 2026 17:53:58 -0600 Subject: [PATCH 1/2] feat(mosaic): add shared table toolbar and search --- .changeset/tidy-tables-search.md | 2 + packages/mosaic/src/components/table/index.ts | 2 + .../src/components/table/table.styles.ts | 9 +++ .../src/components/table/table.test.tsx | 53 ++++++++++++ .../mosaic/src/components/table/table.tsx | 80 ++++++++++++++++++- .../members-table-tab.styles.ts | 9 --- .../members-table-tab.view.tsx | 45 +++-------- ...anization-profile-api-keys-panel.styles.ts | 9 --- ...ganization-profile-api-keys-panel.view.tsx | 47 +++-------- .../user-profile-api-keys-panel.styles.ts | 9 --- .../user-profile-api-keys-panel.view.tsx | 47 +++-------- packages/swingset/src/lib/registry.ts | 2 + .../organization-profile-api-keys-panel.mdx | 2 - .../organization-profile-members-panel.mdx | 1 - packages/swingset/src/stories/table.mdx | 58 ++++++++++---- .../swingset/src/stories/table.stories.tsx | 42 ++++++++++ .../stories/user-profile-api-keys-panel.mdx | 2 - 17 files changed, 259 insertions(+), 160 deletions(-) create mode 100644 .changeset/tidy-tables-search.md diff --git a/.changeset/tidy-tables-search.md b/.changeset/tidy-tables-search.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/tidy-tables-search.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/mosaic/src/components/table/index.ts b/packages/mosaic/src/components/table/index.ts index 26b143caa70..695aaf521c4 100644 --- a/packages/mosaic/src/components/table/index.ts +++ b/packages/mosaic/src/components/table/index.ts @@ -8,7 +8,9 @@ export type { TableHeaderProps, TableProps, TableRowProps, + TableSearchProps, TableSelectAllCellProps, TableSelectCellProps, TableSort, + TableToolbarProps, } from './table'; diff --git a/packages/mosaic/src/components/table/table.styles.ts b/packages/mosaic/src/components/table/table.styles.ts index 6a87e53cd02..ed80339534b 100644 --- a/packages/mosaic/src/components/table/table.styles.ts +++ b/packages/mosaic/src/components/table/table.styles.ts @@ -3,6 +3,15 @@ import * as stylex from '@stylexjs/stylex'; import { colorVars, fontWeightVars, radiusVars, space, typeScaleVars } from '../../tokens.stylex'; export const styles = stylex.create({ + toolbar: { + gap: space['4'], + alignItems: 'center', + display: 'flex', + flexWrap: 'wrap', + justifyContent: 'space-between', + }, + search: { maxWidth: '100%', width: '17rem' }, + noWrap: { whiteSpace: 'nowrap' }, shell: { borderColor: colorVars['--cl-color-border'], borderRadius: radiusVars['--cl-radius-xl'], diff --git a/packages/mosaic/src/components/table/table.test.tsx b/packages/mosaic/src/components/table/table.test.tsx index 19fb8f17f61..04a40af9ca5 100644 --- a/packages/mosaic/src/components/table/table.test.tsx +++ b/packages/mosaic/src/components/table/table.test.tsx @@ -32,6 +32,40 @@ function renderTable(props: Partial> = { } describe('Mosaic Table', () => { + it('reports search changes and returns focus to the input when cleared', async () => { + const user = userEvent.setup(); + const ref = React.createRef(); + const onValueChange = vi.fn(); + function Example() { + const [value, setValue] = React.useState(''); + return ( + + { + onValueChange(next); + setValue(next); + }} + /> + + ); + } + render(); + const input = screen.getByRole('searchbox', { name: 'Search members' }); + expect(ref.current).toBe(input); + expect(screen.queryByRole('button', { name: 'Clear member search' })).not.toBeInTheDocument(); + await user.type(input, 'Ada'); + expect(onValueChange).toHaveBeenLastCalledWith('Ada'); + await user.click(screen.getByRole('button', { name: 'Clear member search' })); + expect(onValueChange).toHaveBeenLastCalledWith(''); + expect(input).toHaveValue(''); + expect(input).toHaveFocus(); + expect(screen.queryByRole('button', { name: 'Clear member search' })).not.toBeInTheDocument(); + }); + it('renders a table inside a scrolling shell', () => { renderTable(); const table = screen.getByRole('table'); @@ -40,6 +74,25 @@ describe('Mosaic Table', () => { expect(table.parentElement?.parentElement).toHaveClass('cl-table-shell'); }); + it('opts cells into no-wrap styling without changing neighboring cells', () => { + render( + + + + September 23, 2026 + A longer description can wrap + + + , + ); + const date = screen.getByRole('cell', { name: 'September 23, 2026' }); + const description = screen.getByRole('cell', { name: 'A longer description can wrap' }); + expect(date).toHaveAttribute('data-no-wrap', ''); + expect(date).toHaveClass(stylex.props(styles.noWrap).className ?? ''); + expect(description).not.toHaveAttribute('data-no-wrap'); + expect(description).not.toHaveClass(stylex.props(styles.noWrap).className ?? ''); + }); + it('lets the keyboard reach the scrolling viewport', () => { renderTable(); expect(screen.getByRole('table').parentElement).toHaveAttribute('tabindex', '0'); diff --git a/packages/mosaic/src/components/table/table.tsx b/packages/mosaic/src/components/table/table.tsx index 61f23b1c05e..e067cef5d08 100644 --- a/packages/mosaic/src/components/table/table.tsx +++ b/packages/mosaic/src/components/table/table.tsx @@ -1,3 +1,4 @@ +import { useMergeRefs } from '@floating-ui/react'; import * as stylex from '@stylexjs/stylex'; import React from 'react'; @@ -9,6 +10,8 @@ import { Button } from '../button'; import type { CheckboxProps } from '../checkbox'; import { Checkbox } from '../checkbox'; import { Icon } from '../icon'; +import type { InputProps } from '../input'; +import { InputGroup } from '../input-group'; import { scrollAreaRoot, scrollAreaViewport } from '../scroll-area'; import { aligns, styles } from './table.styles'; @@ -22,6 +25,74 @@ export type TableSort = 'ascending' | 'descending' | 'none'; export type TableProps = MosaicElementProps<'table'>; +export type TableToolbarProps = MosaicComponentProps<'div'>; + +const Toolbar = React.forwardRef(function MosaicTableToolbar( + { render, xstyle, ...rest }, + ref, +) { + return useRender({ + defaultTagName: 'div', + render, + ref, + props: mergeStyleProps(themeProps('table-toolbar'), stylex.props(reset.base, styles.toolbar, xstyle), rest), + }); +}); + +export interface TableSearchProps extends Omit< + InputProps, + 'value' | 'defaultValue' | 'onChange' | 'type' | 'children' | 'size' | 'variant' +> { + label: string; + clearLabel: string; + value: string; + onValueChange: (value: string) => void; +} + +const Search = React.forwardRef(function MosaicTableSearch( + { label, clearLabel, value, onValueChange, disabled, readOnly, ...rest }, + ref, +) { + const inputRef = React.useRef(null); + const mergedRef = useMergeRefs([ref, inputRef]); + return ( + + + + + onValueChange(event.currentTarget.value)} + /> + {value ? ( + + + + ) : null} + + ); +}); + const Root = React.forwardRef(function MosaicTable({ xstyle, ...rest }, ref) { return (
@@ -147,10 +218,11 @@ const HeaderCell = React.forwardRef( export interface TableCellProps extends Omit, 'align'> { align?: TableAlign; + noWrap?: boolean; } const Cell = React.forwardRef(function MosaicTableCell( - { align = 'start', render, xstyle, ...rest }, + { align = 'start', noWrap = false, render, xstyle, ...rest }, ref, ) { return useRender({ @@ -158,8 +230,8 @@ const Cell = React.forwardRef(function Mos render, ref, props: mergeStyleProps( - themeProps('table-cell', { align }), - stylex.props(reset.base, styles.cell, aligns[align], xstyle), + themeProps('table-cell', { align, noWrap }), + stylex.props(reset.base, styles.cell, aligns[align], noWrap && styles.noWrap, xstyle), rest, ), }); @@ -227,4 +299,4 @@ const Empty = React.forwardRef(function M ); }); -export const Table = { Root, Header, Body, Row, HeaderCell, Cell, SelectAllCell, SelectCell, Empty }; +export const Table = { Root, Toolbar, Search, Header, Body, Row, HeaderCell, Cell, SelectAllCell, SelectCell, Empty }; diff --git a/packages/mosaic/src/features/organization-profile/members-table-tab.styles.ts b/packages/mosaic/src/features/organization-profile/members-table-tab.styles.ts index c6dc19c44d5..6b3ee08455e 100644 --- a/packages/mosaic/src/features/organization-profile/members-table-tab.styles.ts +++ b/packages/mosaic/src/features/organization-profile/members-table-tab.styles.ts @@ -3,14 +3,5 @@ import * as stylex from '@stylexjs/stylex'; import { space } from '../../tokens.stylex'; export const styles = stylex.create({ - toolbar: { - gap: space['4'], - alignItems: 'center', - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'space-between', - }, - search: { maxWidth: '100%', width: '17rem' }, name: { gap: space['2'], alignItems: 'center', display: 'flex' }, - dateCell: { whiteSpace: 'nowrap' }, }); diff --git a/packages/mosaic/src/features/organization-profile/members-table-tab.view.tsx b/packages/mosaic/src/features/organization-profile/members-table-tab.view.tsx index 7c06d620dcb..d3075e396cf 100644 --- a/packages/mosaic/src/features/organization-profile/members-table-tab.view.tsx +++ b/packages/mosaic/src/features/organization-profile/members-table-tab.view.tsx @@ -7,8 +7,6 @@ import { Avatar } from '../../components/avatar'; import { Badge } from '../../components/badge'; import { Button } from '../../components/button'; import { EmptyState } from '../../components/empty-state'; -import { Icon } from '../../components/icon'; -import { InputGroup } from '../../components/input-group'; import { Item } from '../../components/item'; import { Pagination } from '../../components/pagination'; import { panelStyles } from '../../components/profile'; @@ -116,37 +114,14 @@ export function MembersTableTabView({ return ( <>
-
- - - - - table.setGlobalFilter(event.currentTarget.value)} - /> - {table.globalFilter ? ( - - - - ) : null} - + + {onInvite ? (
+ - {member.joinedAtLabel} + {member.joinedAtLabel} {onChangeRole && !member.isDeprovisioned ? (
{m.title} -
- - - - - table.setGlobalFilter(event.currentTarget.value)} - /> - {table.globalFilter ? ( - - - - ) : null} - + + {onCreate ? (
+
- + {row.original.createdAtLabel} - + {row.original.lastUsedAtLabel ?? m.neverUsed} {onRevoke ? ( diff --git a/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.styles.ts b/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.styles.ts index f1b1e7190ff..c61ec582db5 100644 --- a/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.styles.ts +++ b/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.styles.ts @@ -3,15 +3,6 @@ import * as stylex from '@stylexjs/stylex'; import { fontWeightVars, space } from '../../tokens.stylex'; export const styles = stylex.create({ - toolbar: { - gap: space['4'], - alignItems: 'center', - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'space-between', - }, - search: { maxWidth: '100%', width: '17rem' }, name: { fontWeight: fontWeightVars['--cl-font-medium'] }, - dateCell: { whiteSpace: 'nowrap' }, metadata: { gap: space['0.5'], display: 'flex', flexDirection: 'column', minWidth: '25ch' }, }); diff --git a/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.view.tsx b/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.view.tsx index 7bcbbce7b3f..b37dcf73084 100644 --- a/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.view.tsx +++ b/packages/mosaic/src/features/user-profile/user-profile-api-keys-panel.view.tsx @@ -4,8 +4,6 @@ import { useMemo, useRef, useState } from 'react'; import { Destructive } from '../../blocks/destructive'; import { Button } from '../../components/button'; import { EmptyState } from '../../components/empty-state'; -import { Icon } from '../../components/icon'; -import { InputGroup } from '../../components/input-group'; import { Menu } from '../../components/menu'; import { Pagination } from '../../components/pagination'; import { panelStyles, Profile } from '../../components/profile'; @@ -114,37 +112,14 @@ export function UserProfileApiKeysPanelView({ <>
{m.title} -
- - - - - table.setGlobalFilter(event.currentTarget.value)} - /> - {table.globalFilter ? ( - - - - ) : null} - + + {onCreate ? (
+
- + {row.original.createdAtLabel} - + {row.original.lastUsedAtLabel ?? m.neverUsed} {onRevoke ? ( diff --git a/packages/swingset/src/lib/registry.ts b/packages/swingset/src/lib/registry.ts index 7376ebed605..07baabf6a6e 100644 --- a/packages/swingset/src/lib/registry.ts +++ b/packages/swingset/src/lib/registry.ts @@ -254,6 +254,7 @@ import { Empty as TableEmpty, meta as tableMeta, Overflow as TableOverflow, + Search as TableSearch, Selection as TableSelection, Sorting as TableSorting, } from '../stories/table.stories'; @@ -701,6 +702,7 @@ const tableModule: StoryModule = { meta: tableMeta, Default: TableDefault, Sorting: TableSorting, + Search: TableSearch, Selection: TableSelection, Empty: TableEmpty, Overflow: TableOverflow, diff --git a/packages/swingset/src/stories/organization-profile-api-keys-panel.mdx b/packages/swingset/src/stories/organization-profile-api-keys-panel.mdx index b818b9a38a3..417daf3ada2 100644 --- a/packages/swingset/src/stories/organization-profile-api-keys-panel.mdx +++ b/packages/swingset/src/stories/organization-profile-api-keys-panel.mdx @@ -13,12 +13,10 @@ A controlled organization API keys table with search, page navigation, and confi { name: 'Table', href: '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/components/table', layer: 'Components' }, { name: 'EmptyState', href: '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/components/empty-state', layer: 'Components' }, { name: 'useDataTable', href: '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/hooks/use-data-table', layer: 'Hooks' }, - { name: 'InputGroup', href: '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/components/input-group', layer: 'Components' }, { name: 'Pagination', href: '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/components/pagination', layer: 'Components' }, { name: 'Menu', href: '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/components/menu', layer: 'Components' }, { name: 'Button', href: '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/components/button', layer: 'Components' }, { name: 'Text', href: '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/components/text', layer: 'Components' }, - { name: 'Icon', href: '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/components/icon', layer: 'Components' }, { name: 'Spinner', href: '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/components/spinner', layer: 'Components' }, { name: 'Profile', href: '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/components/profile', layer: 'Components' }, { name: 'Dialog', href: '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/components/dialog', layer: 'Components' }, diff --git a/packages/swingset/src/stories/organization-profile-members-panel.mdx b/packages/swingset/src/stories/organization-profile-members-panel.mdx index c561d494b3f..52b76da8e40 100644 --- a/packages/swingset/src/stories/organization-profile-members-panel.mdx +++ b/packages/swingset/src/stories/organization-profile-members-panel.mdx @@ -21,7 +21,6 @@ The Members table shows the user, joined date, role, and optional row actions. T { name: 'Tabs', href: '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/components/tabs', layer: 'Components' }, { name: 'Confirmation', href: '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/blocks/confirmation', layer: 'Blocks' }, { name: 'Table', href: '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/components/table', layer: 'Components' }, - { name: 'InputGroup', href: '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/components/input-group', layer: 'Components' }, { name: 'Pagination', href: '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/components/pagination', layer: 'Components' }, { name: 'Select', href: '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/components/select', layer: 'Components' }, { name: 'Menu', href: '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/components/menu', layer: 'Components' }, diff --git a/packages/swingset/src/stories/table.mdx b/packages/swingset/src/stories/table.mdx index 1397fcb085a..38dbdae184c 100644 --- a/packages/swingset/src/stories/table.mdx +++ b/packages/swingset/src/stories/table.mdx @@ -18,31 +18,44 @@ Sorting, selection, and the empty state are opt-in parts rather than state the t ```tsx import { Table } from '@clerk/mosaic/components/table'; - - - - Name - Created - - - - {rows.map(row => ( - - {row.name} - {row.created} +<> + + + + + + + + Name + Created - ))} - -; + + + {rows.map(row => ( + + {row.name} + {row.created} + + ))} + +
+; ``` ## Parts +- `Table.Toolbar` wraps search and optional actions in a responsive row. Render it before `Table.Root`, outside the table. +- `Table.Search` composes [InputGroup](/components/input-group), [Icon](/components/icon), and [Button](/components/button). Supply the controlled `value`, `onValueChange`, and localized `label` and `clearLabel`. Clearing returns focus to the input. Its `ref`, `xstyle`, and input props apply to the search input; `placeholder` defaults to `label`. The caller owns filtering and any debounce. - `Table.Root` renders the ``. `xstyle`, `ref`, and any table props land on it; the scrolling shell around it is internal. - `Table.Header` and `Table.Body` render `` and ``. Rows inside the body get a top border. - `Table.Row` renders a ``. Pass `selected` to mark it `aria-selected` and tint it. - `Table.HeaderCell` renders a `
`. Pass `onSort` to make it sortable: the label becomes a button with a direction icon, and `sort` (`'ascending'`, `'descending'`, or `'none'`) reflects the current direction as `aria-sort`. `align` moves the content to `'center'` or `'end'`. -- `Table.Cell` renders a `` with the same `align` prop. +- `Table.Cell` renders a `` with the same `align` prop. `noWrap` defaults to `false`; enable it to keep dates and other short values on one line. - `Table.SelectAllCell` and `Table.SelectCell` render a narrow header or body cell holding a [Checkbox](/components/checkbox). They take Checkbox props, so pass `checked`, `indeterminate`, and an `aria-label`. `Table.SelectCell` also takes `onToggleSelected`, called with `{ range: true }` when the checkbox was shift-clicked, which fits the row's `toggleSelected` from `useDataTable` directly. - `Table.Empty` renders a full-width row with a single cell that spans every column. Put an [EmptyState](/components/empty-state) inside it. The cell uses the largest `colSpan` browsers allow, which stretches across the columns the table actually has; pass `colSpan` yourself if you need the exact count. @@ -55,11 +68,13 @@ Each part carries a stable `.cl-*` class, and the parts with state reflect it as | `.cl-table-shell` | The bordered wrapper around the table | | | `.cl-table-viewport` | The horizontally scrolling viewport | | | `.cl-table` | `Table.Root` | | +| `.cl-table-toolbar` | `Table.Toolbar` | | +| `.cl-table-search` | `Table.Search` input group | | | `.cl-table-header` | `Table.Header` | | | `.cl-table-body` | `Table.Body` | | | `.cl-table-row` | `Table.Row` | `data-selected` when `selected` | | `.cl-table-header-cell` | `Table.HeaderCell` | `data-align` (`start` / `center` / `end`), `data-sortable` when `onSort` is set, `data-sort` (`ascending` / `descending`) | -| `.cl-table-cell` | `Table.Cell` | `data-align` (`start` / `center` / `end`) | +| `.cl-table-cell` | `Table.Cell` | `data-align` (`start` / `center` / `end`), `data-no-wrap` when `noWrap` | | `.cl-table-select-cell` | `Table.SelectAllCell`, `Table.SelectCell` | | | `.cl-table-empty` | `Table.Empty` | | @@ -73,6 +88,15 @@ Each part carries a stable `.cl-*` class, and the parts with state reflect it as ## Examples +### Search + +The toolbar places the search field beside optional actions and wraps on narrow screens. This example filters locally; server-backed views can pass their controlled search value and change handler instead. + + + ### Sorting Each sortable header cycles through ascending, descending, and unsorted. The story keeps sorting in `useDataTable` and sorts the rows itself before rendering. diff --git a/packages/swingset/src/stories/table.stories.tsx b/packages/swingset/src/stories/table.stories.tsx index 230ab1bde23..0a45584dccb 100644 --- a/packages/swingset/src/stories/table.stories.tsx +++ b/packages/swingset/src/stories/table.stories.tsx @@ -201,6 +201,48 @@ export function Default() { ); } +export function Search() { + const [search, setSearch] = React.useState(''); + const filtered = apiKeys.filter(key => key.name.toLowerCase().includes(search.trim().toLowerCase())); + return ( +
+ + + + + + + + Name + Created + + + + {filtered.length ? ( + filtered.map(key => ( + + {key.name} + {key.created} + + )) + ) : ( + + + No API keys found + + + )} + + +
+ ); +} + export function Sorting() { const { sorting, setSorting, sorted } = useSortedApiKeys(apiKeys); diff --git a/packages/swingset/src/stories/user-profile-api-keys-panel.mdx b/packages/swingset/src/stories/user-profile-api-keys-panel.mdx index fbb72176b47..77352fc8d51 100644 --- a/packages/swingset/src/stories/user-profile-api-keys-panel.mdx +++ b/packages/swingset/src/stories/user-profile-api-keys-panel.mdx @@ -13,12 +13,10 @@ A controlled API keys table with search, page navigation, and confirmation by ty { name: 'Table', href: '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/components/table', layer: 'Components' }, { name: 'EmptyState', href: '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/components/empty-state', layer: 'Components' }, { name: 'useDataTable', href: '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/hooks/use-data-table', layer: 'Hooks' }, - { name: 'InputGroup', href: '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/components/input-group', layer: 'Components' }, { name: 'Pagination', href: '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/components/pagination', layer: 'Components' }, { name: 'Menu', href: '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/components/menu', layer: 'Components' }, { name: 'Button', href: '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/components/button', layer: 'Components' }, { name: 'Text', href: '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/components/text', layer: 'Components' }, - { name: 'Icon', href: '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/components/icon', layer: 'Components' }, { name: 'Spinner', href: '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/components/spinner', layer: 'Components' }, { name: 'Profile', href: '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/components/profile', layer: 'Components' }, { name: 'Dialog', href: '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/components/dialog', layer: 'Components' }, From 205297c099a37ebe79cacacdb4af84d7256315c6 Mon Sep 17 00:00:00 2001 From: austincalvelage Date: Thu, 24 Sep 2026 11:15:25 -0600 Subject: [PATCH 2/2] refactor(mosaic): share toolbar across all searchable tables --- .../invitations-table-tab.styles.ts | 15 ------ .../invitations-table-tab.view.tsx | 46 ++++-------------- .../requests-table-tab.styles.ts | 9 ---- .../requests-table-tab.view.tsx | 47 +++++-------------- .../organization-profile-members-panel.mdx | 2 +- 5 files changed, 22 insertions(+), 97 deletions(-) delete mode 100644 packages/mosaic/src/features/organization-profile/invitations-table-tab.styles.ts diff --git a/packages/mosaic/src/features/organization-profile/invitations-table-tab.styles.ts b/packages/mosaic/src/features/organization-profile/invitations-table-tab.styles.ts deleted file mode 100644 index d406ad8ac95..00000000000 --- a/packages/mosaic/src/features/organization-profile/invitations-table-tab.styles.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as stylex from '@stylexjs/stylex'; - -import { space } from '../../tokens.stylex'; - -export const styles = stylex.create({ - toolbar: { - gap: space['4'], - alignItems: 'center', - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'space-between', - }, - search: { maxWidth: '100%', width: '17rem' }, - dateCell: { whiteSpace: 'nowrap' }, -}); diff --git a/packages/mosaic/src/features/organization-profile/invitations-table-tab.view.tsx b/packages/mosaic/src/features/organization-profile/invitations-table-tab.view.tsx index 25f9f292d65..4e9258bf4ed 100644 --- a/packages/mosaic/src/features/organization-profile/invitations-table-tab.view.tsx +++ b/packages/mosaic/src/features/organization-profile/invitations-table-tab.view.tsx @@ -6,8 +6,6 @@ import { ActionMenu } from '../../components/action-menu'; import { Avatar } from '../../components/avatar'; import { Button } from '../../components/button'; import { EmptyState } from '../../components/empty-state'; -import { Icon } from '../../components/icon'; -import { InputGroup } from '../../components/input-group'; import { Item } from '../../components/item'; import { Pagination } from '../../components/pagination'; import { panelStyles } from '../../components/profile'; @@ -18,7 +16,6 @@ import { useListRemovalFocus } from '../../hooks/useListRemovalFocus'; import { fill, useMessages } from '../../localization'; import { useDataTable } from '../../primitives/hooks'; import { mergeStyleProps, themeProps } from '../../props'; -import { styles } from './invitations-table-tab.styles'; import type { InvitationsTableSort, InvitationsTableTabViewProps, @@ -107,37 +104,14 @@ export function InvitationsTableTabView({ return ( <>
-
- - - - - table.setGlobalFilter(event.currentTarget.value)} - /> - {table.globalFilter ? ( - - - - ) : null} - + + {onInvite ? (
+ - {row.original.invitedAtLabel} + {row.original.invitedAtLabel} {row.original.roleLabel} {onRevoke ? ( diff --git a/packages/mosaic/src/features/organization-profile/requests-table-tab.styles.ts b/packages/mosaic/src/features/organization-profile/requests-table-tab.styles.ts index 528266c7e6e..6e171ad565f 100644 --- a/packages/mosaic/src/features/organization-profile/requests-table-tab.styles.ts +++ b/packages/mosaic/src/features/organization-profile/requests-table-tab.styles.ts @@ -3,14 +3,5 @@ import * as stylex from '@stylexjs/stylex'; import { space } from '../../tokens.stylex'; export const styles = stylex.create({ - toolbar: { - gap: space['4'], - alignItems: 'center', - display: 'flex', - flexWrap: 'wrap', - justifyContent: 'space-between', - }, - search: { maxWidth: '100%', width: '17rem' }, actions: { gap: space['2'], display: 'flex', justifyContent: 'flex-end' }, - dateCell: { whiteSpace: 'nowrap' }, }); diff --git a/packages/mosaic/src/features/organization-profile/requests-table-tab.view.tsx b/packages/mosaic/src/features/organization-profile/requests-table-tab.view.tsx index af32f34990e..f6aaccd47e3 100644 --- a/packages/mosaic/src/features/organization-profile/requests-table-tab.view.tsx +++ b/packages/mosaic/src/features/organization-profile/requests-table-tab.view.tsx @@ -2,10 +2,8 @@ import * as stylex from '@stylexjs/stylex'; import { useRef, useState } from 'react'; import { Avatar } from '../../components/avatar'; -import { Button, SubmitButton } from '../../components/button'; +import { SubmitButton } from '../../components/button'; import { EmptyState } from '../../components/empty-state'; -import { Icon } from '../../components/icon'; -import { InputGroup } from '../../components/input-group'; import { Item } from '../../components/item'; import { Pagination } from '../../components/pagination'; import { panelStyles } from '../../components/profile'; @@ -109,38 +107,15 @@ export function RequestsTableTabView({ }; return (
-
- - - - - table.setGlobalFilter(event.currentTarget.value)} - /> - {table.globalFilter ? ( - - - - ) : null} - -
+ + + - {request.requestedAtLabel} + {request.requestedAtLabel} {hasActions ? (