ferns-ui 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Common.d.ts +7 -4
- package/dist/Common.js.map +1 -1
- package/dist/SegmentedControl.d.ts +2 -5
- package/dist/SegmentedControl.js +36 -6
- package/dist/SegmentedControl.js.map +1 -1
- package/dist/SplitPage.d.ts +9 -20
- package/dist/SplitPage.js +83 -40
- package/dist/SplitPage.js.map +1 -1
- package/package.json +1 -1
- package/src/Common.ts +6 -3
- package/src/SegmentedControl.tsx +74 -33
- package/src/SplitPage.tsx +147 -49
package/dist/Common.d.ts
CHANGED
|
@@ -319,13 +319,16 @@ export interface PillProps {
|
|
|
319
319
|
onClick: (enabled: boolean) => void;
|
|
320
320
|
}
|
|
321
321
|
export interface SegmentedControlProps {
|
|
322
|
-
items:
|
|
323
|
-
onChange
|
|
324
|
-
activeIndex: number;
|
|
322
|
+
items: string[];
|
|
323
|
+
onChange?: ({ activeIndex }: {
|
|
324
|
+
activeIndex: number | number[];
|
|
325
325
|
}) => void;
|
|
326
|
-
selectedItemIndex
|
|
326
|
+
selectedItemIndex?: number;
|
|
327
|
+
selectedItemIndexes?: number[];
|
|
327
328
|
responsive?: boolean;
|
|
328
329
|
size?: "md" | "lg";
|
|
330
|
+
multiselect?: boolean;
|
|
331
|
+
selectLimit?: number;
|
|
329
332
|
}
|
|
330
333
|
export interface FieldWithLabelsProps {
|
|
331
334
|
errorMessage?: string;
|
package/dist/Common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AAorDA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AAmBzB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAe,EAAE,EAAE;IAClD,OAAO;QACL,EAAE,EAAE,CAAC;QACL,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;KACP,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAI,GAAG,EAAE,EAAY,EAAE;IACtD,IAAI,QAAkB,CAAC;IACvB,IAAI,IAAI,GAAG,CAAC,EAAE;QACZ,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM,IAAI,IAAI,GAAG,EAAE,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM,IAAI,IAAI,GAAG,EAAE,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM,IAAI,IAAI,GAAG,EAAE,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM;QACL,QAAQ,GAAG,IAAI,CAAC;KACjB;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,OAAgE;IAC9F,OAAO,CAAC;QACN,SAAS,EAAE,QAAQ;QACnB,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,KAAK;QACZ,cAAc,EAAE,KAAK;QACrB,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;KACjB,CAAC,OAAO,CAAC,IAAI,MAAM,CAAU,CAAC;AACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AAorDA,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AAmBzB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAe,EAAE,EAAE;IAClD,OAAO;QACL,EAAE,EAAE,CAAC;QACL,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;KACP,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAI,GAAG,EAAE,EAAY,EAAE;IACtD,IAAI,QAAkB,CAAC;IACvB,IAAI,IAAI,GAAG,CAAC,EAAE;QACZ,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM,IAAI,IAAI,GAAG,EAAE,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM,IAAI,IAAI,GAAG,EAAE,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM,IAAI,IAAI,GAAG,EAAE,EAAE;QACpB,QAAQ,GAAG,IAAI,CAAC;KACjB;SAAM;QACL,QAAQ,GAAG,IAAI,CAAC;KACjB;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,OAAgE;IAC9F,OAAO,CAAC;QACN,SAAS,EAAE,QAAQ;QACnB,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,KAAK;QACZ,cAAc,EAAE,KAAK;QACrB,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,MAAM;KACjB,CAAC,OAAO,CAAC,IAAI,MAAM,CAAU,CAAC;AACjC,CAAC;AA63BD,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,OAAO,CACL,OAAO;QACP,OAAO,CAAC,KAAK;QACb,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CACrF,CAAC;AACJ,CAAC"}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react" />
|
|
2
2
|
import { SegmentedControlProps } from "./Common";
|
|
3
|
-
export declare
|
|
4
|
-
renderItem(item: string | React.ReactNode): JSX.Element;
|
|
5
|
-
render(): JSX.Element;
|
|
6
|
-
}
|
|
3
|
+
export declare const SegmentedControl: ({ items, onChange, selectedItemIndexes, selectedItemIndex, multiselect, selectLimit, }: SegmentedControlProps) => JSX.Element | null;
|
package/dist/SegmentedControl.js
CHANGED
|
@@ -1,18 +1,48 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box } from "./Box";
|
|
3
3
|
import { Text } from "./Text";
|
|
4
|
-
export
|
|
5
|
-
renderItem(item) {
|
|
4
|
+
export const SegmentedControl = ({ items, onChange = () => { }, selectedItemIndexes = undefined, selectedItemIndex = undefined, multiselect = false, selectLimit = 1, }) => {
|
|
5
|
+
const renderItem = (item) => {
|
|
6
6
|
return React.createElement(Text, { weight: "bold" }, item);
|
|
7
7
|
// if (typeof item === "string") {
|
|
8
8
|
// return <Text weight="bold">{item}</Text>;
|
|
9
9
|
// } else {
|
|
10
10
|
// return item;
|
|
11
11
|
// }
|
|
12
|
+
};
|
|
13
|
+
if (selectedItemIndex === undefined && selectedItemIndexes === undefined) {
|
|
14
|
+
console.warn("One of the following must be defined: selectedItemIndex, selectedItemIndexes");
|
|
15
|
+
return null;
|
|
12
16
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
if (!multiselect && (selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.length) && (selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.length) > 1) {
|
|
18
|
+
console.warn("Muliple selections not allowed without multiselect flag");
|
|
19
|
+
return null;
|
|
16
20
|
}
|
|
17
|
-
|
|
21
|
+
if ((selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.length) && (selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.length) > selectLimit) {
|
|
22
|
+
console.warn("The number of selected items exceeds the limit");
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const isTabActive = (index) => {
|
|
26
|
+
return selectedItemIndex === index || (selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.includes(index))
|
|
27
|
+
? "white"
|
|
28
|
+
: "lightGray";
|
|
29
|
+
};
|
|
30
|
+
return (React.createElement(Box, { color: "lightGray", direction: "row", display: "flex", height: 40, justifyContent: "between", padding: 1, rounding: 3, width: "100%" }, items.map((item, index) => (React.createElement(Box, { key: index, color: isTabActive(index), height: "100%", paddingX: 2, rounding: 3, width: `${100 / items.length}%` },
|
|
31
|
+
React.createElement(Box, { alignItems: "center", display: "flex", height: "100%", justifyContent: "center", width: "100%", onClick: () => {
|
|
32
|
+
if (multiselect) {
|
|
33
|
+
if (selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.includes(index)) {
|
|
34
|
+
onChange({ activeIndex: selectedItemIndexes.filter((i) => i !== index) });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const reversed = selectedItemIndexes === null || selectedItemIndexes === void 0 ? void 0 : selectedItemIndexes.reverse();
|
|
38
|
+
reversed === null || reversed === void 0 ? void 0 : reversed.splice(1, 1);
|
|
39
|
+
reversed === null || reversed === void 0 ? void 0 : reversed.push(index);
|
|
40
|
+
onChange({ activeIndex: reversed });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
onChange({ activeIndex: index });
|
|
45
|
+
}
|
|
46
|
+
} }, renderItem(item)))))));
|
|
47
|
+
};
|
|
18
48
|
//# sourceMappingURL=SegmentedControl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../src/SegmentedControl.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;AAE5B,MAAM,
|
|
1
|
+
{"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../src/SegmentedControl.tsx"],"names":[],"mappings":"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"}
|
package/dist/SplitPage.d.ts
CHANGED
|
@@ -1,31 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ReactChild, ReactElement } from "react";
|
|
2
2
|
import { ListRenderItemInfo } from "react-native";
|
|
3
3
|
import { Color } from "./Common";
|
|
4
4
|
interface SplitPageProps {
|
|
5
|
-
|
|
5
|
+
children?: ReactChild | ReactChild[] | null;
|
|
6
|
+
tabs?: string[];
|
|
7
|
+
navigation?: any;
|
|
6
8
|
loading?: boolean;
|
|
7
9
|
color?: Color;
|
|
8
10
|
keyboardOffset?: number;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
renderListViewHeader?: () => React.ReactElement | null;
|
|
13
|
-
renderContent: (index?: number) => React.ReactElement | null;
|
|
11
|
+
renderListViewItem: (itemInfo: ListRenderItemInfo<any>) => ReactElement | null;
|
|
12
|
+
renderListViewHeader?: () => ReactElement | null;
|
|
13
|
+
renderContent?: (index?: number) => ReactElement | ReactElement[] | null;
|
|
14
14
|
listViewData: any[];
|
|
15
15
|
listViewExtraData?: any;
|
|
16
16
|
listViewWidth?: number;
|
|
17
|
+
renderChild?: () => ReactChild;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
-
selectedId?: number;
|
|
20
|
-
}
|
|
21
|
-
export declare class SplitPage extends React.Component<SplitPageProps, SplitPageState> {
|
|
22
|
-
state: {
|
|
23
|
-
selectedId: undefined;
|
|
24
|
-
};
|
|
25
|
-
actionSheetRef: React.RefObject<any>;
|
|
26
|
-
renderItem: (itemInfo: ListRenderItemInfo<any>) => JSX.Element;
|
|
27
|
-
renderList: () => JSX.Element | null;
|
|
28
|
-
renderListContent: () => JSX.Element;
|
|
29
|
-
render(): JSX.Element;
|
|
30
|
-
}
|
|
19
|
+
export declare const SplitPage: ({ children, tabs, loading, color, keyboardOffset, renderListViewItem, renderListViewHeader, renderContent, listViewData, listViewExtraData, listViewWidth, }: SplitPageProps) => JSX.Element | null;
|
|
31
20
|
export {};
|
package/dist/SplitPage.js
CHANGED
|
@@ -1,51 +1,94 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { View } from "react-native";
|
|
1
|
+
import React, { Children, useState } from "react";
|
|
2
|
+
import { ScrollView, View } from "react-native";
|
|
3
3
|
import { Box } from "./Box";
|
|
4
|
+
import { SPACING } from "./Common";
|
|
4
5
|
import { FlatList } from "./FlatList";
|
|
5
6
|
import { IconButton } from "./IconButton";
|
|
6
7
|
import { mediaQueryLargerThan } from "./MediaQuery";
|
|
8
|
+
import { SegmentedControl } from "./SegmentedControl";
|
|
7
9
|
import { Spinner } from "./Spinner";
|
|
8
10
|
import { Unifier } from "./Unifier";
|
|
9
11
|
// A component for rendering a list on one side and a details view on the right for large screens,
|
|
10
12
|
// and a scrollable list where clicking an item takes you the details view.
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
this.setState({ selectedId: itemInfo.index });
|
|
19
|
-
} }, this.props.renderListViewItem(itemInfo)));
|
|
20
|
-
};
|
|
21
|
-
this.renderList = () => {
|
|
22
|
-
var _a, _b;
|
|
23
|
-
if (!mediaQueryLargerThan("sm") && this.state.selectedId) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
return (React.createElement(View, { style: {
|
|
27
|
-
width: mediaQueryLargerThan("sm") ? (_a = this.props.listViewWidth) !== null && _a !== void 0 ? _a : 300 : "100%",
|
|
28
|
-
maxWidth: mediaQueryLargerThan("sm") ? (_b = this.props.listViewWidth) !== null && _b !== void 0 ? _b : 300 : "100%",
|
|
29
|
-
flexGrow: 1,
|
|
30
|
-
flexShrink: 0,
|
|
31
|
-
display: "flex",
|
|
32
|
-
flexDirection: "column",
|
|
33
|
-
} },
|
|
34
|
-
this.props.renderListViewHeader && this.props.renderListViewHeader(),
|
|
35
|
-
React.createElement(FlatList, { data: this.props.listViewData, extraData: this.props.listViewExtraData, keyExtractor: (item) => item.id, renderItem: this.renderItem })));
|
|
36
|
-
};
|
|
37
|
-
this.renderListContent = () => {
|
|
38
|
-
return (React.createElement(Box, { flex: "grow", padding: 2 },
|
|
39
|
-
!mediaQueryLargerThan("sm") && (React.createElement(Box, { width: "100%" },
|
|
40
|
-
React.createElement(IconButton, { accessibilityLabel: "close", icon: "times", iconColor: "darkGray", onClick: () => this.setState({ selectedId: undefined }) }))),
|
|
41
|
-
this.props.renderContent(this.state.selectedId)));
|
|
42
|
-
};
|
|
13
|
+
export const SplitPage = ({ children, tabs = [], loading = false, color, keyboardOffset, renderListViewItem, renderListViewHeader, renderContent, listViewData, listViewExtraData, listViewWidth, }) => {
|
|
14
|
+
const [selectedId, setSelectedId] = useState(undefined);
|
|
15
|
+
const [activeTabs, setActiveTabs] = useState(tabs.length > 2 ? [0, 1] : []);
|
|
16
|
+
const elementArray = Children.toArray(children);
|
|
17
|
+
if (!children && !renderContent) {
|
|
18
|
+
console.warn("A child node is required");
|
|
19
|
+
return null;
|
|
43
20
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
this.renderList(),
|
|
48
|
-
this.renderListContent()));
|
|
21
|
+
if (Children.count(children) > 2 && Children.count(children) !== tabs.length) {
|
|
22
|
+
console.warn("There must be a tab for each child");
|
|
23
|
+
return null;
|
|
49
24
|
}
|
|
50
|
-
|
|
25
|
+
const renderItem = (itemInfo) => {
|
|
26
|
+
return (React.createElement(Box, { onClick: () => {
|
|
27
|
+
setSelectedId(itemInfo.index);
|
|
28
|
+
} }, renderListViewItem(itemInfo)));
|
|
29
|
+
};
|
|
30
|
+
const renderList = () => {
|
|
31
|
+
if (!mediaQueryLargerThan("sm") && selectedId) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return (React.createElement(View, { style: {
|
|
35
|
+
width: mediaQueryLargerThan("sm") ? listViewWidth !== null && listViewWidth !== void 0 ? listViewWidth : 300 : "100%",
|
|
36
|
+
maxWidth: mediaQueryLargerThan("sm") ? listViewWidth !== null && listViewWidth !== void 0 ? listViewWidth : 300 : "100%",
|
|
37
|
+
flexGrow: 1,
|
|
38
|
+
flexShrink: 0,
|
|
39
|
+
display: "flex",
|
|
40
|
+
paddingTop: "12px",
|
|
41
|
+
paddingBottom: "12px",
|
|
42
|
+
flexDirection: "column",
|
|
43
|
+
} },
|
|
44
|
+
renderListViewHeader && renderListViewHeader(),
|
|
45
|
+
React.createElement(FlatList, { data: listViewData, extraData: listViewExtraData, keyExtractor: (item) => item.id, renderItem: renderItem })));
|
|
46
|
+
};
|
|
47
|
+
const renderListContent = () => {
|
|
48
|
+
return (React.createElement(Box, { flex: "grow", padding: 2 },
|
|
49
|
+
!mediaQueryLargerThan("sm") && (React.createElement(Box, { width: "100%" },
|
|
50
|
+
React.createElement(IconButton, { accessibilityLabel: "close", icon: "times", iconColor: "darkGray", onClick: () => setSelectedId(undefined) }))),
|
|
51
|
+
renderContent && renderContent(selectedId)));
|
|
52
|
+
};
|
|
53
|
+
const renderChildrenContent = () => {
|
|
54
|
+
if (Array.isArray(children) && children.length > 2) {
|
|
55
|
+
return (React.createElement(View, { style: {
|
|
56
|
+
flex: 1,
|
|
57
|
+
width: "100%",
|
|
58
|
+
height: "100%",
|
|
59
|
+
alignItems: "center",
|
|
60
|
+
} },
|
|
61
|
+
React.createElement(Box, { paddingX: 4, paddingY: 2, width: "100%" },
|
|
62
|
+
React.createElement(SegmentedControl, { items: tabs, multiselect: true, selectLimit: tabs.length, selectedItemIndexes: activeTabs, onChange: (index) => {
|
|
63
|
+
setActiveTabs([...index.activeIndex]);
|
|
64
|
+
} })),
|
|
65
|
+
React.createElement(Box, { direction: "row", flex: "grow", height: "100%", paddingX: 2, width: activeTabs.length > 1 ? "100%" : "60%" }, activeTabs.map((tabIndex) => {
|
|
66
|
+
return (React.createElement(ScrollView, { key: tabIndex, contentContainerStyle: {
|
|
67
|
+
flex: 1,
|
|
68
|
+
}, style: {
|
|
69
|
+
flex: 1,
|
|
70
|
+
width: "60%",
|
|
71
|
+
padding: 3 * SPACING,
|
|
72
|
+
height: "100%",
|
|
73
|
+
} }, elementArray[tabIndex]));
|
|
74
|
+
}))));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return (React.createElement(Box, { alignItems: "center", direction: "row", flex: "grow", justifyContent: "center", paddingX: 2 }, elementArray.map((element, index) => {
|
|
78
|
+
return (React.createElement(ScrollView, { key: index, contentContainerStyle: {
|
|
79
|
+
flex: 1,
|
|
80
|
+
}, style: {
|
|
81
|
+
flex: 1,
|
|
82
|
+
width: "60%",
|
|
83
|
+
padding: 3 * SPACING,
|
|
84
|
+
height: "100%",
|
|
85
|
+
} }, element));
|
|
86
|
+
})));
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return (React.createElement(Box, { avoidKeyboard: true, color: color || "lightGray", direction: "row", display: "flex", flex: "grow", height: "100%", keyboardOffset: keyboardOffset, padding: 2, width: "100%" },
|
|
90
|
+
loading === true && React.createElement(Spinner, { color: Unifier.theme.darkGray, size: "md" }),
|
|
91
|
+
renderList(),
|
|
92
|
+
renderContent ? renderListContent() : renderChildrenContent()));
|
|
93
|
+
};
|
|
51
94
|
//# sourceMappingURL=SplitPage.js.map
|
package/dist/SplitPage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SplitPage.js","sourceRoot":"","sources":["../src/SplitPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SplitPage.js","sourceRoot":"","sources":["../src/SplitPage.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/Common.ts
CHANGED
|
@@ -2001,11 +2001,14 @@ export interface PillProps {
|
|
|
2001
2001
|
}
|
|
2002
2002
|
|
|
2003
2003
|
export interface SegmentedControlProps {
|
|
2004
|
-
items:
|
|
2005
|
-
onChange
|
|
2006
|
-
selectedItemIndex
|
|
2004
|
+
items: string[];
|
|
2005
|
+
onChange?: ({activeIndex}: {activeIndex: number | number[]}) => void;
|
|
2006
|
+
selectedItemIndex?: number;
|
|
2007
|
+
selectedItemIndexes?: number[];
|
|
2007
2008
|
responsive?: boolean;
|
|
2008
2009
|
size?: "md" | "lg"; // defaults to md
|
|
2010
|
+
multiselect?: boolean;
|
|
2011
|
+
selectLimit?: number;
|
|
2009
2012
|
}
|
|
2010
2013
|
|
|
2011
2014
|
// Shared props for fields with labels, subtext, and error messages.
|
package/src/SegmentedControl.tsx
CHANGED
|
@@ -4,48 +4,89 @@ import {Box} from "./Box";
|
|
|
4
4
|
import {SegmentedControlProps} from "./Common";
|
|
5
5
|
import {Text} from "./Text";
|
|
6
6
|
|
|
7
|
-
export
|
|
8
|
-
|
|
7
|
+
export const SegmentedControl = ({
|
|
8
|
+
items,
|
|
9
|
+
onChange = () => {},
|
|
10
|
+
selectedItemIndexes = undefined,
|
|
11
|
+
selectedItemIndex = undefined,
|
|
12
|
+
multiselect = false,
|
|
13
|
+
selectLimit = 1,
|
|
14
|
+
}: SegmentedControlProps) => {
|
|
15
|
+
const renderItem = (item: string | React.ReactNode) => {
|
|
9
16
|
return <Text weight="bold">{item}</Text>;
|
|
10
17
|
// if (typeof item === "string") {
|
|
11
18
|
// return <Text weight="bold">{item}</Text>;
|
|
12
19
|
// } else {
|
|
13
20
|
// return item;
|
|
14
21
|
// }
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (selectedItemIndex === undefined && selectedItemIndexes === undefined) {
|
|
25
|
+
console.warn("One of the following must be defined: selectedItemIndex, selectedItemIndexes");
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!multiselect && selectedItemIndexes?.length && selectedItemIndexes?.length > 1) {
|
|
30
|
+
console.warn("Muliple selections not allowed without multiselect flag");
|
|
31
|
+
return null;
|
|
15
32
|
}
|
|
16
33
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
if (selectedItemIndexes?.length && selectedItemIndexes?.length > selectLimit) {
|
|
35
|
+
console.warn("The number of selected items exceeds the limit");
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const isTabActive = (index: any) => {
|
|
40
|
+
return selectedItemIndex === index || selectedItemIndexes?.includes(index)
|
|
41
|
+
? "white"
|
|
42
|
+
: "lightGray";
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Box
|
|
47
|
+
color="lightGray"
|
|
48
|
+
direction="row"
|
|
49
|
+
display="flex"
|
|
50
|
+
height={40}
|
|
51
|
+
justifyContent="between"
|
|
52
|
+
padding={1}
|
|
53
|
+
rounding={3}
|
|
54
|
+
width="100%"
|
|
55
|
+
>
|
|
56
|
+
{items.map((item, index) => (
|
|
57
|
+
<Box
|
|
58
|
+
key={index}
|
|
59
|
+
color={isTabActive(index)}
|
|
60
|
+
height="100%"
|
|
61
|
+
paddingX={2}
|
|
62
|
+
rounding={3}
|
|
63
|
+
width={`${100 / items.length}%`}
|
|
64
|
+
>
|
|
29
65
|
<Box
|
|
30
|
-
|
|
31
|
-
|
|
66
|
+
alignItems="center"
|
|
67
|
+
display="flex"
|
|
32
68
|
height="100%"
|
|
33
|
-
|
|
34
|
-
width=
|
|
69
|
+
justifyContent="center"
|
|
70
|
+
width="100%"
|
|
71
|
+
onClick={() => {
|
|
72
|
+
if (multiselect) {
|
|
73
|
+
if (selectedItemIndexes?.includes(index)) {
|
|
74
|
+
onChange({activeIndex: selectedItemIndexes.filter((i) => i !== index)});
|
|
75
|
+
} else {
|
|
76
|
+
const reversed = selectedItemIndexes?.reverse();
|
|
77
|
+
reversed?.splice(1, 1);
|
|
78
|
+
reversed?.push(index);
|
|
79
|
+
onChange({activeIndex: reversed as number[]});
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
onChange({activeIndex: index});
|
|
83
|
+
}
|
|
84
|
+
}}
|
|
35
85
|
>
|
|
36
|
-
|
|
37
|
-
alignItems="center"
|
|
38
|
-
display="flex"
|
|
39
|
-
height="100%"
|
|
40
|
-
justifyContent="center"
|
|
41
|
-
width="100%"
|
|
42
|
-
onClick={() => this.props.onChange({activeIndex: index})}
|
|
43
|
-
>
|
|
44
|
-
{this.renderItem(item)}
|
|
45
|
-
</Box>
|
|
86
|
+
{renderItem(item)}
|
|
46
87
|
</Box>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
88
|
+
</Box>
|
|
89
|
+
))}
|
|
90
|
+
</Box>
|
|
91
|
+
);
|
|
92
|
+
};
|
package/src/SplitPage.tsx
CHANGED
|
@@ -1,80 +1,103 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import {ListRenderItemInfo, View} from "react-native";
|
|
1
|
+
import React, {Children, ReactChild, ReactElement, useState} from "react";
|
|
2
|
+
import {ListRenderItemInfo, ScrollView, View} from "react-native";
|
|
3
3
|
|
|
4
4
|
import {Box} from "./Box";
|
|
5
|
-
import {Color} from "./Common";
|
|
5
|
+
import {Color, SPACING} from "./Common";
|
|
6
6
|
import {FlatList} from "./FlatList";
|
|
7
7
|
import {IconButton} from "./IconButton";
|
|
8
8
|
import {mediaQueryLargerThan} from "./MediaQuery";
|
|
9
|
+
import {SegmentedControl} from "./SegmentedControl";
|
|
9
10
|
import {Spinner} from "./Spinner";
|
|
10
11
|
import {Unifier} from "./Unifier";
|
|
11
12
|
|
|
12
13
|
interface SplitPageProps {
|
|
14
|
+
children?: ReactChild | ReactChild[] | null;
|
|
15
|
+
tabs?: string[];
|
|
13
16
|
// TODO: figure out navigation
|
|
14
|
-
navigation
|
|
17
|
+
navigation?: any;
|
|
15
18
|
loading?: boolean;
|
|
16
19
|
color?: Color;
|
|
17
20
|
keyboardOffset?: number;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
renderListViewHeader?: () => React.ReactElement | null;
|
|
22
|
-
renderContent: (index?: number) => React.ReactElement | null;
|
|
21
|
+
renderListViewItem: (itemInfo: ListRenderItemInfo<any>) => ReactElement | null;
|
|
22
|
+
renderListViewHeader?: () => ReactElement | null;
|
|
23
|
+
renderContent?: (index?: number) => ReactElement | ReactElement[] | null;
|
|
23
24
|
listViewData: any[];
|
|
24
25
|
listViewExtraData?: any;
|
|
25
26
|
listViewWidth?: number;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
interface SplitPageState {
|
|
29
|
-
selectedId?: number;
|
|
27
|
+
renderChild?: () => ReactChild;
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
// A component for rendering a list on one side and a details view on the right for large screens,
|
|
33
31
|
// and a scrollable list where clicking an item takes you the details view.
|
|
34
|
-
export
|
|
35
|
-
|
|
32
|
+
export const SplitPage = ({
|
|
33
|
+
children,
|
|
34
|
+
tabs = [],
|
|
35
|
+
loading = false,
|
|
36
|
+
color,
|
|
37
|
+
keyboardOffset,
|
|
38
|
+
renderListViewItem,
|
|
39
|
+
renderListViewHeader,
|
|
40
|
+
renderContent,
|
|
41
|
+
listViewData,
|
|
42
|
+
listViewExtraData,
|
|
43
|
+
listViewWidth,
|
|
44
|
+
}: SplitPageProps) => {
|
|
45
|
+
const [selectedId, setSelectedId] = useState<number | undefined>(undefined);
|
|
46
|
+
const [activeTabs, setActiveTabs] = useState<number[]>(tabs.length > 2 ? [0, 1] : []);
|
|
47
|
+
|
|
48
|
+
const elementArray = Children.toArray(children);
|
|
49
|
+
|
|
50
|
+
if (!children && !renderContent) {
|
|
51
|
+
console.warn("A child node is required");
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
if (Children.count(children) > 2 && Children.count(children) !== tabs.length) {
|
|
56
|
+
console.warn("There must be a tab for each child");
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
38
59
|
|
|
39
|
-
renderItem = (itemInfo: ListRenderItemInfo<any>) => {
|
|
60
|
+
const renderItem = (itemInfo: ListRenderItemInfo<any>) => {
|
|
40
61
|
return (
|
|
41
62
|
<Box
|
|
42
63
|
onClick={() => {
|
|
43
|
-
|
|
64
|
+
setSelectedId(itemInfo.index);
|
|
44
65
|
}}
|
|
45
66
|
>
|
|
46
|
-
{
|
|
67
|
+
{renderListViewItem(itemInfo)}
|
|
47
68
|
</Box>
|
|
48
69
|
);
|
|
49
70
|
};
|
|
50
71
|
|
|
51
|
-
renderList = () => {
|
|
52
|
-
if (!mediaQueryLargerThan("sm") &&
|
|
72
|
+
const renderList = () => {
|
|
73
|
+
if (!mediaQueryLargerThan("sm") && selectedId) {
|
|
53
74
|
return null;
|
|
54
75
|
}
|
|
55
76
|
return (
|
|
56
77
|
<View
|
|
57
78
|
style={{
|
|
58
|
-
width: mediaQueryLargerThan("sm") ?
|
|
59
|
-
maxWidth: mediaQueryLargerThan("sm") ?
|
|
79
|
+
width: mediaQueryLargerThan("sm") ? listViewWidth ?? 300 : "100%",
|
|
80
|
+
maxWidth: mediaQueryLargerThan("sm") ? listViewWidth ?? 300 : "100%",
|
|
60
81
|
flexGrow: 1,
|
|
61
82
|
flexShrink: 0,
|
|
62
83
|
display: "flex",
|
|
84
|
+
paddingTop: "12px",
|
|
85
|
+
paddingBottom: "12px",
|
|
63
86
|
flexDirection: "column",
|
|
64
87
|
}}
|
|
65
88
|
>
|
|
66
|
-
{
|
|
89
|
+
{renderListViewHeader && renderListViewHeader()}
|
|
67
90
|
<FlatList
|
|
68
|
-
data={
|
|
69
|
-
extraData={
|
|
91
|
+
data={listViewData}
|
|
92
|
+
extraData={listViewExtraData}
|
|
70
93
|
keyExtractor={(item) => item.id}
|
|
71
|
-
renderItem={
|
|
94
|
+
renderItem={renderItem}
|
|
72
95
|
/>
|
|
73
96
|
</View>
|
|
74
97
|
);
|
|
75
98
|
};
|
|
76
99
|
|
|
77
|
-
renderListContent = () => {
|
|
100
|
+
const renderListContent = () => {
|
|
78
101
|
return (
|
|
79
102
|
<Box flex="grow" padding={2}>
|
|
80
103
|
{!mediaQueryLargerThan("sm") && (
|
|
@@ -83,31 +106,106 @@ export class SplitPage extends React.Component<SplitPageProps, SplitPageState> {
|
|
|
83
106
|
accessibilityLabel="close"
|
|
84
107
|
icon="times"
|
|
85
108
|
iconColor="darkGray"
|
|
86
|
-
onClick={() =>
|
|
109
|
+
onClick={() => setSelectedId(undefined)}
|
|
87
110
|
/>
|
|
88
111
|
</Box>
|
|
89
112
|
)}
|
|
90
|
-
{
|
|
113
|
+
{renderContent && renderContent(selectedId)}
|
|
91
114
|
</Box>
|
|
92
115
|
);
|
|
93
116
|
};
|
|
94
117
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
const renderChildrenContent = () => {
|
|
119
|
+
if (Array.isArray(children) && children.length > 2) {
|
|
120
|
+
return (
|
|
121
|
+
<View
|
|
122
|
+
style={{
|
|
123
|
+
flex: 1,
|
|
124
|
+
width: "100%",
|
|
125
|
+
height: "100%",
|
|
126
|
+
alignItems: "center",
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<Box paddingX={4} paddingY={2} width="100%">
|
|
130
|
+
<SegmentedControl
|
|
131
|
+
items={tabs}
|
|
132
|
+
multiselect
|
|
133
|
+
selectLimit={tabs.length}
|
|
134
|
+
selectedItemIndexes={activeTabs}
|
|
135
|
+
onChange={(index) => {
|
|
136
|
+
setActiveTabs([...(index.activeIndex as number[])]);
|
|
137
|
+
}}
|
|
138
|
+
/>
|
|
139
|
+
</Box>
|
|
140
|
+
<Box
|
|
141
|
+
direction="row"
|
|
142
|
+
flex="grow"
|
|
143
|
+
height="100%"
|
|
144
|
+
paddingX={2}
|
|
145
|
+
width={activeTabs.length > 1 ? "100%" : "60%"}
|
|
146
|
+
>
|
|
147
|
+
{activeTabs.map((tabIndex) => {
|
|
148
|
+
return (
|
|
149
|
+
<ScrollView
|
|
150
|
+
key={tabIndex}
|
|
151
|
+
contentContainerStyle={{
|
|
152
|
+
flex: 1,
|
|
153
|
+
}}
|
|
154
|
+
style={{
|
|
155
|
+
flex: 1,
|
|
156
|
+
width: "60%",
|
|
157
|
+
padding: 3 * SPACING,
|
|
158
|
+
height: "100%",
|
|
159
|
+
}}
|
|
160
|
+
>
|
|
161
|
+
{elementArray[tabIndex]}
|
|
162
|
+
</ScrollView>
|
|
163
|
+
);
|
|
164
|
+
})}
|
|
165
|
+
</Box>
|
|
166
|
+
</View>
|
|
167
|
+
);
|
|
168
|
+
} else {
|
|
169
|
+
return (
|
|
170
|
+
<Box alignItems="center" direction="row" flex="grow" justifyContent="center" paddingX={2}>
|
|
171
|
+
{elementArray.map((element, index) => {
|
|
172
|
+
return (
|
|
173
|
+
<ScrollView
|
|
174
|
+
key={index}
|
|
175
|
+
contentContainerStyle={{
|
|
176
|
+
flex: 1,
|
|
177
|
+
}}
|
|
178
|
+
style={{
|
|
179
|
+
flex: 1,
|
|
180
|
+
width: "60%",
|
|
181
|
+
padding: 3 * SPACING,
|
|
182
|
+
height: "100%",
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
{element}
|
|
186
|
+
</ScrollView>
|
|
187
|
+
);
|
|
188
|
+
})}
|
|
189
|
+
</Box>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<Box
|
|
196
|
+
avoidKeyboard
|
|
197
|
+
color={color || "lightGray"}
|
|
198
|
+
direction="row"
|
|
199
|
+
display="flex"
|
|
200
|
+
flex="grow"
|
|
201
|
+
height="100%"
|
|
202
|
+
keyboardOffset={keyboardOffset}
|
|
203
|
+
padding={2}
|
|
204
|
+
width="100%"
|
|
205
|
+
>
|
|
206
|
+
{loading === true && <Spinner color={Unifier.theme.darkGray as any} size="md" />}
|
|
207
|
+
{renderList()}
|
|
208
|
+
{renderContent ? renderListContent() : renderChildrenContent()}
|
|
209
|
+
</Box>
|
|
210
|
+
);
|
|
211
|
+
};
|