Skip to content

Commit 382e677

Browse files
authored
Merge pull request #2989 from ably/web-4801-admonitions-tables
[WEB-4801] Add Admonition and Table MDX components
2 parents 5c1e160 + 9368377 commit 382e677

File tree

4 files changed

+224
-53
lines changed

4 files changed

+224
-53
lines changed

src/components/Layout/MDXWrapper.tsx

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, {
2-
PropsWithChildren,
32
useState,
43
createContext,
54
isValidElement,
@@ -15,18 +14,17 @@ import type { CodeSnippetProps, SDKType } from '@ably/ui/core/CodeSnippet';
1514
import cn from '@ably/ui/core/utils/cn';
1615

1716
import { getRandomChannelName } from '../blocks/software/Code/get-random-channel-name';
18-
import Aside from '../blocks/dividers/Aside';
1917

2018
import If from './mdx/If';
2119
import { useCopyableHeaders } from './mdx/headers';
22-
import { Table, TableHead, TableBody, TableRow, TableHeader, TableCell } from './mdx/tables';
20+
import Table from './mdx/Table';
2321
import { Tiles } from './mdx/tiles';
2422
import { PageHeader } from './mdx/PageHeader';
23+
import Admonition from './mdx/Admonition';
2524

2625
import { Frontmatter, PageContextType } from './Layout';
2726
import { ActivePage } from './utils/nav';
2827

29-
import { HtmlComponentPropsData } from '../html-component-props';
3028
import { MarkdownProvider } from '../Markdown';
3129

3230
import Article from '../Article';
@@ -158,15 +156,6 @@ const WrappedCodeSnippet: React.FC<{ activePage: ActivePage } & CodeSnippetProps
158156
);
159157
};
160158

161-
const WrappedAside = (props: PropsWithChildren<{ 'data-type': string }>) => {
162-
return (
163-
<Aside
164-
attribs={{ 'data-type': props['data-type'] }}
165-
data={(<>{props.children}</>) as unknown as HtmlComponentPropsData}
166-
/>
167-
);
168-
};
169-
170159
const META_DESCRIPTION_FALLBACK = `Ably provides a suite of APIs to build, extend, and deliver powerful digital experiences in realtime. Organizations like Toyota, Bloomberg, HubSpot, and Hopin depend on Ably’s platform to offload the growing complexity of business-critical realtime data synchronization at global scale.`;
171160
const META_PRODUCT_FALLBACK = 'pub_sub';
172161

@@ -221,13 +210,14 @@ const MDXWrapper: React.FC<MDXWrapperProps> = ({ children, pageContext, location
221210
components={{
222211
If,
223212
Code: (props) => <WrappedCodeSnippet activePage={activePage} apiKeys={apiKeys} {...props} />,
224-
Aside: WrappedAside,
225-
table: Table,
226-
thead: TableHead,
227-
tbody: TableBody,
228-
tr: TableRow,
229-
th: TableHeader,
230-
td: TableCell,
213+
Aside: Admonition,
214+
Table,
215+
table: Table.Root,
216+
thead: Table.Header,
217+
tbody: Table.Body,
218+
tr: Table.Row,
219+
th: Table.Head,
220+
td: Table.Cell,
231221
Tiles,
232222
}}
233223
>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import React from 'react';
2+
import cn from '@ably/ui/core/utils/cn';
3+
4+
type AdmonitionVariant =
5+
| 'neutral'
6+
| 'note'
7+
| 'further-reading'
8+
| 'important'
9+
| 'new'
10+
| 'warning'
11+
| 'experimental'
12+
| 'updated';
13+
14+
interface AdmonitionProps extends React.HTMLAttributes<HTMLElement> {
15+
'data-type'?: AdmonitionVariant;
16+
}
17+
18+
const admonitionConfig: Record<
19+
AdmonitionVariant,
20+
{
21+
borderColor: string;
22+
backgroundColor: string;
23+
title: string;
24+
}
25+
> = {
26+
neutral: {
27+
borderColor: 'border-l-neutral-500 dark:border-l-neutral-800',
28+
backgroundColor: 'bg-neutral-100 dark:bg-neutral-1200',
29+
title: 'Category',
30+
},
31+
note: {
32+
borderColor: 'border-l-blue-500 dark:border-l-blue-400',
33+
backgroundColor: 'bg-blue-100 dark:bg-blue-800',
34+
title: 'Note',
35+
},
36+
'further-reading': {
37+
borderColor: 'border-l-green-500 dark:border-l-green-400',
38+
backgroundColor: 'bg-green-100 dark:bg-green-800',
39+
title: 'Further reading',
40+
},
41+
important: {
42+
borderColor: 'border-l-orange-500 dark:border-l-orange-600',
43+
backgroundColor: 'bg-orange-100 dark:bg-orange-1000',
44+
title: 'Important',
45+
},
46+
new: {
47+
borderColor: 'border-l-yellow-500 dark:border-l-yellow-400',
48+
backgroundColor: 'bg-yellow-100 dark:bg-yellow-800',
49+
title: 'New',
50+
},
51+
warning: {
52+
borderColor: 'border-l-yellow-500 dark:border-l-yellow-400',
53+
backgroundColor: 'bg-yellow-100 dark:bg-yellow-800',
54+
title: 'Warning',
55+
},
56+
experimental: {
57+
borderColor: 'border-l-purple-500 dark:border-l-purple-400',
58+
backgroundColor: 'bg-purple-100 dark:bg-purple-800',
59+
title: 'Experimental',
60+
},
61+
updated: {
62+
borderColor: 'border-l-pink-500 dark:border-l-pink-400',
63+
backgroundColor: 'bg-pink-100 dark:bg-pink-800',
64+
title: 'Updated',
65+
},
66+
};
67+
68+
const Admonition: React.FC<AdmonitionProps> = ({ 'data-type': dataType = 'note', children, className, ...rest }) => {
69+
const { borderColor, backgroundColor, title } = admonitionConfig[dataType] ?? admonitionConfig.note;
70+
71+
return (
72+
<aside
73+
{...rest}
74+
data-type={dataType}
75+
className={cn(
76+
'border-l px-6 py-4 my-4 rounded-r-lg text-neutral-1000 dark:text-neutral-300',
77+
borderColor,
78+
backgroundColor,
79+
className,
80+
)}
81+
>
82+
<div className="text-sm leading-relaxed [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&>*:nth-child(2)]:inline [&>*:nth-child(3)]:mt-5">
83+
<strong className="font-bold ui-text-p2">{title}: </strong>
84+
{children}
85+
</div>
86+
</aside>
87+
);
88+
};
89+
90+
export default Admonition;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import React from 'react';
2+
import cn from '@ably/ui/core/utils/cn';
3+
4+
// Table Root Component
5+
interface TableRootProps extends React.HTMLAttributes<HTMLDivElement> {
6+
children: React.ReactNode;
7+
}
8+
9+
const TableRoot: React.FC<TableRootProps> = ({ children, className, ...props }) => {
10+
return (
11+
<div className={cn('overflow-x-auto my-4 rounded-lg overflow-hidden', className)} {...props}>
12+
<table className="w-full border-separate border-spacing-0 text-left text-sm">{children}</table>
13+
</div>
14+
);
15+
};
16+
17+
// Table Header Component
18+
interface TableHeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {
19+
children: React.ReactNode;
20+
}
21+
22+
const TableHeader: React.FC<TableHeaderProps> = ({ children, className, ...props }) => {
23+
return (
24+
<thead className={cn('bg-neutral-100 dark:bg-neutral-1200', className)} {...props}>
25+
{children}
26+
</thead>
27+
);
28+
};
29+
30+
// Table Body Component
31+
interface TableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {
32+
children: React.ReactNode;
33+
}
34+
35+
const TableBody: React.FC<TableBodyProps> = ({ children, className, ...props }) => {
36+
return (
37+
<tbody className={className} {...props}>
38+
{children}
39+
</tbody>
40+
);
41+
};
42+
43+
// Table Row Component
44+
interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
45+
children: React.ReactNode;
46+
}
47+
48+
const TableRow: React.FC<TableRowProps> = ({ children, className, ...props }) => {
49+
return (
50+
<tr className={cn('first:border-t', className)} {...props}>
51+
{children}
52+
</tr>
53+
);
54+
};
55+
56+
// Table Head Cell Component
57+
interface TableHeadProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
58+
children: React.ReactNode;
59+
}
60+
61+
const TableHead: React.FC<TableHeadProps> = ({ children, className, ...props }) => {
62+
return (
63+
<th
64+
className={cn(
65+
'px-4 py-3 text-left font-bold text-neutral-1000 dark:text-neutral-300',
66+
'first:rounded-tl-lg last:rounded-tr-lg',
67+
'border-t first:border-l last:border-r border-b border-neutral-300 dark:border-neutral-1000',
68+
className,
69+
)}
70+
{...props}
71+
>
72+
{children}
73+
</th>
74+
);
75+
};
76+
77+
// Table Cell Component
78+
interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
79+
children: React.ReactNode;
80+
}
81+
82+
const TableCell: React.FC<TableCellProps> = ({ children, className, ...props }) => {
83+
return (
84+
<td
85+
className={cn(
86+
'px-4 py-3 font-medium text-neutral-1000 dark:text-neutral-300',
87+
'first:border-l last:border-r border-b border-neutral-300 dark:border-neutral-1000',
88+
'[table>tbody:first-child_tr:first-child_&]:border-t',
89+
'[table>tbody:first-child_tr:first-child_&]:first:rounded-tl-lg [table>tbody:first-child_tr:first-child_&]:last:rounded-tr-lg',
90+
'[tr:last-child_&]:first:rounded-bl-lg [tr:last-child_&]:last:rounded-br-lg',
91+
className,
92+
)}
93+
{...props}
94+
>
95+
{children}
96+
</td>
97+
);
98+
};
99+
100+
// Table Caption Component (optional)
101+
interface TableCaptionProps extends React.HTMLAttributes<HTMLTableCaptionElement> {
102+
children: React.ReactNode;
103+
}
104+
105+
const TableCaption: React.FC<TableCaptionProps> = ({ children, className, ...props }) => {
106+
return (
107+
<caption className={cn('mt-2 text-sm text-neutral-600 dark:text-neutral-700', className)} {...props}>
108+
{children}
109+
</caption>
110+
);
111+
};
112+
113+
// Compound component pattern
114+
export const Table = Object.assign(TableRoot, {
115+
Root: TableRoot,
116+
Header: TableHeader,
117+
Body: TableBody,
118+
Row: TableRow,
119+
Head: TableHead,
120+
Cell: TableCell,
121+
Caption: TableCaption,
122+
});
123+
124+
export default Table;

src/components/Layout/mdx/tables.tsx

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)