@etsoo/react 1.5.17 → 1.5.21

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.
@@ -1,9 +1,21 @@
1
- import { History } from '@reach/router';
1
+ import { History, HistorySource } from '@reach/router';
2
2
  import React from 'react';
3
+ declare type MemoryHistorySource = HistorySource & {
4
+ history: {
5
+ get entries(): any;
6
+ get index(): number;
7
+ go(to: number): void;
8
+ };
9
+ };
3
10
  /**
4
11
  * React utils
5
12
  */
6
13
  export declare namespace ReactUtils {
14
+ /**
15
+ * Cretae memory source to fix go back bug
16
+ * @param initialPath Initial path
17
+ */
18
+ function createMemorySource(initialPath?: string): MemoryHistorySource;
7
19
  /**
8
20
  * Format input value
9
21
  * @param value Input value
@@ -35,3 +47,4 @@ export declare namespace ReactUtils {
35
47
  */
36
48
  function triggerChange(input: HTMLInputElement, value: string, cancelable: boolean): void;
37
49
  }
50
+ export {};
@@ -1,4 +1,4 @@
1
- import { createHistory, createMemorySource, navigate } from '@reach/router';
1
+ import { createHistory, navigate } from '@reach/router';
2
2
  /**
3
3
  * React utils
4
4
  */
@@ -7,6 +7,71 @@ export var ReactUtils;
7
7
  // Memory history
8
8
  // https://github.com/reach/router/issues/225
9
9
  let memoryHistory;
10
+ /**
11
+ * Cretae memory source to fix go back bug
12
+ * @param initialPath Initial path
13
+ */
14
+ function createMemorySource(initialPath = '/') {
15
+ const searchIndex = initialPath.indexOf('?');
16
+ const pathname = searchIndex > -1
17
+ ? initialPath.substring(0, searchIndex)
18
+ : initialPath;
19
+ const initialLocation = {
20
+ pathname,
21
+ search: searchIndex > -1 ? initialPath.substring(searchIndex) : ''
22
+ };
23
+ let index = 0;
24
+ const stack = [initialLocation];
25
+ const states = [null];
26
+ return {
27
+ get location() {
28
+ return stack[index];
29
+ },
30
+ addEventListener(name, fn) { },
31
+ removeEventListener(name, fn) { },
32
+ history: {
33
+ get entries() {
34
+ return stack;
35
+ },
36
+ get index() {
37
+ return index;
38
+ },
39
+ get state() {
40
+ return states[index];
41
+ },
42
+ pushState(state, _, uri) {
43
+ const [pathname, search = ''] = uri.split('?');
44
+ index++;
45
+ // View a, index = 0
46
+ // View b, index = 1
47
+ // Go(-1), a, index = 0
48
+ // View c, index = 1, directly push is wrong
49
+ if (index < stack.length) {
50
+ stack.splice(index, stack.length - index);
51
+ states.splice(index, stack.length - index);
52
+ }
53
+ stack.push({
54
+ pathname,
55
+ search: search.length ? `?${search}` : search
56
+ });
57
+ states.push(state);
58
+ },
59
+ replaceState(state, _, uri) {
60
+ const [pathname, search = ''] = uri.split('?');
61
+ stack[index] = { pathname, search };
62
+ states[index] = state;
63
+ },
64
+ go(to) {
65
+ const newIndex = index + to;
66
+ if (newIndex < 0 || newIndex > states.length - 1) {
67
+ return;
68
+ }
69
+ index = newIndex;
70
+ }
71
+ }
72
+ };
73
+ }
74
+ ReactUtils.createMemorySource = createMemorySource;
10
75
  /**
11
76
  * Format input value
12
77
  * @param value Input value
@@ -23,10 +23,6 @@ export function BackButton(props) {
23
23
  // Navigate
24
24
  const navigate = ReactUtils.getNavigateFn();
25
25
  await navigate(-1);
26
- const history = ReactUtils.getMemoryHistory();
27
- if (history) {
28
- console.log(history);
29
- }
30
26
  };
31
27
  return (React.createElement(IconButton, { "aria-label": "Back", color: color, size: size, onClick: onClickLocal, sx: {
32
28
  backgroundColor: pColor.contrastText,
@@ -56,6 +56,8 @@ export function ListMoreDisplay(props) {
56
56
  ref.lastLoadedItems = newItems;
57
57
  ref.isNextPageLoading = false;
58
58
  ref.hasNextPage = hasNextPage;
59
+ // Next page
60
+ ref.currentPage = currentPage + 1;
59
61
  // Update rows
60
62
  if (states.items == null || reset)
61
63
  setStates({ items, completed: !hasNextPage });
@@ -1,16 +1,6 @@
1
1
  import { Card, CardContent, CardHeader, LinearProgress } from '@mui/material';
2
2
  import React from 'react';
3
3
  import { MoreFab } from './MoreFab';
4
- function getActions(input) {
5
- // Actions
6
- const actions = [];
7
- input.forEach((action) => {
8
- if (typeof action === 'boolean')
9
- return;
10
- actions.push(action);
11
- });
12
- return actions;
13
- }
14
4
  /**
15
5
  * Default mobile list item renderer
16
6
  * @param param0 List renderer props
@@ -34,32 +24,7 @@ export function MobileListItemRenderer({ data, itemHeight, margins }, renderer)
34
24
  }, transformOrigin: {
35
25
  vertical: 'top',
36
26
  horizontal: 'right'
37
- }, actions: getActions(actions), PaperProps: {
38
- elevation: 0,
39
- sx: {
40
- overflow: 'visible',
41
- filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
42
- mt: -0.4,
43
- '& .MuiAvatar-root': {
44
- width: 32,
45
- height: 32,
46
- ml: -0.5,
47
- mr: 1
48
- },
49
- '&:before': {
50
- content: '""',
51
- display: 'block',
52
- position: 'absolute',
53
- top: 0,
54
- right: 14,
55
- width: 10,
56
- height: 10,
57
- bgcolor: 'background.paper',
58
- transform: 'translateY(-50%) rotate(45deg)',
59
- zIndex: 0
60
- }
61
- }
62
- } })) : (actions), title: title, titleTypographyProps: { variant: 'body2' }, subheader: subheader, subheaderTypographyProps: { variant: 'caption' } }),
27
+ }, actions: actions })) : (actions), title: title, titleTypographyProps: { variant: 'body2' }, subheader: subheader, subheaderTypographyProps: { variant: 'caption' } }),
63
28
  React.createElement(CardContent, { sx: {
64
29
  paddingTop: 0,
65
30
  paddingBottom: cardActions == null
@@ -9,7 +9,11 @@ export interface MoreFabProps extends CustomFabProps {
9
9
  /**
10
10
  * Actions
11
11
  */
12
- actions?: ListItemReact[];
12
+ actions?: (ListItemReact | boolean)[];
13
+ /**
14
+ * Dray arrow
15
+ */
16
+ drawArrow?: boolean;
13
17
  /**
14
18
  * Main icon
15
19
  */
package/lib/mu/MoreFab.js CHANGED
@@ -2,16 +2,53 @@ import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
2
2
  import React from 'react';
3
3
  import { Divider, Fab, IconButton, ListItemIcon, ListItemText, Menu, MenuItem } from '@mui/material';
4
4
  import { Link } from '@reach/router';
5
+ function getActions(input) {
6
+ // Actions
7
+ const actions = [];
8
+ input.forEach((action) => {
9
+ if (typeof action === 'boolean')
10
+ return;
11
+ actions.push(action);
12
+ });
13
+ return actions;
14
+ }
5
15
  /**
6
16
  * More fab
7
17
  * @returns Component
8
18
  */
9
19
  export function MoreFab(props) {
10
20
  // Destruct
11
- const { actions, anchorOrigin = {
21
+ const { actions, drawArrow = true, anchorOrigin = {
12
22
  vertical: 'top',
13
23
  horizontal: 'right'
14
- }, color = 'primary', icon = React.createElement(MoreHorizIcon, null), iconButton = false, PaperProps, size, title, transformOrigin = {
24
+ }, color = 'primary', icon = React.createElement(MoreHorizIcon, null), iconButton = false, PaperProps = drawArrow
25
+ ? {
26
+ elevation: 0,
27
+ sx: {
28
+ overflow: 'visible',
29
+ filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
30
+ mt: -0.4,
31
+ '& .MuiAvatar-root': {
32
+ width: 32,
33
+ height: 32,
34
+ ml: -0.5,
35
+ mr: 1
36
+ },
37
+ '&:before': {
38
+ content: '""',
39
+ display: 'block',
40
+ position: 'absolute',
41
+ top: 0,
42
+ right: 14,
43
+ width: 10,
44
+ height: 10,
45
+ bgcolor: 'background.paper',
46
+ transform: 'translateY(-50%) rotate(45deg)',
47
+ zIndex: 0
48
+ }
49
+ }
50
+ }
51
+ : undefined, size, title, transformOrigin = {
15
52
  vertical: 'bottom',
16
53
  horizontal: 'right'
17
54
  } } = props;
@@ -30,13 +67,15 @@ export function MoreFab(props) {
30
67
  // No actions
31
68
  if (actions == null || actions.length == 0)
32
69
  return React.createElement(React.Fragment, null);
70
+ // Actions
71
+ const actionsLocal = getActions(actions);
33
72
  // Has any icon
34
- const hasIcon = actions.some((action) => action.icon != null);
73
+ const hasIcon = actionsLocal.some((action) => action.icon != null);
35
74
  // Main
36
75
  const main = iconButton ? (React.createElement(IconButton, { color: color, size: size, title: title, onClick: handleClick }, icon)) : (React.createElement(Fab, { color: color, size: size, title: title, onClick: handleClick }, icon));
37
76
  return (React.createElement(React.Fragment, null,
38
77
  main,
39
- React.createElement(Menu, { disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: open, onClose: handleClose, PaperProps: PaperProps }, actions.map(({ label, icon, action }, index) => label === '-' ? (React.createElement(Divider, { key: index })) : (React.createElement(MenuItem, { key: label, ...(typeof action === 'string'
78
+ React.createElement(Menu, { disableScrollLock: true, anchorEl: anchorEl, anchorOrigin: anchorOrigin, keepMounted: true, transformOrigin: transformOrigin, open: open, onClose: handleClose, PaperProps: PaperProps }, actionsLocal.map(({ label, icon, action }, index) => label === '-' ? (React.createElement(Divider, { key: index })) : (React.createElement(MenuItem, { key: label, ...(typeof action === 'string'
40
79
  ? action.includes('://')
41
80
  ? {
42
81
  component: 'a',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.5.17",
3
+ "version": "1.5.21",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -53,8 +53,8 @@
53
53
  "@etsoo/appscript": "^1.2.50",
54
54
  "@etsoo/notificationbase": "^1.1.1",
55
55
  "@etsoo/shared": "^1.1.11",
56
- "@mui/icons-material": "^5.4.1",
57
- "@mui/material": "^5.4.1",
56
+ "@mui/icons-material": "^5.4.2",
57
+ "@mui/material": "^5.4.2",
58
58
  "@reach/router": "^1.3.4",
59
59
  "@types/pica": "^9.0.0",
60
60
  "@types/pulltorefreshjs": "^0.1.5",
@@ -76,16 +76,16 @@
76
76
  "react-window": "^1.8.6"
77
77
  },
78
78
  "devDependencies": {
79
- "@babel/cli": "^7.17.0",
80
- "@babel/core": "^7.17.2",
79
+ "@babel/cli": "^7.17.3",
80
+ "@babel/core": "^7.17.4",
81
81
  "@babel/plugin-transform-runtime": "^7.17.0",
82
82
  "@babel/preset-env": "^7.16.11",
83
83
  "@babel/runtime-corejs3": "^7.17.2",
84
84
  "@types/jest": "^27.4.0",
85
85
  "@types/react-test-renderer": "^17.0.1",
86
- "@typescript-eslint/eslint-plugin": "^5.11.0",
87
- "@typescript-eslint/parser": "^5.11.0",
88
- "eslint": "^8.8.0",
86
+ "@typescript-eslint/eslint-plugin": "^5.12.0",
87
+ "@typescript-eslint/parser": "^5.12.0",
88
+ "eslint": "^8.9.0",
89
89
  "eslint-config-airbnb-base": "^15.0.0",
90
90
  "eslint-plugin-import": "^2.25.4",
91
91
  "eslint-plugin-react": "^7.28.0",
@@ -1,11 +1,14 @@
1
- import {
2
- createHistory,
3
- createMemorySource,
4
- History,
5
- navigate
6
- } from '@reach/router';
1
+ import { createHistory, History, HistorySource, navigate } from '@reach/router';
7
2
  import React from 'react';
8
3
 
4
+ type MemoryHistorySource = HistorySource & {
5
+ history: {
6
+ get entries(): any;
7
+ get index(): number;
8
+ go(to: number): void;
9
+ };
10
+ };
11
+
9
12
  /**
10
13
  * React utils
11
14
  */
@@ -14,6 +17,82 @@ export namespace ReactUtils {
14
17
  // https://github.com/reach/router/issues/225
15
18
  let memoryHistory: History | null;
16
19
 
20
+ /**
21
+ * Cretae memory source to fix go back bug
22
+ * @param initialPath Initial path
23
+ */
24
+ export function createMemorySource(
25
+ initialPath: string = '/'
26
+ ): MemoryHistorySource {
27
+ const searchIndex = initialPath.indexOf('?');
28
+ const pathname =
29
+ searchIndex > -1
30
+ ? initialPath.substring(0, searchIndex)
31
+ : initialPath;
32
+
33
+ const initialLocation: any = {
34
+ pathname,
35
+ search: searchIndex > -1 ? initialPath.substring(searchIndex) : ''
36
+ };
37
+
38
+ let index = 0;
39
+
40
+ const stack = [initialLocation];
41
+ const states = [null];
42
+
43
+ return {
44
+ get location() {
45
+ return stack[index];
46
+ },
47
+ addEventListener(name, fn) {},
48
+ removeEventListener(name, fn) {},
49
+ history: {
50
+ get entries() {
51
+ return stack;
52
+ },
53
+ get index() {
54
+ return index;
55
+ },
56
+ get state() {
57
+ return states[index];
58
+ },
59
+ pushState(state, _, uri) {
60
+ const [pathname, search = ''] = uri.split('?');
61
+ index++;
62
+
63
+ // View a, index = 0
64
+ // View b, index = 1
65
+ // Go(-1), a, index = 0
66
+ // View c, index = 1, directly push is wrong
67
+ if (index < stack.length) {
68
+ stack.splice(index, stack.length - index);
69
+ states.splice(index, stack.length - index);
70
+ }
71
+
72
+ stack.push({
73
+ pathname,
74
+ search: search.length ? `?${search}` : search
75
+ });
76
+ states.push(state);
77
+ },
78
+ replaceState(state, _, uri) {
79
+ const [pathname, search = ''] = uri.split('?');
80
+ stack[index] = { pathname, search };
81
+ states[index] = state;
82
+ },
83
+ go(to: number) {
84
+ const newIndex = index + to;
85
+
86
+ if (newIndex < 0 || newIndex > states.length - 1) {
87
+ return;
88
+ }
89
+
90
+ index = newIndex;
91
+ }
92
+ }
93
+ };
94
+ }
95
+
17
96
  /**
18
97
  * Format input value
19
98
  * @param value Input value
@@ -2,7 +2,6 @@ import { IconButton, IconButtonProps, useTheme } from '@mui/material';
2
2
  import ArrowBackIcon from '@mui/icons-material/ArrowBack';
3
3
  import React from 'react';
4
4
  import { ReactUtils } from '../app/ReactUtils';
5
- import { BridgeUtils } from '@etsoo/appscript';
6
5
 
7
6
  /**
8
7
  * BackButton props
@@ -34,11 +33,6 @@ export function BackButton(props: BackButtonProps) {
34
33
  // Navigate
35
34
  const navigate = ReactUtils.getNavigateFn();
36
35
  await navigate(-1);
37
-
38
- const history = ReactUtils.getMemoryHistory();
39
- if (history) {
40
- console.log(history);
41
- }
42
36
  };
43
37
 
44
38
  return (
@@ -137,6 +137,9 @@ export function ListMoreDisplay<
137
137
  ref.isNextPageLoading = false;
138
138
  ref.hasNextPage = hasNextPage;
139
139
 
140
+ // Next page
141
+ ref.currentPage = currentPage + 1;
142
+
140
143
  // Update rows
141
144
  if (states.items == null || reset)
142
145
  setStates({ items, completed: !hasNextPage });
@@ -4,16 +4,6 @@ import { ListItemReact } from '../components/ListItemReact';
4
4
  import { MoreFab } from './MoreFab';
5
5
  import { ScrollerListExInnerItemRendererProps } from './ScrollerListEx';
6
6
 
7
- function getActions(input: (ListItemReact | boolean)[]): ListItemReact[] {
8
- // Actions
9
- const actions: ListItemReact[] = [];
10
- input.forEach((action) => {
11
- if (typeof action === 'boolean') return;
12
- actions.push(action);
13
- });
14
- return actions;
15
- }
16
-
17
7
  /**
18
8
  * Default mobile list item renderer
19
9
  * @param param0 List renderer props
@@ -61,34 +51,7 @@ export function MobileListItemRenderer<T>(
61
51
  vertical: 'top',
62
52
  horizontal: 'right'
63
53
  }}
64
- actions={getActions(actions)}
65
- PaperProps={{
66
- elevation: 0,
67
- sx: {
68
- overflow: 'visible',
69
- filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
70
- mt: -0.4,
71
- '& .MuiAvatar-root': {
72
- width: 32,
73
- height: 32,
74
- ml: -0.5,
75
- mr: 1
76
- },
77
- '&:before': {
78
- content: '""',
79
- display: 'block',
80
- position: 'absolute',
81
- top: 0,
82
- right: 14,
83
- width: 10,
84
- height: 10,
85
- bgcolor: 'background.paper',
86
- transform:
87
- 'translateY(-50%) rotate(45deg)',
88
- zIndex: 0
89
- }
90
- }
91
- }}
54
+ actions={actions}
92
55
  />
93
56
  ) : (
94
57
  actions
@@ -5,7 +5,6 @@ import {
5
5
  Divider,
6
6
  Fab,
7
7
  IconButton,
8
- Link as MLink,
9
8
  ListItemIcon,
10
9
  ListItemText,
11
10
  Menu,
@@ -23,7 +22,12 @@ export interface MoreFabProps extends CustomFabProps {
23
22
  /**
24
23
  * Actions
25
24
  */
26
- actions?: ListItemReact[];
25
+ actions?: (ListItemReact | boolean)[];
26
+
27
+ /**
28
+ * Dray arrow
29
+ */
30
+ drawArrow?: boolean;
27
31
 
28
32
  /**
29
33
  * Main icon
@@ -54,6 +58,16 @@ export interface MoreFabProps extends CustomFabProps {
54
58
  transformOrigin?: PopoverOrigin;
55
59
  }
56
60
 
61
+ function getActions(input: (ListItemReact | boolean)[]): ListItemReact[] {
62
+ // Actions
63
+ const actions: ListItemReact[] = [];
64
+ input.forEach((action) => {
65
+ if (typeof action === 'boolean') return;
66
+ actions.push(action);
67
+ });
68
+ return actions;
69
+ }
70
+
57
71
  /**
58
72
  * More fab
59
73
  * @returns Component
@@ -62,6 +76,7 @@ export function MoreFab(props: MoreFabProps) {
62
76
  // Destruct
63
77
  const {
64
78
  actions,
79
+ drawArrow = true,
65
80
  anchorOrigin = {
66
81
  vertical: 'top',
67
82
  horizontal: 'right'
@@ -69,7 +84,34 @@ export function MoreFab(props: MoreFabProps) {
69
84
  color = 'primary',
70
85
  icon = <MoreHorizIcon />,
71
86
  iconButton = false,
72
- PaperProps,
87
+ PaperProps = drawArrow
88
+ ? {
89
+ elevation: 0,
90
+ sx: {
91
+ overflow: 'visible',
92
+ filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
93
+ mt: -0.4,
94
+ '& .MuiAvatar-root': {
95
+ width: 32,
96
+ height: 32,
97
+ ml: -0.5,
98
+ mr: 1
99
+ },
100
+ '&:before': {
101
+ content: '""',
102
+ display: 'block',
103
+ position: 'absolute',
104
+ top: 0,
105
+ right: 14,
106
+ width: 10,
107
+ height: 10,
108
+ bgcolor: 'background.paper',
109
+ transform: 'translateY(-50%) rotate(45deg)',
110
+ zIndex: 0
111
+ }
112
+ }
113
+ }
114
+ : undefined,
73
115
  size,
74
116
  title,
75
117
  transformOrigin = {
@@ -97,8 +139,11 @@ export function MoreFab(props: MoreFabProps) {
97
139
  // No actions
98
140
  if (actions == null || actions.length == 0) return <React.Fragment />;
99
141
 
142
+ // Actions
143
+ const actionsLocal = getActions(actions);
144
+
100
145
  // Has any icon
101
- const hasIcon = actions.some((action) => action.icon != null);
146
+ const hasIcon = actionsLocal.some((action) => action.icon != null);
102
147
 
103
148
  // Main
104
149
  const main = iconButton ? (
@@ -129,7 +174,7 @@ export function MoreFab(props: MoreFabProps) {
129
174
  onClose={handleClose}
130
175
  PaperProps={PaperProps}
131
176
  >
132
- {actions.map(({ label, icon, action }, index) =>
177
+ {actionsLocal.map(({ label, icon, action }, index) =>
133
178
  label === '-' ? (
134
179
  <Divider key={index} />
135
180
  ) : (