Skip to content
Open
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
77 changes: 77 additions & 0 deletions e2e/fixtures/theme-css/doc/prose/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Prose

## Paragraph

some paragraph, some text here

<p>some paragraph, some text here</p>

## Blockquote

> blockquote text

<blockquote>blockquote text</blockquote>

## List

- list item 1
- list item 2

<ul>
<li>list item 1</li>
<li>list item 2</li>
</ul>

<div className="rp-not-doc">
<ul>
<li>list item 1</li>
<li>list item 2</li>
</ul>
</div>

## Table

| Header 1 | Header 2 |
| -------- | -------- |
| Data 1 | Data 2 |
| Data 1 | Data 2 |

<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
</tbody>
</table>

<div className="rp-not-doc">
<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
<tr>
<td>Data 1</td>
<td>Data 2</td>
</tr>
</tbody>
</table>
</div>
8 changes: 6 additions & 2 deletions packages/core/src/node/mdx/remarkPlugins/containerSyntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ const parseTitle = (rawTitle = '', isMDX = false) => {
return trimTailingQuote(matched?.[1] || rawTitle);
};

const getTypeName = (type: DirectiveType | string): string => {
return type[0].toUpperCase() + type.slice(1).toLowerCase();
};

/**
* Construct the DOM structure of the container directive.
* For example:
Expand All @@ -61,7 +65,7 @@ const parseTitle = (rawTitle = '', isMDX = false) => {
* will be transformed to:
*
* <div class="rspress-directive tip">
* <div class="rspress-directive-title">TIP</div>
* <div class="rspress-directive-title">Tip</div>
* <div class="rspress-directive-content">
* <p>This is a tip</p>
* </div>
Expand Down Expand Up @@ -96,7 +100,7 @@ const createContainer = (
class: 'rspress-directive-title',
},
},
children: [{ type: 'text', value: title || type.toUpperCase() }],
children: [{ type: 'text', value: title || getTypeName(type) }],
},
{
type: 'paragraph',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ export default function Playground(props: PlaygroundProps) {
'rspress-playground',
`rspress-playground-${direction}`,
`rspress-playground-reverse-${useReverseLayout ? 'y' : 'n'}`,
'rp-not-doc',
className,
].join(' ');
]
.filter(Boolean)
.join(' ');

return (
<div className={classNames} {...rest}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const Container: React.FC<ContainerProps> = props => {

return (
<NoSSR>
<div className="rspress-preview">
<div className="rspress-preview rp-not-doc">
{isMobile === 'true' ? (
<div className="rspress-preview-wrapper rp-flex">
<div className="rspress-preview-code">{children?.[0]}</div>
Expand Down
11 changes: 6 additions & 5 deletions packages/plugin-twoslash/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ export function pluginTwoslash(options?: PluginTwoslashOptions): RspressPlugin {
class: 'twoslash-popup-trigger',
},
},
completionPopup: {
properties: {
class: 'twoslash-popup-inner',
},
},
// TODO: css changes
// completionPopup: {
// properties: {
// class: 'twoslash-popup-inner',
// },
// },
completionCompose: ({ cursor, popup }) => [
cursor,
<Element>{
Expand Down
22 changes: 7 additions & 15 deletions packages/plugin-twoslash/static/global-styles/twoslash.css
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@
background-color: var(--twoslash-cursor-color);
}

.twoslash .twoslash-popup-inner > .rp-list-disc {
.twoslash .twoslash-popup-inner > ul {
width: 240px;
font-size: 0.8rem;
padding: 6px 8px;
Expand All @@ -256,36 +256,28 @@
gap: 4px;
}

.twoslash .twoslash-popup-inner > .rp-list-disc:hover {
.twoslash .twoslash-popup-inner > ul:hover {
user-select: auto;
}

.twoslash .twoslash-popup-inner > .rp-list-disc li {
.twoslash .twoslash-popup-inner > ul li {
overflow: hidden;
display: flex;
align-items: center;
gap: 0.25em;
line-height: 1em;
}

.twoslash
.twoslash-popup-inner
> .rp-list-disc
li
span.twoslash-completions-unmatched {
.twoslash .twoslash-popup-inner > ul li span.twoslash-completions-unmatched {
color: var(--twoslash-unmatched-color);
}

.twoslash .twoslash-popup-inner > .rp-list-disc .deprecated {
.twoslash .twoslash-popup-inner > ul .deprecated {
text-decoration: line-through;
opacity: 0.5;
}

.twoslash
.twoslash-popup-inner
> .rp-list-disc
li
span.twoslash-completions-matched {
.twoslash .twoslash-popup-inner > ul li span.twoslash-completions-matched {
color: var(--twoslash-matched-color);
}

Expand All @@ -299,7 +291,7 @@
}

/* Icons */
.twoslash .twoslash-popup-inner > .rp-list-disc .twoslash-completions-icon {
.twoslash .twoslash-popup-inner > ul .twoslash-completions-icon {
color: var(--twoslash-unmatched-color);
width: 1em;
flex: none;
Expand Down
18 changes: 18 additions & 0 deletions packages/runtime/src/hooks/useActiveMatcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useCallback, useRef } from 'react';
import { useLocation } from 'react-router-dom';
import { isActive } from '../route';

export const useActiveMatcher = () => {
const { pathname: rawPathname } = useLocation();

const ref = useRef(rawPathname);
ref.current = rawPathname;

const activeMatcher = useCallback((link: string) => {
const rawPathname = ref.current;
const pathname = decodeURIComponent(rawPathname);
return isActive(link, pathname);
}, []);

return activeMatcher;
};
82 changes: 81 additions & 1 deletion packages/runtime/src/hooks/useSidebar.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import {
matchSidebar,
type NormalizedSidebar,
type NormalizedSidebarGroup,
type SidebarData,
type SidebarDivider,
type SidebarItem,
type SidebarSectionHeader,
} from '@rspress/shared';
import { useMemo } from 'react';
import { useLayoutEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { useActiveMatcher } from './useActiveMatcher';
import { useLocaleSiteData } from './useLocaleSiteData';

/**
Expand Down Expand Up @@ -50,3 +55,78 @@ export function useSidebar(): SidebarData {

return sidebarData;
}

function createInitialSidebar(
rawSidebarData: SidebarData,
activeMatcher: (link: string) => boolean,
) {
const matchCache = new WeakMap<
| NormalizedSidebarGroup
| SidebarItem
| SidebarDivider
| SidebarSectionHeader,
boolean
>();
const match = (
item:
| NormalizedSidebarGroup
| SidebarItem
| SidebarDivider
| SidebarSectionHeader,
) => {
if (matchCache.has(item)) {
return matchCache.get(item);
}
if ('link' in item && item.link && activeMatcher(item.link)) {
matchCache.set(item, true);
return true;
}
if ('items' in item) {
const result = item.items.some(child => match(child));
if (result) {
matchCache.set(item, true);
return true;
}
}
matchCache.set(item, false);
return false;
};
const traverse = (
item:
| NormalizedSidebarGroup
| SidebarItem
| SidebarDivider
| SidebarSectionHeader,
) => {
if ('items' in item) {
item.items.forEach(traverse);
if (match(item)) {
item.collapsed = false;
}
}
};
const newSidebarData = rawSidebarData.filter(Boolean).flat();
newSidebarData.forEach(traverse);
return newSidebarData;
}

/**
* handle the collapsed state of the sidebar groups
*/
export function useSidebarDynamic(): [
SidebarData,
React.Dispatch<React.SetStateAction<SidebarData>>,
] {
const rawSidebarData = useSidebar();
const activeMatcher = useActiveMatcher();

const [sidebar, setSidebar] = useState<SidebarData>(() =>
createInitialSidebar(rawSidebarData, activeMatcher),
);

useLayoutEffect(() => {
setSidebar(createInitialSidebar(rawSidebarData, activeMatcher));
}, [rawSidebarData]);

return [sidebar, setSidebar];
}
9 changes: 7 additions & 2 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { Head } from '@unhead/react';
export { createPortal, flushSync } from 'react-dom';
export * from 'react-router-dom';
export { Content } from './Content';
export { useActiveMatcher } from './hooks/useActiveMatcher';
export { ThemeContext, useDark } from './hooks/useDark';
export { useFrontmatter } from './hooks/useFrontmatter';
export { useI18n } from './hooks/useI18n';
Expand All @@ -11,13 +12,17 @@ export { useNav } from './hooks/useNav';
export { PageContext, usePage } from './hooks/usePage';
export { usePageData } from './hooks/usePageData';
export { usePages } from './hooks/usePages';
export { getSidebarDataGroup, useSidebar } from './hooks/useSidebar';
export {
getSidebarDataGroup,
useSidebar,
useSidebarDynamic,
} from './hooks/useSidebar';
export { useSite } from './hooks/useSite';

export { useVersion } from './hooks/useVersion';
export { useWindowSize } from './hooks/useWindowSize';
export { NoSSR } from './NoSSR';
export { isActive, pathnameToRouteService } from './route';
export { isActive, pathnameToRouteService, preloadLink } from './route';
export {
addLeadingSlash,
cleanUrlByConfig,
Expand Down
7 changes: 7 additions & 0 deletions packages/runtime/src/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,10 @@ export function isActive(itemLink: string, currentPathname: string): boolean {
const linkMatched = matchPath(normalizedItemLink, normalizedCurrentPathname);
return linkMatched !== null;
}

export const preloadLink = (link: string) => {
const route = pathnameToRouteService(link);
if (route) {
route.preload();
}
};
5 changes: 0 additions & 5 deletions packages/shared/src/types/defaultTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,6 @@ export interface Config {
* @default false
*/
enableAppearanceAnimation?: boolean;
/**
* Enable scroll to top button on documentation
* @default false
*/
enableScrollToTop?: boolean;
/**
* Whether to redirect to the closest locale when the user visits the site
* @default 'auto'
Expand Down
1 change: 1 addition & 0 deletions packages/theme-default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@rspress/shared": "workspace:*",
"@unhead/react": "^2.0.14",
"body-scroll-lock": "4.0.0-beta.0",
"clsx": "2.1.1",
"copy-to-clipboard": "^3.3.3",
"flexsearch": "0.7.43",
"github-slugger": "^2.0.0",
Expand Down
6 changes: 5 additions & 1 deletion packages/theme-default/rslib.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export default defineConfig({
plugins: [
pluginReact(),
pluginSvgr({ svgrOptions: { exportType: 'default' } }),
pluginSass(),
pluginSass({
sassLoaderOptions: {
additionalData: `$prefix: 'rp-';`,
},
}),
],
source: {
define: {
Expand Down
Loading
Loading