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
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ describe('useCiceroneOverlayViewModel', () => {
});
});

describe('cardProps', () => {
it('Carries the positioning data renderCard needs to place itself', async () => {
const { result } = await renderHook(() =>
useCiceroneOverlayViewModel(mountProps()),
);

expect(result.current.cardProps.layout).toEqual(result.current.layout);
expect(result.current.cardProps.width).toBe(result.current.cardWidth);
expect(result.current.cardProps.containerHeight).toBe(result.current.screen.height);
expect(result.current.cardProps.isExiting).toBe(false);
});
});

describe('cardWidth', () => {
it('Uses the prototype width unless the consumer overrides it', async () => {
const { result } = await renderHook(() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,16 @@ export const useCiceroneOverlayViewModel = (props: ICiceroneOverlayProps) => {
placement,
palette,
labels,
layout,
width: cardWidth,
containerHeight: screen.height,
isExiting: props.isExiting,
next: props.next,
previous: props.previous,
skip: props.skip,
stop: props.stop,
}),
[step, props, placement, palette, labels],
[step, props, placement, palette, labels, layout, cardWidth, screen.height],
);

const overlayPress = options.overlayPress ?? 'next';
Expand Down
11 changes: 1 addition & 10 deletions src/components/CiceroneOverlay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export const CiceroneOverlay: React.FC<ICiceroneOverlayProps> = (props) => {
const {
theme,
isHighlight,
cardWidth,
layout,
cardProps,
geometry,
screen,
Expand Down Expand Up @@ -44,14 +42,7 @@ export const CiceroneOverlay: React.FC<ICiceroneOverlayProps> = (props) => {
{options.renderCard ? (
options.renderCard(cardProps)
) : (
<TourCard
{...cardProps}
layout={layout}
width={cardWidth}
containerHeight={screen.height}
isExiting={isExiting}
style={options.cardStyle}
/>
<TourCard {...cardProps} style={options.cardStyle} />
)}
</View>
);
Expand Down
7 changes: 1 addition & 6 deletions src/components/TourCard/types/ITourCardProps.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import type { StyleProp, ViewStyle } from 'react-native';
import type { ICardLayout, ICiceroneCardProps } from '@/types';
import type { ICiceroneCardProps } from '@/types';

export interface ITourCardProps extends ICiceroneCardProps {
layout: ICardLayout;
width: number;
/** The overlay's box, which the layout was measured against. */
containerHeight: number;
isExiting: boolean;
style?: StyleProp<ViewStyle>;
}
6 changes: 6 additions & 0 deletions src/types/ICiceroneCardProps.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ICardLayout } from './ICardLayout';
import type { ICiceroneCardPalette } from './ICiceroneCardPalette';
import type { ICiceroneLabels } from './ICiceroneLabels';
import type { ICiceronePlacement } from './ICiceronePlacement';
Expand All @@ -12,6 +13,11 @@ export interface ICiceroneCardProps {
placement: ICiceronePlacement;
palette: ICiceroneCardPalette;
labels: ICiceroneLabels;
layout: ICardLayout;
width: number;
/** The overlay's box, which the layout was measured against. */
containerHeight: number;
isExiting: boolean;
next: () => void;
previous: () => void;
skip: () => void;
Expand Down
9 changes: 9 additions & 0 deletions website/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,13 @@ What `renderCard` receives.
| `placement` | `'top' \| 'bottom'` |
| `palette` | `ICiceroneCardPalette` |
| `labels` | `ICiceroneLabels` |
| `layout` | `ICardLayout` |
| `width` | `number` |
| `containerHeight` | `number` |
| `isExiting` | `boolean` |
| `next` / `previous` / `skip` / `stop` | `() => void` |

`layout`, `width` and `containerHeight` are what the built-in card uses to position itself
next to the target — `left`/`arrowLeft` from `layout`, anchored against `containerHeight`
depending on `placement`. `isExiting` drives the exit animation. A custom `renderCard` needs
all four to place itself the same way; see [Replacing the card](./theming.md#replacing-the-card).
48 changes: 36 additions & 12 deletions website/docs/theming.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,42 @@ you draw your own. The spotlight, ring and placement stay as they are.
```tsx
<Cicerone.Provider
steps={STEPS}
renderCard={({ step, index, total, isLast, next, skip }) => (
<MyCard
title={step.title}
body={step.text}
counter={`${index + 1}/${total}`}
onNext={next}
onSkip={skip}
nextLabel={isLast ? 'Done' : 'Next'}
/>
)}
renderCard={({
step,
index,
total,
isLast,
next,
skip,
placement,
layout,
width,
containerHeight,
}) => {
const anchorY =
placement === 'bottom' ? (layout.top ?? 0) : containerHeight - (layout.bottom ?? 0);

return (
<MyCard
style={{
position: 'absolute',
left: layout.left,
top: placement === 'bottom' ? anchorY : undefined,
bottom: placement === 'top' ? containerHeight - anchorY : undefined,
width,
}}
title={step.title}
body={step.text}
counter={`${index + 1}/${total}`}
onNext={next}
onSkip={skip}
nextLabel={isLast ? 'Done' : 'Next'}
/>
);
}}
/>
```

Positioning is on you. The `placement` and `layout` you get tell you which side the tour
picked and where it would have put its own card.
Positioning is on you. `placement` tells you which side the tour picked; `layout`, `width`
and `containerHeight` are the same numbers `TourCard` itself uses to land there — see
[`ICiceroneCardProps`](./api.md#iciceronecardprops) for what each one means.
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,13 @@ O que o `renderCard` recebe.
| `placement` | `'top' \| 'bottom'` |
| `palette` | `ICiceroneCardPalette` |
| `labels` | `ICiceroneLabels` |
| `layout` | `ICardLayout` |
| `width` | `number` |
| `containerHeight` | `number` |
| `isExiting` | `boolean` |
| `next` / `previous` / `skip` / `stop` | `() => void` |

`layout`, `width` e `containerHeight` são o que o card embutido usa para se posicionar ao
lado do alvo — `left`/`arrowLeft` vêm de `layout`, ancorado em `containerHeight` conforme o
`placement`. `isExiting` controla a animação de saída. Um `renderCard` customizado precisa
dos quatro para se posicionar do mesmo jeito; veja [Trocando o card](./theming.md#trocando-o-card).
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,42 @@ desenhar o seu. O holofote, o anel e o posicionamento continuam como estão.
```tsx
<Cicerone.Provider
steps={STEPS}
renderCard={({ step, index, total, isLast, next, skip }) => (
<MyCard
title={step.title}
body={step.text}
counter={`${index + 1}/${total}`}
onNext={next}
onSkip={skip}
nextLabel={isLast ? 'Pronto' : 'Próximo'}
/>
)}
renderCard={({
step,
index,
total,
isLast,
next,
skip,
placement,
layout,
width,
containerHeight,
}) => {
const anchorY =
placement === 'bottom' ? (layout.top ?? 0) : containerHeight - (layout.bottom ?? 0);

return (
<MyCard
style={{
position: 'absolute',
left: layout.left,
top: placement === 'bottom' ? anchorY : undefined,
bottom: placement === 'top' ? containerHeight - anchorY : undefined,
width,
}}
title={step.title}
body={step.text}
counter={`${index + 1}/${total}`}
onNext={next}
onSkip={skip}
nextLabel={isLast ? 'Pronto' : 'Próximo'}
/>
);
}}
/>
```

O posicionamento fica com você. O `placement` e o `layout` que chegam dizem qual lado o tour
escolheu e onde ele teria posto o próprio card.
O posicionamento fica com você. `placement` diz qual lado o tour escolheu; `layout`, `width`
e `containerHeight` são os mesmos números que o próprio `TourCard` usa para se posicionar —
veja [`ICiceroneCardProps`](./api.md#iciceronecardprops) para o que cada um significa.
Loading