Skip to content
Merged
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
31 changes: 31 additions & 0 deletions docs/blog/accordion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
slug: accordion
title: Accordion
---

An accordion allows to show and hide a piece of content with a smooth animation. Commonly used in "FAQ" sections.

import Accordion from '@site/static/examples/Accordion';
import AccordionSrc from '!!raw-loader!@site/static/examples/Accordion';
import ExampleVideo from '@site/src/components/ExampleVideo';

<InteractiveExample src={AccordionSrc} component={<Accordion />} />

The following implementation of an accordion relies on [shared values](/docs/fundamentals/glossary#shared-value). Leveraging shared values helps to prevent unnecessary re-renders. We define shared values using the useSharedValue hook.

<CollapsibleCode src={AccordionSrc} showLines={[16,16]}/>

<ExampleVideo
sources={{
android: "/react-native-reanimated/recordings/examples/accordion_android.mov",
ios: "/react-native-reanimated/recordings/examples/accordion_ios.mov"
}}
/>

The **AccordionItem** component encapsulates each item in the accordion. A `height` shared value manages the height of the item. The height dynamically adjusts based on the `isExpanded` prop, resulting in smooth expansion and collapse animations. The `duration` prop controls the duration of the animation.

Inside the **AccordionItem**, the children represent the content section. It can accommodate various types of content.

<samp id="Accordion">Accordion</samp>

<CollapsibleCode src={AccordionSrc} showLines={[9,41]}/>
34 changes: 34 additions & 0 deletions docs/blog/bottom-sheet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
slug: bottomsheet
title: Bottom Sheet
---

Bottom sheets are surfaces containing supplementary content, anchored to the bottom of the screen. They can provide users with quick access to contextual information, actions, or settings without interrupting their current workflow.

import BottomSheet from '@site/static/examples/BottomSheet';
import BottomSheetSrc from '!!raw-loader!@site/static/examples/BottomSheet';
import ExampleVideo from '@site/src/components/ExampleVideo';
import CollapsibleCode from '@site/src/components/CollapsibleCode';

<InteractiveExample src={BottomSheetSrc} component={<BottomSheet />} />

The **BottomSheet** component accepts props such as `isOpen` - a [shared value](/docs/fundamentals/glossary#shared-value) indicating whether the bottom sheet is open or closed, `toggleSheet` - a function to toggle the visibility of the bottom sheet, and an optional `duration` for animation.

<samp id="BottomSheet">Bottom Sheet</samp>

<CollapsibleCode src={BottomSheetSrc} showLines={[17,48]}/>

The `height` shared value is used to track the height of the bottom sheet, while the `progress` derived value interpolates between 0 and 1 based on the state of `isOpen`, controlling the animation of the bottom sheet.

<ExampleVideo
sources={{
android: "/react-native-reanimated/recordings/examples/bottom_sheet_android.mov",
ios: "/react-native-reanimated/recordings/examples/bottom_sheet_ios.mov"
}}
/>

<CollapsibleCode src={BottomSheetSrc} showLines={[18,21]}/>

The `useAnimatedStyle` hook helps in creating [animated styles](https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedStyle/) based on shared values. These styles are then applied to **BottomSheet** to make it visually dynamic by adding backdrop and translating bottom sheet to the top.

<CollapsibleCode src={BottomSheetSrc} showLines={[23,32]}/>
43 changes: 43 additions & 0 deletions docs/blog/marquee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
slug: marquee
title: Marquee
---

A marquee is an element used to display scrolling content horizontally within a confined space. It's commonly seen in applications to information such as news tickers, advertisements, or any content that needs continuous display within a limited area.

import Marquee from '@site/static/examples/Marquee';
import MarqueeSrc from '!!raw-loader!@site/static/examples/Marquee';
import ExampleVideo from '@site/src/components/ExampleVideo';
import CollapsibleCode from '@site/src/components/CollapsibleCode';

<InteractiveExample src={MarqueeSrc} component={<Marquee />} />

Now, let's understand how this example works:

The **MeasureElement** component measures the width of its children and passes this information to its parent component, Marquee.

<samp id="Marquee">Marquee</samp>

<CollapsibleCode src={MarqueeSrc} showLines={[8,18]}/>

<ExampleVideo
sources={{
android: "/react-native-reanimated/recordings/examples/marquee_android.mov",
ios: "/react-native-reanimated/recordings/examples/marquee_ios.mov"
}}
/>

We use the `useFrameCallback` hook to execute the animation logic on each frame.

<CollapsibleCode src={MarqueeSrc} showLines={[57,62]}/>

It is located inside **ChildrenScroller** component that manages the scrolling animation by updating the offset value. It determines the horizontal translation of the child components, creates clones of the children and animates them horizontally based on the specified duration.

<samp id="Marquee">Marquee</samp>
<CollapsibleCode src={MarqueeSrc} showLines={[43,76]}/>

The **Marquee** component serves as the main orchestrator of the marquee effect. It calculates necessary dimensions, renders child components within a container, and coordinates the animation by utilizing the ChildrenScroller component.

<samp id="Marquee">Marquee</samp>

<CollapsibleCode src={MarqueeSrc} showLines={[78,104]}/>
60 changes: 60 additions & 0 deletions docs/blog/section-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
slug: sectionlist
title: Section List
---

import SectionList from '@site/static/examples/SectionList';
import SectionListSrc from '!!raw-loader!@site/static/examples/SectionList';
import ExampleVideo from '@site/src/components/ExampleVideo';
import CollapsibleCode from '@site/src/components/CollapsibleCode';

Section lists allow you to organize long lists of content by dividing them with headings.

<InteractiveExample src={SectionListSrc} component={<SectionList />} />

The primary component, **SectionList**, acts as the main orchestrator of the entire Section List interface. It coordinates the rendering of the table of contents and individual content sections.

<samp id="SectionList">Section List</samp>

<CollapsibleCode src={SectionListSrc} showLines={[150,174]}/>

Within **SectionList**, there are two key components: **TableOfContents** and **SectionCards**.

**TableOfContents** is responsible for rendering the list of section names as a table of contents. It receives props such as `data`, `visibleIndex`, `sectionCardsRef`, and `tableOfContentsRef` to manage navigation and synchronization between the table of contents and section content.

<samp id="SectionList">Section List</samp>

<CollapsibleCode src={SectionListSrc} showLines={[123,148]}/>

**SectionCards**, on the other hand, manages the rendering of individual sections and their corresponding content. It receives props: `sections`, `visibleIndex`, `sectionCardsRef`, and `tableOfContentsRef` to render the content sections and handle scrolling interactions.

<samp id="SectionList">Section List</samp>

<CollapsibleCode src={SectionListSrc} showLines={[198,256]}/>

<ExampleVideo
sources={{
android: "/react-native-reanimated/recordings/examples/section_list_android.mov",
ios: "/react-native-reanimated/recordings/examples/section_list_ios.mov"
}}
/>

The `onScroll` in **SectionCards** calculates the offset as the user scrolls through the content and determines which section is currently most visible on the screen. It is done by comparing the distance of each section from the top of the screen - it identifies the section closest to the viewport's top edge.

<CollapsibleCode src={SectionListSrc} showLines={[204,227]}/>

We use the `useSharedValue` hook to create mutable shared values across different components. For instance, `selectedItem` and `visibleIndex` are [shared values](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value) used to manage the currently selected section and its visibility index.

<CollapsibleCode src={SectionListSrc} showLines={[151,152]}/>

Additionally, we use `useAnimatedStyle` hook to define [animated styles](https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedStyle/) based on the shared values. Then, we apply these animated styles to components to create dynamic visual effects, such as changing font weights and adding bottom borders.

<CollapsibleCode src={SectionListSrc} showLines={[96,99]}/>

To enable interaction with the FlashList component - such as scrolling to specific sections, the code utilizes variables created using `useRef` such as `sectionCardsRef` and `tableContentsRef`

<CollapsibleCode src={SectionListSrc} showLines={[154,155]}/>

Here, the `debounce` function throttles the invocations of `onScroll` event handler which improves the perfomrance.

<CollapsibleCode src={SectionListSrc} showLines={[85,93]}/>
21 changes: 20 additions & 1 deletion docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ const config = {
organizationName: 'software-mansion', // Usually your GitHub org/user name.
projectName: 'react-native-reanimated', // Usually your repo name.

scripts: [
{
src: '/react-native-reanimated/js/snack-helpers.js',
async: true,
},
],

onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'throw',

Expand Down Expand Up @@ -58,10 +65,15 @@ const config = {
trackingID: 'UA-41044622-6',
anonymizeIP: true,
},
blog: {
routeBasePath: '/examples',
blogSidebarTitle: 'Examples',
blogSidebarCount: 'ALL',
showReadingTime: false,
},
}),
],
],

themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
Expand All @@ -79,6 +91,13 @@ const config = {
srcDark: 'img/logo-dark.svg',
},
items: [
{
to: 'docs/fundamentals/getting-started',
activeBasePath: 'docs',
label: 'Docs',
position: 'left',
},
{ to: 'examples/accordion', label: 'Examples', position: 'left' },
{
type: 'docsVersionDropdown',
position: 'right',
Expand Down
1 change: 1 addition & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@emotion/styled": "^11.10.6",
"@mdx-js/react": "^1.6.22",
"@mui/material": "^5.12.0",
"@shopify/flash-list": "^1.6.3",
"babel-polyfill": "^6.26.0",
"babel-preset-expo": "^9.2.2",
"babel-preset-react-native": "^4.0.1",
Expand Down
43 changes: 43 additions & 0 deletions docs/src/components/ExampleVideo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';

interface Props {
sources: {
android: string;
ios: string;
};
}

export default function ExampleVideo({ sources }: Props) {
return (
<div
style={{
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: '16px',
display: 'flex',
}}>
<video
autoPlay
muted
loop
style={{
height: 'auto',
width: '48%',
}}>
<source src={sources.android} type="video/mp4" />
Your browser does not support the video tag.
</video>
<video
autoPlay
muted
loop
style={{
height: 'auto',
width: '48%',
}}>
<source src={sources.ios} type="video/mp4" />
Your browser does not support the video tag.
</video>
</div>
);
}
13 changes: 13 additions & 0 deletions docs/src/css/examples.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
time {
display: none;
}

.pagination-nav {
display: none;
}

.navbar-sidebar__rightItems {
display: flex;
flex-direction: row;
gap: 1rem;
}
1 change: 1 addition & 0 deletions docs/src/css/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import 'colors.css';
@import 'typography.css';
@import 'overrides.css';
@import 'examples.css';
5 changes: 5 additions & 0 deletions docs/src/css/overrides.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,8 @@ table thead tr {
border: none;
margin-bottom: 8px;
}

.snack-link {
display: inline-block;
margin-bottom: 25px;
}
2 changes: 1 addition & 1 deletion docs/src/theme/Navbar/Content/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function NavbarContent() {
<div className={styles.logoWrapper}>
<NavbarLogo />
</div>
<NavbarItems items={leftItems} />
{!isLanding && <NavbarItems items={leftItems} />}
{!searchBarItem && !isMobile && !isLanding && <AlgoliaSearchBar />}
{!isMobile && isDocumentation && (
<NavbarColorModeToggle className={styles.colorModeToggle} />
Expand Down
13 changes: 10 additions & 3 deletions docs/src/theme/Navbar/MobileSidebar/Layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,16 @@ export default function NavbarMobileSidebarLayout({ header, secondaryMenu }) {
);
})}
</div>
<a href="https://github.com/software-mansion/react-native-reanimated/tree/main/docs">
<div className={clsx(styles.sidebarGithubIcon, 'header-github')} />
</a>
<div className="navbar-sidebar__rightItems">
<a
href={'/react-native-reanimated/docs/fundamentals/getting-started'}>
Docs
</a>
<a href={'/react-native-reanimated/examples/accordion'}>Examples</a>
<a href="https://github.com/software-mansion/react-native-reanimated/tree/main/docs">
<div className={clsx(styles.sidebarGithubIcon, 'header-github')} />
</a>
</div>
</div>
</div>
);
Expand Down
Loading