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
137 changes: 117 additions & 20 deletions apps/docs/docs/components/inputs/SlideButton/_mobileExamples.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import useBaseUrl from '@docusaurus/useBaseUrl';
import ThemedImage from '@theme/ThemedImage';

### SlideButton
## Basics

Use the `onChange` prop to listen and make changes to the `checked` state.
Use the `onChange` callback to update the `checked` state. This is the primary callback that controls both the visual and accessible state of the component.

<ThemedImage
sources={{
Expand All @@ -25,17 +25,16 @@ function Example() {
<SlideButton
checked={checked}
onChange={setChecked}
onSlideComplete={() => console.log('Completed')}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
/>
);
}
```

### Negative SlideButton
## Variants

You can use the `variant` prop to change the color of the button.
Use the `variant` prop to change the color of the button. The default variant is `primary`. Available variants are `negative` and `positive`.

<ThemedImage
sources={{
Expand All @@ -57,7 +56,6 @@ function Example() {
<SlideButton
checked={checked}
onChange={setChecked}
onSlideComplete={() => console.log('Completed')}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
variant="negative"
Expand All @@ -66,7 +64,7 @@ function Example() {
}
```

### Compact SlideButton
## Compact

Use the `compact` prop to reduce the height, border-radius and padding of the button:

Expand All @@ -78,7 +76,6 @@ function Example() {
<SlideButton
checked={checked}
onChange={setChecked}
onSlideComplete={() => console.log('Completed')}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
compact
Expand All @@ -87,9 +84,31 @@ function Example() {
}
```

### Auto Complete on Threshold
## Disabled

Use the `disabled` prop to prevent interaction. This works for both unchecked and checked states.

```jsx
function Example() {
return (
<VStack gap={2}>
<SlideButton
checked={false}
disabled
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
/>
<SlideButton checked disabled uncheckedLabel="Swipe to confirm" checkedLabel="Confirmed" />
</VStack>
);
}
```

## Auto Complete on Threshold

You can set the button to automatically complete when the slide reaches the threshold:
By default, the user must release the handle past the threshold to complete. Set `autoCompleteSlideOnThresholdMet` to automatically complete as soon as the threshold is reached, without requiring release.

You can also adjust the threshold via `checkThreshold` (a value from 0 to 1, defaulting to 0.7).

```jsx
function Example() {
Expand All @@ -99,7 +118,6 @@ function Example() {
<SlideButton
checked={checked}
onChange={setChecked}
onSlideComplete={() => console.log('Completed')}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
autoCompleteSlideOnThresholdMet
Expand All @@ -108,9 +126,41 @@ function Example() {
}
```

### Custom Nodes on SlideButton
## Callback Lifecycle

SlideButton fires callbacks in a specific order during the slide gesture:

1. `onSlideStart` -- when the gesture begins
2. `onChange` -- when the slide completes past the threshold (sets `checked` to `true`)
3. `onSlideComplete` -- immediately after `onChange`
4. `onSlideEnd` -- always fires last

If the user releases before the threshold, `onSlideCancel` fires instead, followed by `onSlideEnd`.

**Important:** Always use `onChange` to manage the `checked` state. The `checked` prop drives the component's `accessibilityLabel` (switching between `uncheckedLabel` and `checkedLabel`), so failing to update it means screen readers won't announce the state change. Use `onSlideComplete` only for supplementary side effects (e.g. analytics, haptic feedback) that don't affect accessible state.

```jsx
function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
onSlideStart={() => console.log('Started')}
onSlideComplete={() => console.log('Completed')}
onSlideCancel={() => console.log('Cancelled')}
onSlideEnd={() => console.log('Ended')}
uncheckedLabel="Swipe to confirm"
checkedLabel="Confirming..."
/>
);
}
```

## Custom Nodes

You can also use SlideButton with custom nodes.
Use `startUncheckedNode` and `endCheckedNode` to replace the default arrow icon and loading indicator on the handle.

<ThemedImage
sources={{
Expand All @@ -121,7 +171,7 @@ You can also use SlideButton with custom nodes.
borderRadius: 'var(--borderRadius-400)',
border: '1.5px solid var(--color-bgLine)',
}}
alt="Custom nodes on slide button"
alt="Slide button with custom bell icons on the handle"
/>

```jsx
Expand All @@ -132,19 +182,41 @@ function Example() {
<SlideButton
checked={checked}
onChange={setChecked}
onSlideComplete={() => console.log('Completed')}
uncheckedLabel="Swipe to enable notifications"
checkedLabel="Enabling..."
startUncheckedNode={<Icon color="fgInverse" name="bellCheck" size="m" />}
endCheckedNode={<Icon color="fgInverse" name="bellInactive" size="m" />}
startUncheckedNode={<Icon color="fgInverse" name="bell" size="m" />}
endCheckedNode={<Icon color="fgInverse" name="bellCheck" size="m" />}
/>
);
}
```

### Custom Background and Handle Components
## Labels as Nodes

The `uncheckedLabel` and `checkedLabel` props accept `ReactNode`, so you can pass custom styled text or other components. When using non-string labels, the component uses `accessibilityLabelledBy` to associate the handle with the container element, so ensure your label nodes contain meaningful text content.

You can customize the background and handle components of the SlideButton.
```jsx
function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel={<Text font="label2">Swipe to confirm</Text>}
checkedLabel={
<Text color="fgInverse" font="label2">
Confirming...
</Text>
}
/>
);
}
```

## Custom Background and Handle Components

You can fully customize the background and handle by providing your own components via `SlideButtonBackgroundComponent` and `SlideButtonHandleComponent`. Your components receive typed props (`SlideButtonBackgroundProps` and `SlideButtonHandleProps`) including a `progress` spring value and the current `checked` state.

<ThemedImage
sources={{
Expand All @@ -155,7 +227,7 @@ You can customize the background and handle components of the SlideButton.
borderRadius: 'var(--borderRadius-400)',
border: '1.5px solid var(--color-bgLine)',
}}
alt="Custom background and handle components"
alt="Slide button with custom green/red background and handle"
/>

```jsx
Expand Down Expand Up @@ -208,3 +280,28 @@ function Example() {
);
}
```

## Accessibility

SlideButton has built-in accessibility support. The component automatically derives its `accessibilityLabel` from the `checked` state -- displaying `uncheckedLabel` when unchecked and `checkedLabel` when checked. It also registers an `activate` accessibility action so screen readers can trigger the slide without performing a gesture.

**Use `onChange` as your primary callback.** The `onChange` callback updates the `checked` prop, which controls the accessible label. Placing critical logic in `onSlideComplete` without updating `checked` via `onChange` will leave the accessible state stale, meaning screen readers won't announce the confirmation.

When providing a custom `SlideButtonHandleComponent`, always spread the incoming props to preserve the built-in `accessibilityActions` and `onAccessibilityAction` handlers, and set `accessibilityLabel` and `accessibilityRole="button"` on the handle element.

When using `ReactNode` labels instead of strings, the component uses `accessibilityLabelledBy` to link to the container element, so ensure your custom label nodes contain meaningful text.

```jsx
function Example() {
const [checked, setChecked] = useState(false);

return (
<SlideButton
checked={checked}
onChange={setChecked}
uncheckedLabel="Swipe to send payment"
checkedLabel="Sending payment..."
/>
);
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,10 @@
"url": "/components/inputs/Pressable/"
}
],
"dependencies": []
"dependencies": [
{
"name": "react-native-gesture-handler",
"version": "^2.16.2"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { MDXArticle } from '@site/src/components/page/MDXArticle';
<MDXArticle>
## Installation

:::tip Starting a new project?
Check out our [templates](/getting-started/templates) for pre-configured starter apps with CDS already set up.
:::

To install the CDS library for React Native applications, run the following command:

```bash
Expand Down
4 changes: 4 additions & 0 deletions apps/docs/docs/getting-started/installation/_webContent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { MDXArticle } from '@site/src/components/page/MDXArticle';
<MDXArticle>
## Installation

:::tip Starting a new project?
Check out our [templates](/getting-started/templates) for pre-configured starter apps with CDS already set up.
:::

To install the CDS library for React web applications, run the following command:

```bash
Expand Down
105 changes: 105 additions & 0 deletions apps/docs/docs/getting-started/templates/_mobileContent.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { MDXSection } from '@site/src/components/page/MDXSection';
import { MDXArticle } from '@site/src/components/page/MDXArticle';
import { TemplateCard } from '@site/src/components/page/TemplateCard';
import { HStack } from '@coinbase/cds-web/layout';
import ThemedImage from '@theme/ThemedImage';

<MDXSection>
<MDXArticle>

## Get started

The easiest way to get started with CDS on mobile is with a template. The Expo template includes the required CDS packages, dependencies, and pre-configured settings with a working example application to help you start building.

<HStack gap={2} style={{ marginTop: '1.5rem', flexWrap: 'wrap', alignItems: 'stretch' }}>
<TemplateCard
name="Expo"
description="Built for cross-platform mobile applications with React Native"
href="https://github.com/coinbase/cds/tree/master/templates/expo-app"
icon={
<ThemedImage
sources={{
light: '/img/logos/frameworks/expo_light.png',
dark: '/img/logos/frameworks/expo_dark.png',
}}
alt="Expo"
style={{ paddingTop: 'var(--space-0_75)', paddingBottom: 'var(--space-0_75)' }}
height="100%"
/>
}
/>
</HStack>

</MDXArticle>
</MDXSection>

<MDXSection>
<MDXArticle>

## Installation

To create a new project from the template, use `gitpick` to bootstrap your application:

### Expo

```bash
npx -y gitpick coinbase/cds/tree/master/templates/expo-app cds-expo
cd cds-expo
```

</MDXArticle>
</MDXSection>

<MDXSection>
<MDXArticle>

## Setup

After creating your project, install dependencies and start developing:

```bash
# We suggest using nvm to manage Node.js versions
nvm install
nvm use

# Enable corepack for package manager setup
corepack enable

# Install dependencies
yarn

# Start development server
yarn start
```

</MDXArticle>
</MDXSection>

<MDXSection>
<MDXArticle>

## What's included

All templates come pre-configured with:

- Latest CDS packages (`@coinbase/cds-mobile`, `@coinbase/cds-icons`, etc.)
- TypeScript configuration
- Example components demonstrating common UI patterns
- Theme setup with CDS default theme
- Navigation with React Navigation

</MDXArticle>
</MDXSection>

<MDXSection>
<MDXArticle>

## Next steps

After setting up your template, learn how to customize and extend CDS:

- [Theming](/getting-started/theming) - Customize colors, spacing, and typography
- [Installation](/getting-started/installation) - Manual installation and setup options

</MDXArticle>
</MDXSection>
Loading