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
3 changes: 3 additions & 0 deletions docs/component-docs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';

import { extendedExamples } from './src/data/extendedExamples.ts';
import { liveExamples, type LiveExample } from './src/data/liveExamples.ts';
import { screenshots } from './src/data/screenshots.ts';
import { themeColors } from './src/data/themeColors.ts';

Expand All @@ -27,6 +28,7 @@ type ComponentDocsConfig = {
themeColors: Record<string, unknown>;
screenshots: Record<string, unknown>;
extendedExamples: Record<string, unknown>;
liveExamples: Record<string, LiveExample>;
};
};

Expand Down Expand Up @@ -186,6 +188,7 @@ const componentDocsConfig: ComponentDocsConfig = {
themeColors,
screenshots,
extendedExamples,
liveExamples,
},
};

Expand Down
2 changes: 2 additions & 0 deletions docs/plugins/component-docs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { createComponentParser } from './parser.ts';
import { renderComponentPage } from './render.ts';
import type { ComponentPageConfig } from './types.ts';
import type { Page, Pages } from '../../component-docs.config.ts';
import type { LiveExample } from '../../src/data/liveExamples.ts';

type ComponentDocsPluginOptions = {
customFields: {
extendedExamples: Record<string, unknown>;
knownIssues: Record<string, Record<string, string>>;
liveExamples: Record<string, LiveExample>;
moreExamples: Record<string, Record<string, string>>;
screenshots: Record<string, unknown>;
themeColors: Record<string, unknown>;
Expand Down
10 changes: 8 additions & 2 deletions docs/plugins/component-docs/render.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import path from 'node:path';

import type { ComponentDoc, ComponentProp } from './types.ts';
import type { LiveExample } from '../../src/data/liveExamples.ts';

type CustomFields = {
extendedExamples: Record<string, unknown>;
knownIssues: Record<string, Record<string, string>>;
liveExamples: Record<string, LiveExample>;
moreExamples: Record<string, Record<string, string>>;
screenshots: Record<string, unknown>;
themeColors: Record<string, unknown>;
Expand Down Expand Up @@ -127,7 +129,10 @@ export const renderComponentPage = (
const usage = summaryMatch
? doc.description.slice(summary.length)
: doc.description;
const screenshot = customFields.screenshots[doc.title];
const liveExample = customFields.liveExamples[doc.title];
const screenshot = liveExample
? undefined
: customFields.screenshots[doc.title];
const extendedExample = customFields.extendedExamples[doc.title];
const extendedExampleTitle =
extendedExample && typeof extendedExample === 'object'
Expand All @@ -144,11 +149,12 @@ import PropTable from '@docs/components/PropTable.tsx';
import ExtendsLink from '@docs/components/ExtendsLink.tsx';
import ThemeColorsTable from '@docs/components/ThemeColorsTable.tsx';
import ScreenshotTabs from '@docs/components/ScreenshotTabs.tsx';
import ExtendedExample from '@docs/components/ExtendedExample.tsx';
import ExtendedExample from '@docs/components/ExtendedExample.tsx';${liveExample ? `\nimport { ${liveExample.exports.join(', ')} } from '${liveExample.module}';` : ''}

${summary}

${screenshot ? `<ScreenshotTabs screenshotData={${JSON.stringify(screenshot)}} />` : ''}
${liveExample ? liveExample.exports.map((name) => `<${name} />`).join('\n') : ''}

${usage}

Expand Down
65 changes: 65 additions & 0 deletions docs/src/components/FABExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import * as React from 'react';

import { FAB, type FABSize, type FABVariant } from 'react-native-paper';

import InteractiveExample, { ExampleRow, Labelled } from './InteractiveExample';

const VARIANTS: FABVariant[] = [
'primary',
'secondary',
'tertiary',
'tonalPrimary',
'tonalSecondary',
'tonalTertiary',
];

const SIZES: FABSize[] = ['default', 'medium', 'large'];

export const FABVariantsExample = () => (
<InteractiveExample title="Variants">
<ExampleRow>
{VARIANTS.map((variant) => (
<Labelled key={variant} label={variant}>
<FAB
icon="pencil"
variant={variant}
onPress={() => {}}
aria-label={`${variant} floating action button`}
/>
</Labelled>
))}
</ExampleRow>
</InteractiveExample>
);

export const FABSizesExample = () => (
<InteractiveExample title="Sizes">
<ExampleRow>
{SIZES.map((size) => (
<Labelled key={size} label={size}>
<FAB
icon="pencil"
size={size}
onPress={() => {}}
aria-label={`${size} floating action button`}
/>
</Labelled>
))}
</ExampleRow>
</InteractiveExample>
);

export const FABExtendedExample = () => {
const [expanded, setExpanded] = React.useState(true);

return (
<InteractiveExample title="Extended">
<FAB.Extended
icon="plus"
label="New message"
expanded={expanded}
onPress={() => setExpanded((value) => !value)}
/>
</InteractiveExample>
);
};
79 changes: 79 additions & 0 deletions docs/src/components/InteractiveExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';

import { DarkTheme, LightTheme, Provider, Text } from 'react-native-paper';

import { useColorMode } from './theme-common';

/**
* Row of demo variations, wrapping on narrow viewports.
*/
export const ExampleRow = ({ children }: React.PropsWithChildren) => (
<View style={styles.row}>{children}</View>
);

/**
* A single demo variation captioned with the prop value it illustrates.
*/
export const Labelled = ({
label,
children,
}: React.PropsWithChildren<{ label: string }>) => (
<View style={styles.item}>
{children}
<Text style={styles.itemLabel}>{label}</Text>
</View>
);

type InteractiveExampleProps = React.PropsWithChildren<{
/**
* Short caption rendered above the live preview, describing what the
* example demonstrates.
*/
title?: string;
}>;

/**
* Shared shell for live component demos embedded in the docs.
*
* The Paper theme follows the active docs color mode so demos match the
* surrounding page.
*/
const InteractiveExample = ({ title, children }: InteractiveExampleProps) => {
const isDarkTheme = useColorMode().colorMode === 'dark';

return (
<Provider theme={isDarkTheme ? DarkTheme : LightTheme}>
<figure className="paper-interactive-example">
{title ? (
<figcaption className="paper-interactive-example__title">
{title}
</figcaption>
) : null}
<View style={styles.content}>{children}</View>
</figure>
</Provider>
);
};

const styles = StyleSheet.create({
content: {
alignItems: 'flex-start',
},
row: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
gap: 24,
},
item: {
alignItems: 'center',
gap: 8,
},
itemLabel: {
fontSize: 12,
opacity: 0.7,
},
});

export default InteractiveExample;
66 changes: 66 additions & 0 deletions docs/src/components/SwitchExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as React from 'react';

import { Switch } from 'react-native-paper';

import InteractiveExample, { ExampleRow, Labelled } from './InteractiveExample';

export const SwitchStatesExample = () => {
const [on, setOn] = React.useState(true);
const [off, setOff] = React.useState(false);

return (
<InteractiveExample title="Enabled">
<ExampleRow>
<Labelled label="selected">
<Switch value={on} onValueChange={setOn} aria-label="Selected" />
</Labelled>
<Labelled label="unselected">
<Switch value={off} onValueChange={setOff} aria-label="Unselected" />
</Labelled>
</ExampleRow>
</InteractiveExample>
);
};

export const SwitchDisabledExample = () => (
<InteractiveExample title="Disabled">
<ExampleRow>
<Labelled label="selected">
<Switch value disabled aria-label="Disabled and selected" />
</Labelled>
<Labelled label="unselected">
<Switch value={false} disabled aria-label="Disabled and unselected" />
</Labelled>
</ExampleRow>
</InteractiveExample>
);

export const SwitchIconsExample = () => {
const [on, setOn] = React.useState(true);
const [off, setOff] = React.useState(false);

return (
<InteractiveExample title="With icons in the handle">
<ExampleRow>
<Labelled label="selected">
<Switch
value={on}
onValueChange={setOn}
checkedIcon="check"
uncheckedIcon="close"
aria-label="Selected with icon"
/>
</Labelled>
<Labelled label="unselected">
<Switch
value={off}
onValueChange={setOff}
checkedIcon="check"
uncheckedIcon="close"
aria-label="Unselected with icon"
/>
</Labelled>
</ExampleRow>
</InteractiveExample>
);
};
16 changes: 16 additions & 0 deletions docs/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -1286,3 +1286,19 @@ html:not(.dark) .paper-version-selector-menu {
padding: 18px;
}
}

.paper-interactive-example {
margin: 16px 0 24px;
padding: 24px;
border: 1px solid var(--rp-c-divider, rgba(148, 163, 184, 0.24));
border-radius: 16px;
background: var(--rp-c-bg-soft, rgba(148, 163, 184, 0.06));
overflow-x: auto;
}

.paper-interactive-example__title {
margin-bottom: 16px;
color: var(--rp-c-text-2);
font-size: 13px;
font-weight: 600;
}
25 changes: 25 additions & 0 deletions docs/src/data/liveExamples.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export type LiveExample = {
/** Module specifier the examples are imported from. */
module: string;
/** Named exports rendered, in order, under the page summary. */
exports: string[];
};

export const liveExamples: Record<string, LiveExample> = {
FAB: {
module: '@docs/components/FABExample.tsx',
exports: ['FABVariantsExample', 'FABSizesExample'],
},
Extended: {
module: '@docs/components/FABExample.tsx',
exports: ['FABExtendedExample'],
},
Switch: {
module: '@docs/components/SwitchExample.tsx',
exports: [
'SwitchStatesExample',
'SwitchDisabledExample',
'SwitchIconsExample',
],
},
};
12 changes: 0 additions & 12 deletions docs/src/data/screenshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,6 @@ export const screenshots = {
'Drawer.CollapsedItem': 'screenshots/drawer-collapsed.png',
'Drawer.Item': 'screenshots/drawer-item.png',
'Drawer.Section': 'screenshots/drawer-section.png',
FAB: {
'all variants': 'screenshots/fab-1.png',
'all sizes': 'screenshots/fab-2.png',
'all modes': 'screenshots/fab-4.png',
'with label': 'screenshots/fab-3.png',
},
AnimatedFAB: 'screenshots/animated-fab.gif',
'FAB.Group': 'screenshots/fab-group.gif',
Icon: 'screenshots/icon.png',
Expand Down Expand Up @@ -138,12 +132,6 @@ export const screenshots = {
elevated: 'screenshots/surface-elevated-full-width.png',
flat: 'screenshots/surface-flat-full-width.png',
},
Switch: {
'Android (enabled)': 'screenshots/switch-enabled.android.png',
'Android (disabled)': 'screenshots/switch-disabled.android.png',
'iOS (enabled)': 'screenshots/switch-enabled.ios.png',
'iOS (disabled)': 'screenshots/switch-disabled.ios.png',
},
Text: 'screenshots/typography.png',
TextInput: {
filled: 'screenshots/text-input-filled.png',
Expand Down
2 changes: 2 additions & 0 deletions src/components/Switch/Switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ const styles = StyleSheet.create({
left: 0,
right: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center',
},
});

Expand Down
4 changes: 4 additions & 0 deletions src/components/__tests__/__snapshots__/Switch.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,9 @@ exports[`Switch render renders with checked icon 1`] = `
style={
[
{
"alignItems": "center",
"bottom": 0,
"justifyContent": "center",
"left": 0,
"position": "absolute",
"right": 0,
Expand Down Expand Up @@ -1215,7 +1217,9 @@ exports[`Switch render renders with per-state icons 1`] = `
style={
[
{
"alignItems": "center",
"bottom": 0,
"justifyContent": "center",
"left": 0,
"position": "absolute",
"right": 0,
Expand Down