Skip to content

Commit

Permalink
Sync TOC with visible headings
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Aug 9, 2024
1 parent 51e56e1 commit 86fd832
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 12 deletions.
5 changes: 4 additions & 1 deletion docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ export default {
favicon: 'img/favicon.ico',
organizationName: 'react-navigation',
projectName: 'react-navigation.github.io',
scripts: ['/js/snack-helpers.js'],
scripts: [
'/js/snack-helpers.js',
'/js/toc-fixes.js',
],
themeConfig: {
prism: {
theme: require('prism-react-renderer').themes.github,
Expand Down
51 changes: 51 additions & 0 deletions static/js/toc-fixes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Docusaurus shows items in hidden tabs in the TOC.
* It's confusing since it doesn't represent the actual page.
* And clicking on those items doesn't do anything.
* This scripts syncs the TOCs with visible headings.
*/
const sync = () => {
const headings = document.querySelectorAll('article :is(h2, h3)');

// Get all visible headings
const titles = Array.from(headings)
.filter((el) => el.offsetParent)
.map((el) => trim(el.textContent));

const toc = document.querySelectorAll('.table-of-contents li > a');

// Hide TOC items that don't have a corresponding heading
toc.forEach((el) => {
if (!titles.includes(trim(el.textContent))) {
el.parentElement.style.display = 'none';
} else {
el.parentElement.style.display = 'block';
}
});
};

if (window.navigation) {
document.addEventListener('DOMContentLoaded', () => {
// For the first page load, wait till page is loaded
const observer = new MutationObserver(() => {
const article = document.querySelector('article');

if (article) {
observer.disconnect();
sync();

// Listen to navigation events to detect tab query param change
window.navigation.addEventListener('navigate', (event) => {
requestAnimationFrame(sync);
});
}
});

observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
});
}

const trim = (str) => str.trim().replace(/[\u200B-\u200D\uFEFF]/g, '');
22 changes: 11 additions & 11 deletions versioned_docs/version-7.x/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Now, when using `StaticParamList<typeof RootStack>`, it will include the screens

When using the dynamic API, it is necessary to specify the types for each screen as well as the nesting structure as it cannot be inferred from the code.

### Typechecking the navigator
## Typechecking the navigator

To typecheck our route name and params, the first thing we need to do is to create an object type with mappings for route names to the params of the route. For example, say we have a route called `Profile` in our root navigator which should have a param `userId`:

Expand Down Expand Up @@ -187,7 +187,7 @@ The type containing the mapping must be a type alias (e.g. `type RootStackParamL

:::

### Type checking screens
## Type checking screens

To typecheck our screens, we need to annotate the `navigation` and the `route` props received by a screen. The navigator packages in React Navigation export generic types to define types for both the `navigation` and `route` props from the corresponding navigator.

Expand Down Expand Up @@ -274,9 +274,9 @@ type ProfileScreenRouteProp = RouteProp<RootStackParamList, 'Profile'>;

We recommend creating a separate file: `types.tsx` - where you keep the types and import from there in your component files instead of repeating them in each file.

### Nesting navigators
## Nesting navigators

#### Type checking screens and params in nested navigator
### Type checking screens and params in nested navigator

You can [navigate to a screen in a nested navigator](nesting-navigators.md#navigating-to-a-screen-in-a-nested-navigator) by passing `screen` and `params` properties for the nested screen:

Expand All @@ -298,7 +298,7 @@ type TabParamList = {
};
```

#### Combining navigation props
### Combining navigation props

When you nest navigators, the navigation prop of the screen is a combination of multiple navigation props. For example, if we have a tab inside a stack, the `navigation` prop will have both `jumpTo` (from the tab navigator) and `push` (from the stack navigator). To make it easier to combine types from multiple navigators, you can use the `CompositeScreenProps` type:

Expand Down Expand Up @@ -340,7 +340,7 @@ type ProfileScreenNavigationProp = CompositeNavigationProp<
>;
```

### Annotating `useNavigation`
## Annotating `useNavigation`

:::danger

Expand All @@ -355,7 +355,7 @@ To annotate the `navigation` object that we get from `useNavigation`, we can use
const navigation = useNavigation<ProfileScreenNavigationProp>();
```

### Annotating `useRoute`
## Annotating `useRoute`

:::danger

Expand All @@ -370,7 +370,7 @@ To annotate the `route` object that we get from `useRoute`, we can use a type pa
const route = useRoute<ProfileScreenRouteProp>();
```

### Annotating `options` and `screenOptions`
## Annotating `options` and `screenOptions`

When you pass the `options` to a `Screen` or `screenOptions` prop to a `Navigator` component, they are already type-checked and you don't need to do anything special. However, sometimes you might want to extract the options to a separate object, and you might want to annotate it.

Expand Down Expand Up @@ -401,7 +401,7 @@ const options = ({ route }: StackOptionsArgs): StackNavigationOptions => {
};
```

### Annotating `ref` on `NavigationContainer`
## Annotating `ref` on `NavigationContainer`

If you use the `createNavigationContainerRef()` method to create the ref, you can annotate it to type-check navigation actions:

Expand Down Expand Up @@ -447,7 +447,7 @@ const navigationRef =
React.createRef<NavigationContainerRef<RootStackParamList>>();
```

### Specifying default types for `useNavigation`, `Link`, `ref` etc
## Specifying default types for `useNavigation`, `Link`, `ref` etc

Instead of manually annotating these APIs, you can specify a global type for your root navigator which will be used as the default type.

Expand All @@ -465,7 +465,7 @@ The `RootParamList` interface lets React Navigation know about the params accept

Specifying this type is important if you heavily use `useNavigation`, `Link` etc. in your app since it'll ensure type-safety. It will also make sure that you have correct nesting on the `linking` prop.

### Organizing types
## Organizing types

When writing types for React Navigation, there are a couple of things we recommend to keep things organized.

Expand Down

0 comments on commit 86fd832

Please sign in to comment.