Skip to content

Commit 5d4e149

Browse files
committed
Merge branch 'master' into release
2 parents 32a999d + cf29b80 commit 5d4e149

37 files changed

+1255
-814
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,69 @@
11
import _ from 'lodash';
2-
import React, {useCallback} from 'react';
2+
import React, {useCallback, useState, useRef} from 'react';
33
import {StyleSheet} from 'react-native';
4-
import {SortableList, View, TouchableOpacity, Text, Icon, Assets, Colors} from 'react-native-ui-lib';
4+
import {SortableList, View, TouchableOpacity, Text, Icon, Assets, Colors, Button} from 'react-native-ui-lib';
55
import {renderHeader} from '../ExampleScreenPresenter';
66

77
interface Item {
88
originalIndex: number;
9+
id: string;
910
}
1011

1112
const data = _.times(30, index => {
1213
return {
13-
originalIndex: index
14+
originalIndex: index,
15+
id: `${index}`
1416
};
1517
});
1618

1719
const SortableListScreen = () => {
20+
const [items, setItems] = useState<Item[]>(data);
21+
const [selectedItems, setSelectedItems] = useState<Item[]>([]);
22+
const [removedItems, setRemovedItems] = useState<Item[]>([]);
23+
const orderedItems = useRef<Item[]>(data);
24+
25+
const toggleItemSelection = useCallback((item: Item) => {
26+
if (selectedItems.includes(item)) {
27+
setSelectedItems(selectedItems.filter(selectedItem => ![item.id].includes(selectedItem.id)));
28+
} else {
29+
setSelectedItems(selectedItems.concat(item));
30+
}
31+
}, [selectedItems, setSelectedItems]);
32+
33+
const addItem = useCallback(() => {
34+
if (removedItems.length > 0) {
35+
orderedItems.current = orderedItems.current.concat(removedItems[0]);
36+
setItems(orderedItems.current);
37+
setRemovedItems(removedItems.slice(1));
38+
}
39+
}, [removedItems, setItems, setRemovedItems]);
40+
41+
const removeSelectedItems = useCallback(() => {
42+
setRemovedItems(removedItems.concat(selectedItems));
43+
setSelectedItems([]);
44+
orderedItems.current = orderedItems.current.filter(item => !selectedItems.includes(item));
45+
setItems(orderedItems.current);
46+
}, [setRemovedItems, removedItems, selectedItems, setItems, setSelectedItems]);
47+
1848
const keyExtractor = useCallback((item: Item) => {
19-
return `${item.originalIndex}`;
49+
return `${item.id}`;
2050
}, []);
2151

2252
const onOrderChange = useCallback((newData: Item[]) => {
2353
console.log('New order:', newData);
54+
orderedItems.current = newData;
2455
}, []);
2556

2657
const renderItem = useCallback(({item, index: _index}: {item: Item; index: number}) => {
58+
const isSelected = selectedItems.includes(item);
2759
return (
2860
<TouchableOpacity
29-
style={styles.itemContainer}
30-
onPress={() => console.log('Original index is', item.originalIndex)}
61+
style={[styles.itemContainer, isSelected && styles.selectedItemContainer]}
62+
onPress={() => toggleItemSelection(item)}
3163
// overriding the BG color to anything other than white will cause Android's elevation to fail
3264
// backgroundColor={Colors.red30}
3365
centerV
34-
marginH-page
66+
paddingH-page
3567
>
3668
<View flex row spread centerV>
3769
<Icon source={Assets.icons.demo.drag} tintColor={Colors.$iconDisabled}/>
@@ -42,13 +74,17 @@ const SortableListScreen = () => {
4274
</View>
4375
</TouchableOpacity>
4476
);
45-
}, []);
77+
}, [selectedItems, toggleItemSelection]);
4678

4779
return (
4880
<View flex bg-$backgroundDefault>
4981
{renderHeader('Sortable List', {'margin-10': true})}
82+
<View row center marginB-s2>
83+
<Button label="Add Item" size={Button.sizes.xSmall} disabled={removedItems.length === 0} onPress={addItem}/>
84+
<Button label="Remove Items" size={Button.sizes.xSmall} disabled={selectedItems.length === 0} marginL-s3 onPress={removeSelectedItems}/>
85+
</View>
5086
<View flex useSafeArea>
51-
<SortableList data={data} renderItem={renderItem} keyExtractor={keyExtractor} onOrderChange={onOrderChange}/>
87+
<SortableList data={items} renderItem={renderItem} keyExtractor={keyExtractor} onOrderChange={onOrderChange}/>
5288
</View>
5389
</View>
5490
);
@@ -60,5 +96,9 @@ const styles = StyleSheet.create({
6096
height: 52,
6197
borderColor: Colors.$outlineDefault,
6298
borderBottomWidth: 1
99+
},
100+
selectedItemContainer: {
101+
borderLeftColor: Colors.$outlinePrimary,
102+
borderLeftWidth: 5
63103
}
64104
});

demo/src/screens/componentScreens/TimelineScreen.tsx

+16-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ const TimelineScreen = () => {
2424
setExpand(!expand);
2525
}, [expand]);
2626

27+
const renderExtraContent = () => {
28+
return (
29+
<View style={{flex: 1, marginTop: 10, backgroundColor: Colors.grey70}}>
30+
<Text>Lorem Ipsum is simply dummy text of the printing and typesetting industry.
31+
Lorem Ipsum is simply dummy text of the printing and typesetting industry</Text>
32+
</View>
33+
);
34+
};
35+
2736
const renderContent = (index = 0, anchorRef?: any) => {
2837
return (
2938
<Card padding-page>
@@ -32,8 +41,10 @@ const TimelineScreen = () => {
3241
</Text>
3342
<View marginT-5 padding-8 bg-grey70 br30>
3443
<Text>{contents[index]}</Text>
35-
<Button marginT-10 size={'small'} label={!expand ? 'Expand' : 'Close'} onPress={onPressExpand}/>
36-
{expand && <View style={{height: 100, marginTop: 10, backgroundColor: 'red'}}/>}
44+
<View right>
45+
<Button marginT-10 link size={'small'} label={!expand ? 'More info' : 'Close'} onPress={onPressExpand}/>
46+
</View>
47+
{expand && renderExtraContent()}
3748
</View>
3849
</Card>
3950
);
@@ -86,11 +97,11 @@ const TimelineScreen = () => {
8697
topLine={{state: Timeline.states.ERROR}}
8798
bottomLine={{
8899
type: Timeline.lineTypes.DASHED,
89-
color: Colors.orange40
100+
color: Colors.purple30
90101
}}
91102
point={{
92103
type: Timeline.pointTypes.OUTLINE,
93-
color: Colors.orange40,
104+
color: Colors.purple30,
94105
icon: Assets.icons.demo.camera
95106
}}
96107
>
@@ -99,7 +110,7 @@ const TimelineScreen = () => {
99110
<Timeline
100111
topLine={{
101112
type: Timeline.lineTypes.DASHED,
102-
color: Colors.orange40
113+
color: Colors.purple30
103114
}}
104115
bottomLine={{
105116
state: Timeline.states.NEXT,

lib/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "uilib-native",
3-
"version": "3.0.7",
3+
"version": "3.0.8",
44
"homepage": "https://github.com/wix/react-native-ui-lib",
55
"description": "uilib native components (separated from js components)",
66
"main": "components/index.js",

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
"jest": "^26.6.3",
8989
"metro-react-native-babel-preset": "^0.66.2",
9090
"mocha": "^5.0.0",
91+
"object-hash": "^3.0.0",
9192
"prettier-eslint": "12.0.0",
9293
"react": "17.0.2",
9394
"react-autobind": "^1.0.6",
+34-28
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
1-
import _ from 'lodash';
2-
import {fireEvent, RenderAPI} from '@testing-library/react-native';
3-
import {ReactTestInstance} from 'react-test-renderer';
4-
import {TextDriver} from '../text/Text.driver';
51
import {ImageDriver} from '../image/Image.driver';
2+
import {ComponentDriver, ComponentDriverArgs} from '../../testkit/Component.driver';
3+
import {TextDriver} from '../text/Text.driver';
4+
5+
/**
6+
* Please run clear after each test
7+
* */
8+
export class ButtonDriver extends ComponentDriver {
9+
private readonly labelDriver: TextDriver;
10+
private readonly iconDriver: ImageDriver;
11+
12+
constructor(componentDriverArgs: ComponentDriverArgs) {
13+
super(componentDriverArgs);
14+
15+
this.labelDriver = new TextDriver({...componentDriverArgs, testID: `${this.testID}.label`});
16+
this.iconDriver = new ImageDriver({...componentDriverArgs, testID: `${this.testID}.icon`});
17+
}
18+
19+
isPressable = async () => {
20+
if (this.exists()) {
21+
return typeof (await this.getElementProps()).onPress === 'function';
22+
} else {
23+
console.warn(`TextDriver: cannot click because testID:${this.testID} were not found`);
24+
return null;
25+
}
26+
}
27+
28+
// label
29+
getLabelRootElement = () => this.labelDriver.getElement();
30+
isLabelExists = () => this.labelDriver.exists();
31+
getLabelContent = () => this.labelDriver.getTextContent();
32+
// icon
33+
getIconElement = () => this.iconDriver.getElement();
34+
isIconExists = () => this.iconDriver.exists()
635

7-
export const ButtonDriver = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI; testID: string}) => {
8-
const button: ReactTestInstance | null = await wrapperComponent.queryByTestId(testID);
9-
const label = await TextDriver({wrapperComponent, testID: `${testID}.label`});
10-
const icon = await ImageDriver({wrapperComponent, testID: `${testID}.icon`});
11-
return {
12-
exists: () => !!button,
13-
getRootElement: () => button,
14-
isClickable: () => !_.get(button, 'props.accessibilityState.disabled'),
15-
click: () => {
16-
if (button) {
17-
fireEvent.press(button);
18-
} else {
19-
console.warn(`ButtonDriver: cannot click because testID:${testID} were not found`);
20-
}
21-
},
22-
// label
23-
getLabelRootElement: () => label.getRootElement(),
24-
isLabelExists: () => label.exists(),
25-
getLabelContent: () => label.getTextContent(),
26-
// icon
27-
getIconRootElement: () => icon.getRootElement(),
28-
isIconExists: () => icon.exists()
29-
};
30-
};
36+
}

src/components/button/__tests__/index.driver.spec.js

-144
This file was deleted.

0 commit comments

Comments
 (0)