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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![NPM Downloads](https://img.shields.io/npm/dm/@fawazahmed/react-native-read-more) ![NPM License](https://img.shields.io/npm/l/@fawazahmed/react-native-read-more) ![NPM Version](https://img.shields.io/npm/v/@fawazahmed/react-native-read-more)

#### Drop a :star: to this repo, it surely keeps me going.
#### Please give :star: and thanks for supporting!
#### Sponsor my work on [lfx crowdfunding](https://crowdfunding.lfx.linuxfoundation.org/projects/react-native-read-more) or [Tidelift](https://tidelift.com/funding/github/npm/@fawazahmed/react-native-read-more).

# react-native-read-more
Expand Down Expand Up @@ -77,9 +77,11 @@ export default Home;
| `onExpand` | `func` | no | optional callback executed when expanded
| `onCollapse` | `func` | no | optional callback executed when collapsed
| `onReady` | `func` | no | optional callback executed when see more placement measurements are completed
| `collapsed` | `bool` | no | Control collapsed state programatically see [issue](https://github.com/fawaz-ahmed/react-native-read-more/issues/61)
| `debug` | `bool` | no | print debug logs to examine
| `seeMoreContainerStyleSecondary` | `object` | no | Incase of text overlap, pass { position: 'relative' } see [issue](https://github.com/fawaz-ahmed/react-native-read-more/issues/52) (not recommended)
| `onSeeMoreBlocked` | `func` | no | when a function is passed, will disable the default See More toggling and use the custom callback instead. Useful to do things like open a modal instead of expanding text when See More is pressed.
| `onSeeMore` | `func` | no | when a function is passed, will disable the default See More toggling and use the custom callback instead. Useful to do things like open a modal instead of expanding text when See More is pressed.
| `onSeeLess` | `func` | no | when a function is passed, will disable the default See Less toggling and use the custom callback instead. Useful to do things like open a modal instead of collapsing text when See Less is pressed.

Any additional props are passed down to underlying `Text` component.

Expand Down
16 changes: 14 additions & 2 deletions example/App.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import React from 'react';
import React, {useState} from 'react';
import {SafeAreaView, StyleSheet, View} from 'react-native';
import ReadMore from './src';

const App = () => {
const [collapsed, setCollapsed] = useState(true);

const toggle = () => {
setCollapsed(!collapsed);
};

return (
<SafeAreaView style={styles.safe}>
<View style={styles.root}>
<ReadMore numberOfLines={3} style={styles.textStyle}>
<ReadMore
numberOfLines={3}
style={styles.textStyle}
collapsed={collapsed}
onPress={toggle}
onSeeMore={() => setCollapsed(false)}
onSeeLess={() => setCollapsed(true)}>
{
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
}
Expand Down
94 changes: 79 additions & 15 deletions example/src/ReadMore.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@ import {
} from 'react-native';
import {getTextByChildren, insertAt, linesToCharacters} from './helper';

if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
let globalAnimationEnabled = false;
const enableGlobalLayoutAnimation = enable => {
if (!enable || globalAnimationEnabled) {
return;
}
}
globalAnimationEnabled = true;
console.log('enabling global animation');
if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
};

const readmoreAnimation = LayoutAnimation.create(
300,
Expand Down Expand Up @@ -52,8 +60,10 @@ const ReadMore = ({
debounceSeeMoreCalc,
onReady,
seeMoreContainerStyleSecondary,
onSeeMoreBlocked,
onSeeMore: onSeeMoreBlocked,
onSeeLess: onSeeLessBlocked,
debug,
collapsed: externalCollapsed,
...restProps
}) => {
const [additionalProps, setAdditionalProps] = useState({});
Expand Down Expand Up @@ -194,13 +204,47 @@ const ReadMore = ({
],
);

const toggle = useCallback(() => {
const onPressSeeLess = useCallback(() => {
if (collapsed) {
log('Already collapsed');
return;
}

if (onSeeLessBlocked) {
log('toggle blocked explicitly via prop onSeeLess');
return onSeeLessBlocked();
}

const isExternalCollapsedDefined = typeof externalCollapsed === 'boolean';
if (isExternalCollapsedDefined) {
log('toggle handled externally via collapsed prop');
return;
}

setCollapsed(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [collapsed, setCollapsed, onSeeLessBlocked, externalCollapsed]);

const onPressSeeMore = useCallback(() => {
if (!collapsed) {
log('Already expanded');
return;
}

if (onSeeMoreBlocked) {
onSeeMoreBlocked();
} else {
setCollapsed(prev => !prev);
log('toggle blocked explicitly via prop onSeeMore');
return onSeeMoreBlocked();
}
}, [setCollapsed, onSeeMoreBlocked]);

const isExternalCollapsedDefined = typeof externalCollapsed === 'boolean';
if (isExternalCollapsedDefined) {
log('toggle handled externally via collapsed prop');
return;
}

setCollapsed(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [collapsed, setCollapsed, onSeeMoreBlocked, externalCollapsed]);

const updateLineOfImpact = useCallback(
(_text = '', resetCollapsedChildren = true) => {
Expand Down Expand Up @@ -545,6 +589,22 @@ const ReadMore = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMeasured, isReady]);

useEffect(() => {
const isExternalCollapsedDefined = typeof externalCollapsed === 'boolean';
const collapsedStateDifferent = externalCollapsed !== collapsed;
if (isExternalCollapsedDefined && collapsedStateDifferent && isReady) {
log(
`Setting collapsed to ${externalCollapsed} extenrally via collapsed prop`,
);
setCollapsed(externalCollapsed);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [externalCollapsed, collapsed, isReady]);

useState(() => {
enableGlobalLayoutAnimation(animate);
}, [animate]);

return (
<View style={wrapperStyle}>
{/* text component to measure see if see more is applicable and get lines */}
Expand Down Expand Up @@ -615,7 +675,7 @@ const ReadMore = ({
<TextComponent
{...additionalProps}
{...restProps}
onPress={toggle}
onPress={onPressSeeLess}
style={seeLessStyle}>
{hiddenTextLinesWithSeeLess.length > lines.length ? '\n' : ' '}
{seeLessText}
Expand All @@ -632,7 +692,7 @@ const ReadMore = ({
key={`${isMeasured}-${hideEllipsis}`}
{...additionalProps}
{...restProps}
onPress={toggle}
onPress={onPressSeeMore}
style={[
style,
seeMoreTextHidingStyle,
Expand All @@ -644,7 +704,7 @@ const ReadMore = ({
<TextComponent
{...additionalProps}
{...restProps}
onPress={toggle}
onPress={onPressSeeMore}
style={[style, seeMoreStyle, seeMoreTextHidingStyle]}>
{seeMoreText}
</TextComponent>
Expand Down Expand Up @@ -729,8 +789,10 @@ ReadMore.propTypes = {
debounceSeeMoreCalc: PropTypes.number,
onReady: PropTypes.func,
seeMoreContainerStyleSecondary: PropTypes.object,
onSeeMoreBlocked: PropTypes.func,
onSeeMore: PropTypes.func,
onSeeLess: PropTypes.func,
debug: PropTypes.bool,
collapsed: PropTypes.bool,
};

ReadMore.defaultProps = {
Expand All @@ -755,8 +817,10 @@ ReadMore.defaultProps = {
}),
onReady: () => {},
seeMoreContainerStyleSecondary: {},
onSeeMoreBlocked: undefined,
onSeeMore: undefined,
onSeeLess: undefined,
debug: false,
collapsed: undefined,
};

export default memo(ReadMore);
4 changes: 3 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ export interface ReadMoreProps extends TextProps {
debounceSeeMoreCalc?: number;
onReady?: () => void;
seeMoreContainerStyleSecondary?: StyleProp<ViewStyle>;
onSeeMoreBlocked?: () => void;
onSeeMore?: () => void;
onSeeLess?: () => void;
debug?: boolean;
collapsed?: boolean;
}
declare const ReadMore: React.FC<ReadMoreProps>;
export default ReadMore;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fawazahmed/react-native-read-more",
"version": "2.3.7",
"version": "3.0.0",
"description": "A simple react native library to show large blocks of text in a condensed manner with the ability to collapse and expand.",
"main": "dist/index.js",
"types": "index.d.ts",
Expand Down