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 CHANGED
@@ -319,13 +319,16 @@ export interface PillProps {
319
319
  onClick: (enabled: boolean) => void;
320
320
  }
321
321
  export interface SegmentedControlProps {
322
- items: (string | React.ReactNode)[];
323
- onChange: ({ activeIndex }: {
324
- activeIndex: number;
322
+ items: string[];
323
+ onChange?: ({ activeIndex }: {
324
+ activeIndex: number | number[];
325
325
  }) => void;
326
- selectedItemIndex: number;
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;
@@ -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;AA03BD,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
+ {"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
- import React from "react";
1
+ /// <reference types="react" />
2
2
  import { SegmentedControlProps } from "./Common";
3
- export declare class SegmentedControl extends React.Component<SegmentedControlProps, {}> {
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;
@@ -1,18 +1,48 @@
1
1
  import React from "react";
2
2
  import { Box } from "./Box";
3
3
  import { Text } from "./Text";
4
- export class SegmentedControl extends React.Component {
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
- render() {
14
- return (React.createElement(Box, { color: "lightGray", direction: "row", display: "flex", height: 40, padding: 1, rounding: 3, width: "100%" }, this.props.items.map((item, index) => (React.createElement(Box, { key: index, color: this.props.selectedItemIndex === index ? "white" : "lightGray", height: "100%", rounding: 3, width: `${100 / this.props.items.length}%` },
15
- React.createElement(Box, { alignItems: "center", display: "flex", height: "100%", justifyContent: "center", width: "100%", onClick: () => this.props.onChange({ activeIndex: index }) }, this.renderItem(item)))))));
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,OAAO,gBAAiB,SAAQ,KAAK,CAAC,SAAoC;IAC9E,UAAU,CAAC,IAA8B;QACvC,OAAO,oBAAC,IAAI,IAAC,MAAM,EAAC,MAAM,IAAE,IAAI,CAAQ,CAAC;QACzC,kCAAkC;QAClC,8CAA8C;QAC9C,WAAW;QACX,iBAAiB;QACjB,IAAI;IACN,CAAC;IAED,MAAM;QACJ,OAAO,CACL,oBAAC,GAAG,IACF,KAAK,EAAC,WAAW,EACjB,SAAS,EAAC,KAAK,EACf,OAAO,EAAC,MAAM,EACd,MAAM,EAAE,EAAE,EACV,OAAO,EAAE,CAAC,EACV,QAAQ,EAAE,CAAC,EACX,KAAK,EAAC,MAAM,IAEX,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CACrC,oBAAC,GAAG,IACF,GAAG,EAAE,KAAK,EACV,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,iBAAiB,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EACrE,MAAM,EAAC,MAAM,EACb,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG;YAE1C,oBAAC,GAAG,IACF,UAAU,EAAC,QAAQ,EACnB,OAAO,EAAC,MAAM,EACd,MAAM,EAAC,MAAM,EACb,cAAc,EAAC,QAAQ,EACvB,KAAK,EAAC,MAAM,EACZ,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAC,WAAW,EAAE,KAAK,EAAC,CAAC,IAEvD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAClB,CACF,CACP,CAAC,CACE,CACP,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../src/SegmentedControl.tsx"],"names":[],"mappings":"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"}
@@ -1,31 +1,20 @@
1
- import React from "react";
1
+ import { ReactChild, ReactElement } from "react";
2
2
  import { ListRenderItemInfo } from "react-native";
3
3
  import { Color } from "./Common";
4
4
  interface SplitPageProps {
5
- navigation: any;
5
+ children?: ReactChild | ReactChild[] | null;
6
+ tabs?: string[];
7
+ navigation?: any;
6
8
  loading?: boolean;
7
9
  color?: Color;
8
10
  keyboardOffset?: number;
9
- rightButton?: string;
10
- rightButtonOnClick?: () => void;
11
- renderListViewItem: (itemInfo: ListRenderItemInfo<any>) => React.ReactElement | null;
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
- interface SplitPageState {
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 class SplitPage extends React.Component {
12
- constructor() {
13
- super(...arguments);
14
- this.state = { selectedId: undefined };
15
- this.actionSheetRef = React.createRef();
16
- this.renderItem = (itemInfo) => {
17
- return (React.createElement(Box, { onClick: () => {
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
- render() {
45
- return (React.createElement(Box, { avoidKeyboard: true, color: this.props.color || "lightGray", direction: "row", display: "flex", flex: "grow", height: "100%", keyboardOffset: this.props.keyboardOffset, width: "100%" },
46
- this.props.loading === true && React.createElement(Spinner, { color: Unifier.theme.darkGray, size: "md" }),
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
@@ -1 +1 @@
1
- {"version":3,"file":"SplitPage.js","sourceRoot":"","sources":["../src/SplitPage.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SplitPage.js","sourceRoot":"","sources":["../src/SplitPage.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ferns-ui",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "main": "dist/index.js",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
package/src/Common.ts CHANGED
@@ -2001,11 +2001,14 @@ export interface PillProps {
2001
2001
  }
2002
2002
 
2003
2003
  export interface SegmentedControlProps {
2004
- items: (string | React.ReactNode)[];
2005
- onChange: ({activeIndex}: {activeIndex: number}) => void;
2006
- selectedItemIndex: number;
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.
@@ -4,48 +4,89 @@ import {Box} from "./Box";
4
4
  import {SegmentedControlProps} from "./Common";
5
5
  import {Text} from "./Text";
6
6
 
7
- export class SegmentedControl extends React.Component<SegmentedControlProps, {}> {
8
- renderItem(item: string | React.ReactNode) {
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
- render() {
18
- return (
19
- <Box
20
- color="lightGray"
21
- direction="row"
22
- display="flex"
23
- height={40}
24
- padding={1}
25
- rounding={3}
26
- width="100%"
27
- >
28
- {this.props.items.map((item, index) => (
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
- key={index}
31
- color={this.props.selectedItemIndex === index ? "white" : "lightGray"}
66
+ alignItems="center"
67
+ display="flex"
32
68
  height="100%"
33
- rounding={3}
34
- width={`${100 / this.props.items.length}%`}
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
- <Box
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
- </Box>
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: any;
17
+ navigation?: any;
15
18
  loading?: boolean;
16
19
  color?: Color;
17
20
  keyboardOffset?: number;
18
- rightButton?: string;
19
- rightButtonOnClick?: () => void;
20
- renderListViewItem: (itemInfo: ListRenderItemInfo<any>) => React.ReactElement | null;
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 class SplitPage extends React.Component<SplitPageProps, SplitPageState> {
35
- state = {selectedId: undefined};
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
- actionSheetRef: React.RefObject<any> = React.createRef();
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
- this.setState({selectedId: itemInfo.index});
64
+ setSelectedId(itemInfo.index);
44
65
  }}
45
66
  >
46
- {this.props.renderListViewItem(itemInfo)}
67
+ {renderListViewItem(itemInfo)}
47
68
  </Box>
48
69
  );
49
70
  };
50
71
 
51
- renderList = () => {
52
- if (!mediaQueryLargerThan("sm") && this.state.selectedId) {
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") ? this.props.listViewWidth ?? 300 : "100%",
59
- maxWidth: mediaQueryLargerThan("sm") ? this.props.listViewWidth ?? 300 : "100%",
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
- {this.props.renderListViewHeader && this.props.renderListViewHeader()}
89
+ {renderListViewHeader && renderListViewHeader()}
67
90
  <FlatList
68
- data={this.props.listViewData}
69
- extraData={this.props.listViewExtraData}
91
+ data={listViewData}
92
+ extraData={listViewExtraData}
70
93
  keyExtractor={(item) => item.id}
71
- renderItem={this.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={() => this.setState({selectedId: undefined})}
109
+ onClick={() => setSelectedId(undefined)}
87
110
  />
88
111
  </Box>
89
112
  )}
90
- {this.props.renderContent(this.state.selectedId)}
113
+ {renderContent && renderContent(selectedId)}
91
114
  </Box>
92
115
  );
93
116
  };
94
117
 
95
- render() {
96
- return (
97
- <Box
98
- avoidKeyboard
99
- color={this.props.color || "lightGray"}
100
- direction="row"
101
- display="flex"
102
- flex="grow"
103
- height="100%"
104
- keyboardOffset={this.props.keyboardOffset}
105
- width="100%"
106
- >
107
- {this.props.loading === true && <Spinner color={Unifier.theme.darkGray as any} size="md" />}
108
- {this.renderList()}
109
- {this.renderListContent()}
110
- </Box>
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
+ };