@onehat/ui 0.3.282 → 0.3.284

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.3.282",
3
+ "version": "0.3.284",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  EDITOR_MODE__VIEW,
3
3
  } from '../../Constants/Editor.js';
4
- import testProps from '../../Functions/testProps.js';
5
4
  import withComponent from '../Hoc/withComponent.js';
6
5
  import Form from '../Form/Form.js';
7
6
  import Viewer from '../Viewer/Viewer.js';
@@ -0,0 +1,163 @@
1
+ import { useState, useEffect, useRef, } from 'react';
2
+ import {
3
+ Box,
4
+ Column,
5
+ Row,
6
+ Text,
7
+ } from 'native-base';
8
+ import withComponent from '../Hoc/withComponent.js';
9
+ import {
10
+ UI_MODE_WEB,
11
+ UI_MODE_REACT_NATIVE,
12
+ } from '../../Constants/UiModes.js';
13
+ import {
14
+ EDITOR_TYPE__INLINE,
15
+ } from '../../Constants/Editor.js';
16
+ import testProps from '../../Functions/testProps.js';
17
+ import UiGlobals from '../../UiGlobals.js';
18
+ import Form from '../Form/Form.js';
19
+ import _ from 'lodash';
20
+
21
+ function InlineEditor(props) {
22
+
23
+ if (UiGlobals.mode === UI_MODE_REACT_NATIVE) {
24
+ throw new Error('Not yet implemented for RN.');
25
+ }
26
+
27
+ const {
28
+ isEditorShown = false,
29
+ columnsConfig,
30
+ setIsEditorShown,
31
+ isEditorViewOnly,
32
+ onEditorCancel,
33
+ onEditorSave,
34
+ onEditorClose,
35
+ editorStateRef,
36
+
37
+ // withComponent
38
+ self,
39
+
40
+ // withSelection
41
+ selection,
42
+
43
+ // withData
44
+ Repository,
45
+ } = props,
46
+ styles = UiGlobals.styles,
47
+ maskRef = useRef(),
48
+ inlineEditorRef = useRef(),
49
+ [currentRow, setCurrentRow] = useState(),
50
+ onScreenResize = () => {
51
+ // TODO: Attach a div with zIndex 0 to body to monitor resize events. THis is handler
52
+
53
+ moveEditor(currentRow);
54
+ },
55
+ moveEditor = (currentRow) => {
56
+ const
57
+ rowBounds = currentRow.getBoundingClientRect(),
58
+ editor = inlineEditorRef.current,
59
+ editorStyle = editor.style,
60
+ editorBounds = editor.parentElement.getBoundingClientRect(), // reference parentElement, because this doesn't change based on last moveEditor call
61
+ delta = editorBounds.top - rowBounds.top;
62
+
63
+ editorStyle.top = (-1 * delta) + 'px';
64
+ },
65
+ onEditorShown = () => {
66
+ // determine which row to move the editor to
67
+ const
68
+ data = self.parent.gridRef.current.props.data, // This is okay, because (for now) the inlineEditor is only for use with grids
69
+ ix = data.indexOf(selection[0]),
70
+ gridRowsContainer = self.parent.gridRef.current._listRef._scrollRef.childNodes[0],
71
+ currentRow = gridRowsContainer.childNodes[ix];
72
+
73
+ // TODO: verify it works if not using a Repository
74
+
75
+ moveEditor(currentRow);
76
+ setCurrentRow(currentRow);
77
+ };
78
+
79
+ useEffect(() => {
80
+ if (maskRef.current) {
81
+ maskRef.current.focus();
82
+ }
83
+ if (isEditorShown) {
84
+ onEditorShown();
85
+ }
86
+ }, [isEditorShown]);
87
+
88
+ if (!isEditorShown) {
89
+ return null;
90
+ }
91
+
92
+ if (selection.length < 1) {
93
+ return null; // phantom record may have just been deleted
94
+ }
95
+ if (selection.length !== 1) {
96
+ throw new Error('Can only edit one at a time with inline editor!');
97
+ }
98
+ if (!Repository) {
99
+ throw new Error('Must use a Repository');
100
+ }
101
+
102
+ return <>
103
+ <Box
104
+ ref={maskRef}
105
+ position="fixed"
106
+ w="100vw"
107
+ h="100vh"
108
+ top="0"
109
+ left="0"
110
+ bg="#000"
111
+ opacity={0.3}
112
+ zIndex={0}
113
+ onClick={(e) => {
114
+ e.preventDefault();
115
+ e.stopPropagation();
116
+ onEditorCancel();
117
+ }}
118
+ tabIndex={-1}
119
+ onKeyDown={(e) => {
120
+ if (e.key === 'Escape') {
121
+ onEditorCancel();
122
+ }
123
+ }}
124
+ />
125
+ <Column
126
+ ref={inlineEditorRef}
127
+ position="absolute"
128
+ zIndex={10}
129
+ {...testProps('inlineEditor')}
130
+ h={isEditorShown ? '100px' : 0}
131
+ minWidth="100%"
132
+ display="inline-block"
133
+ whiteSpace="nowrap"
134
+ >
135
+ <Form
136
+ editorType={EDITOR_TYPE__INLINE}
137
+ editorStateRef={editorStateRef}
138
+
139
+ Repository={Repository}
140
+ isMultiple={selection.length > 1}
141
+ isEditorViewOnly={isEditorViewOnly}
142
+ columnsConfig={columnsConfig}
143
+ bg="#fff"
144
+ borderTopWidth={4}
145
+ borderTopColor={styles.GRID_INLINE_EDITOR_BORDER_COLOR}
146
+ borderBottomWidth={4}
147
+ borderBottomColor={styles.GRID_INLINE_EDITOR_BORDER_COLOR}
148
+ py={1}
149
+ px={0}
150
+
151
+ record={selection[0]}
152
+ onCancel={onEditorCancel}
153
+ onSave={onEditorSave}
154
+ onClose={onEditorClose}
155
+ parent={self}
156
+ reference="form"
157
+ />
158
+ </Column>
159
+ </>;
160
+
161
+ }
162
+
163
+ export default withComponent(InlineEditor);
@@ -324,7 +324,7 @@ function GridComponent(props) {
324
324
  if (row.item.isDestroyed) {
325
325
  return null;
326
326
  }
327
- if (row.item.id === 'inlineEditor') {
327
+ if (row.item.id === 'editor') {
328
328
  return inlineEditor;
329
329
  }
330
330
 
@@ -946,7 +946,7 @@ function GridComponent(props) {
946
946
  rowData.unshift({ id: 'headerRow' });
947
947
  }
948
948
  if (inlineEditor) {
949
- rowData.push({ id: 'inlineEditor' }); // make editor the last row so it can scroll with all other rows
949
+ rowData.push({ id: 'editor' }); // make editor the last row so it can scroll with all other rows
950
950
  }
951
951
  const initialNumToRender = rowData?.length || 10;
952
952
 
@@ -1014,7 +1014,7 @@ function GridComponent(props) {
1014
1014
  />
1015
1015
 
1016
1016
  if (CURRENT_MODE === UI_MODE_WEB) {
1017
- grid = <ScrollView horizontal={false}>{grid}</ScrollView>; // fix scrolling bug on nested FlatLists
1017
+ grid = <ScrollView horizontal={false} testID="ScrollView">{grid}</ScrollView>; // fix scrolling bug on nested FlatLists
1018
1018
  } else
1019
1019
  if (CURRENT_MODE === UI_MODE_REACT_NATIVE) {
1020
1020
  grid = <ScrollView flex={1} w="100%">{grid}</ScrollView>
@@ -1067,7 +1067,6 @@ function GridComponent(props) {
1067
1067
 
1068
1068
  grid = <Column
1069
1069
  {...testProps(self)}
1070
- // testID="outerContainer"
1071
1070
  ref={containerRef}
1072
1071
  tabIndex={0}
1073
1072
  onKeyDown={onGridKeyDown}
@@ -1081,7 +1080,7 @@ function GridComponent(props) {
1081
1080
  {topToolbar}
1082
1081
 
1083
1082
  <Column
1084
- {...testProps('gridContainer')}
1083
+ testID="gridContainer"
1085
1084
  ref={gridContainerRef}
1086
1085
  w="100%"
1087
1086
  flex={1}
@@ -1,21 +1,8 @@
1
- import React, { useState, useEffect, useRef, } from 'react';
2
- import {
3
- Box,
4
- Column,
5
- Modal,
6
- Row,
7
- Text,
8
- } from 'native-base';
1
+ import { useState, } from 'react';
9
2
  import {
10
3
  EDITOR_TYPE__INLINE,
11
4
  } from '../../Constants/Editor.js';
12
- import {
13
- UI_MODE_WEB,
14
- UI_MODE_REACT_NATIVE,
15
- } from '../../Constants/UiModes.js';
16
- import UiGlobals from '../../UiGlobals.js';
17
- import testProps from '../../Functions/testProps.js';
18
- import Form from '../Form/Form.js';
5
+ import InlineEditor from '../Editor/InlineEditor.js';
19
6
  import withEditor from './withEditor.js';
20
7
  import _ from 'lodash';
21
8
 
@@ -35,152 +22,45 @@ function withAdditionalProps(WrappedComponent) {
35
22
  // withAdditionalProps(withEditor(withInlineEditor))
36
23
 
37
24
  export default function withInlineEditor(WrappedComponent, skipWrappers = false) {
38
- const InlineEditor = (props) => {
25
+ const Editor = (props) => {
39
26
  const {
40
- editorType,
41
27
  isEditorShown = false,
42
28
  setIsEditorShown,
43
- isEditorViewOnly,
44
- onEditorCancel,
45
- onEditorSave,
46
- onEditorClose,
47
- editorStateRef,
29
+ editorProps = {},
48
30
 
49
31
  // withComponent
50
32
  self,
51
33
 
52
- // withSelection
53
- selection,
34
+ // pull these out, as we don't want them going to the Editor
35
+ selectorId,
36
+ selectorSelected,
37
+ h,
54
38
 
55
- // withData
56
- Repository,
39
+ ...propsToPass
57
40
  } = props,
58
- styles = UiGlobals.styles,
59
- maskRef = useRef(),
60
- inlineEditorRef = useRef(),
61
41
  [localColumnsConfig, setLocalColumnsConfig] = useState([]),
62
- [currentRow, setCurrentRow] = useState(),
63
42
  onChangeColumnsConfig = (columnsConfig) => {
64
43
  setLocalColumnsConfig(columnsConfig);
65
- },
66
- onScreenResize = () => {
67
- // TODO: Attach a div with zIndex 0 to body to monitor resize events. THis is handler
68
-
69
- moveEditor(currentRow);
70
- },
71
- moveEditor = (currentRow) => {
72
- const
73
- rowBounds = currentRow.getBoundingClientRect(),
74
- editor = inlineEditorRef.current,
75
- editorStyle = editor.style,
76
- editorBounds = editor.parentElement.getBoundingClientRect(), // reference parentElement, because this doesn't change based on last moveEditor call
77
- delta = editorBounds.top - rowBounds.top;
78
-
79
- editorStyle.top = (-1 * delta) + 'px';
80
- },
81
- onEditorShown = () => {
82
- // determine which row to move the editor to
83
- const
84
- data = self.gridRef.current.props.data, // This is okay, because (for now) the inlineEditor is only for use with grids
85
- ix = data.indexOf(selection[0]),
86
- gridRowsContainer = self.gridRef.current._listRef._scrollRef.childNodes[0],
87
- currentRow = gridRowsContainer.childNodes[ix];
88
-
89
- // TODO: verify it works if not using a Repository
90
-
91
- moveEditor(currentRow);
92
- setCurrentRow(currentRow);
93
44
  };
94
-
95
- useEffect(() => {
96
- if (maskRef.current) {
97
- maskRef.current.focus();
98
- }
99
- if (isEditorShown) {
100
- onEditorShown();
101
- }
102
- }, [isEditorShown]);
103
-
104
- if (isEditorShown && selection.length < 1) {
105
- return null; // phantom record may have just been deleted
106
- }
107
- if (isEditorShown && selection.length !== 1) {
108
- throw new Error('Can only edit one at a time with inline editor!');
109
- }
110
- if (UiGlobals.mode === UI_MODE_REACT_NATIVE) {
111
- throw new Error('Not yet implemented for RN.');
112
- }
113
45
 
114
- let inlineEditor = null;
115
- if (Repository) {
116
- inlineEditor = <>
117
- {isEditorShown && <Box
118
- ref={maskRef}
119
- position="fixed"
120
- w="100vw"
121
- h="100vh"
122
- top="0"
123
- left="0"
124
- bg="#000"
125
- opacity={0.3}
126
- zIndex={0}
127
- onClick={(e) => {
128
- e.preventDefault();
129
- e.stopPropagation();
130
- onEditorCancel();
131
- }}
132
- tabIndex={-1}
133
- onKeyDown={(e) => {
134
- if (e.key === 'Escape') {
135
- onEditorCancel();
136
- }
137
- }}
138
- ></Box>}
139
- <Column
140
- ref={inlineEditorRef}
141
- position="absolute"
142
- zIndex={10}
143
- {...testProps('inlineEditor')}
144
- h={isEditorShown ? '100px' : 0}
145
- minWidth="100%"
146
- display="inline-block"
147
- whiteSpace="nowrap"
148
- >
149
- {isEditorShown &&
150
- <Form
151
- parent={self}
152
- reference="form"
153
- editorType={EDITOR_TYPE__INLINE}
154
- editorStateRef={editorStateRef}
155
- record={selection[0]}
156
- Repository={Repository}
157
- isMultiple={selection.length > 1}
158
- isEditorViewOnly={isEditorViewOnly}
159
- columnsConfig={localColumnsConfig}
160
- onCancel={onEditorCancel}
161
- onSave={onEditorSave}
162
- onClose={onEditorClose}
163
- bg="#fff"
164
- borderTopWidth={4}
165
- borderTopColor={styles.GRID_INLINE_EDITOR_BORDER_COLOR}
166
- borderBottomWidth={4}
167
- borderBottomColor={styles.GRID_INLINE_EDITOR_BORDER_COLOR}
168
- py={1}
169
- px={0}
170
- />}
171
- </Column>
172
- </>;
173
- }
174
-
175
46
  return <WrappedComponent
176
- {...props}
177
47
  onChangeColumnsConfig={onChangeColumnsConfig}
178
- inlineEditor={inlineEditor}
179
48
  isInlineEditorShown={isEditorShown}
49
+ inlineEditor={<InlineEditor
50
+ {...propsToPass}
51
+ {...editorProps}
52
+ parent={self}
53
+ reference="editor"
54
+ columnsConfig={localColumnsConfig}
55
+ isEditorShown={isEditorShown}
56
+ setIsEditorShown={setIsEditorShown}
57
+ />}
58
+
59
+ {...props}
180
60
  />;
181
61
  };
182
62
  if (skipWrappers) {
183
- return InlineEditor; // this is for InlineSideEditor, not yet implemented
63
+ return Editor; // this is for InlineSideEditor, not yet implemented
184
64
  }
185
- return withAdditionalProps(withEditor(InlineEditor));
65
+ return withAdditionalProps(withEditor(Editor));
186
66
  }
@@ -0,0 +1,84 @@
1
+
2
+ import {
3
+ getDomNode,
4
+ getDomNodes,
5
+ } from './dom_functions';
6
+ import _ from 'lodash';
7
+ const $ = Cypress.$;
8
+
9
+
10
+ export function clickAddButton(parentSelectors) {
11
+ return clickButton(parentSelectors, 'addBtn');
12
+ }
13
+ export function clickSaveButton(parentSelectors) {
14
+ return clickButton(parentSelectors, 'saveBtn');
15
+ }
16
+ export function clickEditButton(parentSelectors) {
17
+ return clickButton(parentSelectors, 'editBtn');
18
+ }
19
+ export function clickDeleteButton(parentSelectors) {
20
+ return clickButton(parentSelectors, 'deleteBtn');
21
+ }
22
+ export function clickDuplicateButton(parentSelectors) {
23
+ return clickButton(parentSelectors, 'duplicateBtn');
24
+ }
25
+ export function clickReloadButton(parentSelectors) {
26
+ return clickButton(parentSelectors, 'reloadPageBtn');
27
+ }
28
+ export function clickCloseButton(parentSelectors) {
29
+ return clickButton(parentSelectors, 'closeBtn');
30
+ }
31
+ export function clickCancelButton(parentSelectors) {
32
+ return clickButton(parentSelectors, 'cancelBtn');
33
+ }
34
+ export function clickOkButton(parentSelectors) {
35
+ return clickButton(parentSelectors, 'okBtn');
36
+ }
37
+ export function clickYesButton(parentSelectors) {
38
+ return clickButton(parentSelectors, 'yesBtn');
39
+ }
40
+ export function clickNoButton(parentSelectors) {
41
+ return clickButton(parentSelectors, 'noBtn');
42
+ }
43
+ export function clickXButton(parentSelectors) {
44
+ return clickButton(parentSelectors, 'xBtn');
45
+ }
46
+ export function clickTrigger(parentSelectors) {
47
+ return clickButton(parentSelectors, 'trigger');
48
+ }
49
+ export function clickToEditButton(parentSelectors) {
50
+ return clickButton(parentSelectors, 'toEditBtn');
51
+ }
52
+ export function clickToEditButtonIfExists(parentSelectors) {
53
+ return clickButtonIfExists(parentSelectors, 'toEditBtn');
54
+ }
55
+ export function clickToViewButton(parentSelectors) {
56
+ return clickButton(parentSelectors, 'toViewBtn');
57
+ }
58
+ export function clickToViewButtonIfExists(parentSelectors) {
59
+ return clickButtonIfExists(parentSelectors, 'toViewBtn');
60
+ }
61
+ export function toFullMode(parentSelectors) {
62
+ return clickButton(parentSelectors, 'fullModeBtn');
63
+ }
64
+ export function toSideMode(parentSelectors) {
65
+ return clickButton(parentSelectors, 'sideModeBtn');
66
+ }
67
+ export function clickButton(parentSelectors, name) {
68
+ if (_.isString(parentSelectors)) {
69
+ parentSelectors = [parentSelectors];
70
+ }
71
+ return getDomNode([...parentSelectors, name])
72
+ // .scrollIntoView()
73
+ .click({ force: true });
74
+ }
75
+ export function clickButtonIfExists(parentSelectors, name) {
76
+ if (_.isString(parentSelectors)) {
77
+ parentSelectors = [parentSelectors];
78
+ }
79
+ return getDomNode([...parentSelectors, name]).then((node) => {
80
+ if (node) {
81
+ node.click();
82
+ }
83
+ });
84
+ }
@@ -0,0 +1,108 @@
1
+ import {
2
+ getDomNode,
3
+ getDomNodes,
4
+ } from './dom_functions';
5
+
6
+
7
+ export function markForPageReload() {
8
+ // See https://github.com/cypress-io/cypress/issues/1805#issuecomment-525482440
9
+ cy.window()
10
+ .then((win) => {
11
+ win.beforeReload = true;
12
+ });
13
+ }
14
+ export function waitForPageReload() {
15
+ // See https://github.com/cypress-io/cypress/issues/1805#issuecomment-525482440
16
+ cy.window({ timeout: 30000 })
17
+ .should('not.have.prop', 'beforeReload');
18
+ }
19
+ export function waitForNavigationTo(url) {
20
+ return cy.location('pathname', { timeout: 30000 })
21
+ .should('include', url);
22
+ }
23
+
24
+
25
+
26
+ // __ ___ ____
27
+ // / |/ /__ ______________ _____ ____ / __ )____ _ __
28
+ // / /|_/ / _ \/ ___/ ___/ __ `/ __ `/ _ \/ __ / __ \| |/_/
29
+ // / / / / __(__ |__ ) /_/ / /_/ / __/ /_/ / /_/ /> <
30
+ // /_/ /_/\___/____/____/\__,_/\__, /\___/_____/\____/_/|_|
31
+ // /____/
32
+ export function clickMessageBoxDefaultButton() {
33
+ getDomNode(['AlertDialogue', 'okBtn'])
34
+ .click();
35
+ }
36
+ export function verifyNoErrorBox() {
37
+ getDomNode('ErrorMessage', { timeout: 1000 })
38
+ .should('not.exist', 'Error dialogue popped up.');
39
+ }
40
+
41
+
42
+
43
+ // export function verifyNoErrorMessage() {
44
+ // // cy.wait(1000);
45
+ // cy.get('input[data-testid="ErrorMessage"]').should('not.exist');
46
+ // }
47
+
48
+ // export function checkForErrors() {
49
+ // cy.get('html')
50
+ // .first()
51
+ // .then((el) => {
52
+ // const result = hasError(el[0].innerHTML);
53
+ // expect(result).to.eq(false, 'Page has errors!' + (result && result.title));
54
+ // });
55
+ // }
56
+
57
+ // // Helpers for checkForErrors()
58
+ // function hasError(html) {
59
+ // return hasNotice(html) || hasWarning(html) || hasException(html);
60
+ // }
61
+ // function hasNotice(html) {
62
+ // const result = /<b>Notice<\/b> \(/is.test(html);
63
+ // if (result) {
64
+ // // Try to determine error message
65
+ // const re = /<b>Notice<\/b> \([\d]+\)<\/a>: ([^\[]+)\[([^\]]+)\]/is,
66
+ // result2 = html.match(re);
67
+ // return {
68
+ // title: result2[1],
69
+ // line: result2[2],
70
+ // };
71
+ // }
72
+ // return false;
73
+ // }
74
+ // function hasWarning(html) {
75
+ // const result = /<b>Warning<\/b> \(/is.test(html);
76
+ // if (result) {
77
+ // // Try to determine error message
78
+ // const re = /<b>Warning<\/b> \([\d]+\)<\/a>: ([^\[]+)\[([^\]]+)\]/is,
79
+ // result2 = html.match(re);
80
+ // return {
81
+ // title: result2[1],
82
+ // line: result2[2],
83
+ // };
84
+ // }
85
+ // return false;
86
+ // }
87
+ // function hasException(html) {
88
+ // let result = /An Internal Error Has Occurred/is.test(html); // 'debug' mode is off
89
+ // if (result) {
90
+ // return {
91
+ // title: 'An Internal Error Has Occurred',
92
+ // line: null,
93
+ // };
94
+ // }
95
+
96
+ // result = /Exception/ism.test(html) && /stack-trace/is.test(html); // 'debug' mode is on
97
+ // if (result) {
98
+ // // Try to determine error message
99
+ // const re = /<h1 class="header-title">(.*)<\/h1>/is, // this is from DebugKit
100
+ // result2 = html.match(re);
101
+ // return {
102
+ // title: result2[1],
103
+ // line: result2[2],
104
+ // };
105
+ // }
106
+
107
+ // return false;
108
+ // }