/**
* Post — a card carrying something somebody said, and what everyone did about it.
*
* Four shapes, because a feed is not one thing. `feed` is the full card: author,
* body, media and a row of counts. `vote` puts a score pill beside a headline
* and a thumbnail, the way a ranked community reads. `compact` drops the media
* and puts the name and handle on one line, for a dense timeline. `media` gives
* the image the whole card and lays the author over it.
*
* What they share is the anatomy — the same `Post.Header`, `Post.Body`,
* `Post.Footer` in every one — so moving between them is a prop rather than a
* rewrite. The variant decides padding, media shape and where the author sits;
* it does not decide which parts exist.
*
* ```tsx
*
*
*
*
*
* I've been paying off my credit card #FinancialFreedom
*
*
*
*
*
*
*
*
* ```
*
* ## Counts change under the finger
*
* Every control here is a toggle over a number, and the number is the point: a
* like that lights up but leaves `215` sitting there has not told you it
* counted. So a stat that changes animates the old value out and the new one in
* along the direction of the change, and `Post.Votes` does the same with its
* arrows. The alternative — repainting the digits in place — is indisting-
* uishable from a re-render, which is exactly the doubt the animation exists to
* remove.
*/
import { type ComponentType, type ReactNode } from 'react';
import { View, type ImageSourcePropType, type PressableProps, type ViewProps } from 'react-native';
import { type VariantProps } from 'tailwind-variants';
import { type IconProps } from '../../icons/index.js';
declare const postVariants: import("tailwind-variants").TVReturnType<{
variant: {
/** The full card — author, body, media, counts. */
feed: {
header: string;
body: string;
media: string;
footer: string;
};
/** A headline with a score beside it, the way a ranked community reads. */
vote: {
header: string;
body: string;
media: string;
footer: string;
};
/** No media, name and handle on one line — for a dense timeline. */
compact: {
root: string;
header: string;
body: string;
media: string;
footer: string;
};
/** The image is the card; the author is laid over it. */
media: {
header: string;
body: string;
media: string;
footer: string;
};
};
size: {
default: {};
sm: {
name: string;
meta: string;
statLabel: string;
};
};
}, {
root: string;
header: string;
author: string;
authorLine: string;
name: string;
handle: string;
meta: string;
action: string;
community: string;
communityName: string;
communityMeta: string;
title: string;
body: string;
media: string;
footer: string;
stat: string;
statLabel: string;
votes: string;
voteButton: string;
voteScore: string;
}, undefined, {
variant: {
/** The full card — author, body, media, counts. */
feed: {
header: string;
body: string;
media: string;
footer: string;
};
/** A headline with a score beside it, the way a ranked community reads. */
vote: {
header: string;
body: string;
media: string;
footer: string;
};
/** No media, name and handle on one line — for a dense timeline. */
compact: {
root: string;
header: string;
body: string;
media: string;
footer: string;
};
/** The image is the card; the author is laid over it. */
media: {
header: string;
body: string;
media: string;
footer: string;
};
};
size: {
default: {};
sm: {
name: string;
meta: string;
statLabel: string;
};
};
}, {
root: string;
header: string;
author: string;
authorLine: string;
name: string;
handle: string;
meta: string;
action: string;
community: string;
communityName: string;
communityMeta: string;
title: string;
body: string;
media: string;
footer: string;
stat: string;
statLabel: string;
votes: string;
voteButton: string;
voteScore: string;
}, import("tailwind-variants").TVReturnType<{
variant: {
/** The full card — author, body, media, counts. */
feed: {
header: string;
body: string;
media: string;
footer: string;
};
/** A headline with a score beside it, the way a ranked community reads. */
vote: {
header: string;
body: string;
media: string;
footer: string;
};
/** No media, name and handle on one line — for a dense timeline. */
compact: {
root: string;
header: string;
body: string;
media: string;
footer: string;
};
/** The image is the card; the author is laid over it. */
media: {
header: string;
body: string;
media: string;
footer: string;
};
};
size: {
default: {};
sm: {
name: string;
meta: string;
statLabel: string;
};
};
}, {
root: string;
header: string;
author: string;
authorLine: string;
name: string;
handle: string;
meta: string;
action: string;
community: string;
communityName: string;
communityMeta: string;
title: string;
body: string;
media: string;
footer: string;
stat: string;
statLabel: string;
votes: string;
voteButton: string;
voteScore: string;
}, undefined, unknown, unknown, undefined>>;
type PostVariant = 'feed' | 'vote' | 'compact' | 'media';
export interface PostProps extends Omit, VariantProps {
className?: string;
/** Which of the four shapes. */
variant?: PostVariant;
/** `sm` tightens the type for a card in a sidebar or a preview. */
size?: 'default' | 'sm';
/** Opening the post itself. The parts inside keep their own presses. */
onPress?: PressableProps['onPress'];
children?: ReactNode;
}
export interface PostHeaderProps extends ViewProps {
className?: string;
children?: ReactNode;
}
export interface PostAuthorProps extends Omit {
className?: string;
/** Display name. */
name: string;
/** `@handle`, shown beside the name in `compact` and under it elsewhere. */
handle?: string;
avatar?: ImageSourcePropType;
/** Initials behind a missing or broken avatar. */
fallback?: string;
/** Draws the verification rosette after the name. */
verified?: boolean;
/** "Posted 3m ago" — whatever the caller wants to call the time. */
timestamp?: ReactNode;
children?: ReactNode;
}
export interface PostActionProps extends ViewProps {
className?: string;
children?: ReactNode;
}
export interface PostCommunityProps extends Omit {
className?: string;
/** The group's name — "r/reactnative", "#design". */
name: string;
avatar?: ImageSourcePropType;
/** How long ago, and anything else that belongs on the line. */
meta?: ReactNode;
children?: ReactNode;
}
export interface PostTitleProps extends ViewProps {
className?: string;
children?: ReactNode;
}
export interface PostBodyProps extends Omit {
className?: string;
/** How many lines before it is cut off. Unlimited by default. */
numberOfLines?: number;
/** Called with the tag, without its `#`. Makes hashtags pressable. */
onTagPress?: (tag: string) => void;
/** Called with the handle, without its `@`. */
onMentionPress?: (handle: string) => void;
children?: ReactNode;
}
export interface PostMediaProps extends Omit {
className?: string;
source: ImageSourcePropType;
/** Width over height. `16 / 10` by default — wide enough not to eat the feed. */
aspectRatio?: number;
/**
* Darkens an edge of the image so type laid over it stays legible.
*
* A gradient rather than a panel: a flat rectangle over the top of a
* photograph has an edge of its own, and that edge reads as a bar covering
* the picture rather than as shading. `media` posts default to `top`, where
* the author sits; everything else to `none`.
*/
scrim?: 'none' | 'top' | 'bottom' | 'both';
/** Laid over the image: an expand affordance, a duration, a gallery count. */
overlay?: ReactNode;
/** Described for a screen reader. An image with nothing to say is decorative. */
alt?: string;
onPress?: PressableProps['onPress'];
children?: ReactNode;
}
export interface PostFooterProps extends ViewProps {
className?: string;
children?: ReactNode;
}
export interface PostStatProps extends Omit {
className?: string;
/** The icon component itself, not an element — it is re-rendered on toggle. */
icon?: ComponentType;
/** The number, or a word where a number would be meaningless ("Save"). */
value?: ReactNode;
/** Lit, and filled. */
active?: boolean;
/** Which colour "lit" is. */
tone?: 'default' | 'like' | 'save' | 'repost';
/** Pushes this stat and everything after it to the trailing edge. */
align?: 'start' | 'end';
children?: ReactNode;
}
export type PostVote = 'up' | 'down' | null;
export interface PostVotesProps extends Omit {
className?: string;
/** The score as it stands, with the reader's own vote already in it. */
score: number | string;
/** Which way this reader voted, if either. */
vote?: PostVote;
/**
* Called with the new vote. Pressing the arrow already cast clears it, so
* `null` arrives as often as the other two — a vote you cannot take back is
* a vote people hesitate over.
*/
onVote?: (vote: PostVote) => void;
/** `vertical` stacks the arrows beside a thumbnail, the way a ranked list reads. */
orientation?: 'horizontal' | 'vertical';
disabled?: boolean;
}
export declare const Post: import("react").ForwardRefExoticComponent> & {
Header: import("react").ForwardRefExoticComponent>;
Author: import("react").ForwardRefExoticComponent>;
Action: import("react").ForwardRefExoticComponent>;
Community: import("react").ForwardRefExoticComponent>;
Title: import("react").ForwardRefExoticComponent>;
Body: import("react").ForwardRefExoticComponent>;
Media: import("react").ForwardRefExoticComponent>;
Footer: import("react").ForwardRefExoticComponent>;
Stat: import("react").ForwardRefExoticComponent>;
Votes: import("react").ForwardRefExoticComponent>;
};
export {};
//# sourceMappingURL=index.d.ts.map