@onehat/ui 0.4.37 → 0.4.39

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.4.37",
3
+ "version": "0.4.39",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -0,0 +1,27 @@
1
+ /**
2
+ * COPYRIGHT NOTICE
3
+ * This file is categorized as "Custom Source Code"
4
+ * and is subject to the terms and conditions defined in the
5
+ * "LICENSE.txt" file, which is part of this source code package.
6
+ */
7
+
8
+ import ArrayCombo from './ArrayCombo.js';
9
+ import {
10
+ METER_TYPES__HOURS,
11
+ METER_TYPES__MILES,
12
+ } from '../../../../Constants/MeterTypes.js';
13
+
14
+ const data = [
15
+ [METER_TYPES__HOURS, 'Hours'],
16
+ [METER_TYPES__MILES, 'Miles'],
17
+ ];
18
+ function MeterTypesCombo(props) {
19
+ return <ArrayCombo
20
+ reference="MeterTypeCombo"
21
+ data={data}
22
+ disableDirectEntry={true}
23
+ {...props}
24
+ />;
25
+ }
26
+
27
+ export default MeterTypesCombo;
@@ -763,8 +763,18 @@ function GridComponent(props) {
763
763
  const
764
764
  headerHeight = showHeaders ? 50 : 0,
765
765
  footerHeight = !disablePagination ? 50 : 0,
766
- height = containerHeight - headerHeight - footerHeight,
767
- rowsPerContainer = Math.floor(height / defaultRowHeight);
766
+ height = containerHeight - headerHeight - footerHeight;
767
+
768
+ const rowsPerContainer = Math.floor(height / defaultRowHeight);
769
+
770
+ // // Get the total height of all rows
771
+ // const rows = gridRef.current._listRef._scrollRef.childNodes[0].childNodes;
772
+ // let totalRowHeight = 0;
773
+ // rows.forEach((row) => {
774
+ // totalRowHeight += row.getBoundingClientRect().height;
775
+ // });
776
+ // const rowsPerContainer = Math.floor(height / (totalRowHeight / rows.length));
777
+
768
778
  let pageSize = rowsPerContainer;
769
779
  if (showHeaders) {
770
780
  pageSize--;
@@ -83,13 +83,17 @@ function GridRow(props) {
83
83
  if (config.isHidden) {
84
84
  return null;
85
85
  }
86
- const propsToPass = columnProps[key] || {};
87
- const colStyle = {};
86
+ const
87
+ propsToPass = columnProps[key] || {},
88
+ colStyle = {};
88
89
  let colClassName = `
89
90
  GridRow-column
90
91
  p-1
91
92
  justify-center
92
93
  border-r-black-100
94
+ block
95
+ max-h-[40px]
96
+ overflow-scroll
93
97
  `;
94
98
  if (isOnlyOneVisibleColumn) {
95
99
  colClassName = ' w-full';
@@ -152,9 +156,10 @@ function GridRow(props) {
152
156
  if (config.fieldName) {
153
157
 
154
158
  if (item?.properties && item.properties[config.fieldName]) {
155
- const property = item.properties[config.fieldName];
159
+ const
160
+ property = item.properties[config.fieldName],
161
+ type = property?.viewerType?.type;
156
162
  value = property.displayValue;
157
- const type = property?.viewerType?.type;
158
163
 
159
164
  if (type) {
160
165
  const Element = getComponentFromType(type);
@@ -165,6 +170,24 @@ function GridRow(props) {
165
170
  if (config.getCellProps) {
166
171
  _.assign(elementProps, config.getCellProps(item));
167
172
  }
173
+ let elementClassName = `
174
+ GridRow-Element
175
+ self-center
176
+ text-ellipsis
177
+ px-2
178
+ py-3
179
+ block
180
+ max-h-[40px]
181
+ overflow-scroll
182
+ ${colClassName}
183
+ ${styles.GRID_CELL_CLASSNAME}
184
+ `;
185
+ if (config.className) {
186
+ elementClassName += ' ' + config.className;
187
+ }
188
+ if (type.match(/(Tag|TagEditor)$/)) {
189
+ elementClassName += ' max-h-[80px]';
190
+ }
168
191
  return <Element
169
192
  {...testProps('cell-' + config.fieldName)}
170
193
  value={value}
@@ -175,15 +198,7 @@ function GridRow(props) {
175
198
  ...colStyle,
176
199
  }}
177
200
  minimizeForRow={true}
178
- className={`
179
- GridRow-Element
180
- self-center
181
- text-ellipsis
182
- px-2
183
- py-3
184
- ${colClassName}
185
- ${styles.GRID_CELL_CLASSNAME}
186
- `}
201
+ className={elementClassName}
187
202
  numberOfLines={1}
188
203
  ellipsizeMode="head"
189
204
  {...propsToPass}
@@ -213,6 +228,22 @@ function GridRow(props) {
213
228
  if (config.getCellProps) {
214
229
  _.assign(elementProps, config.getCellProps(item));
215
230
  }
231
+ let textClassName = `
232
+ GridRow-TextNative
233
+ self-center
234
+ overflow-hidden
235
+ text-ellipsis
236
+ truncate
237
+ whitespace-nowrap
238
+ overflow-hidden
239
+ ${colClassName}
240
+ ${styles.GRID_CELL_CLASSNAME}
241
+ ${styles.GRID_CELL_PX}
242
+ ${styles.GRID_CELL_PY}
243
+ `;
244
+ if (config.className) {
245
+ textClassName += ' ' + config.className;
246
+ }
216
247
  return <TextNative
217
248
  {...testProps('cell-' + config.fieldName)}
218
249
  key={key}
@@ -222,19 +253,7 @@ function GridRow(props) {
222
253
  }}
223
254
  numberOfLines={1}
224
255
  ellipsizeMode="head"
225
- className={`
226
- GridRow-TextNative
227
- self-center
228
- overflow-hidden
229
- text-ellipsis
230
- truncate
231
- whitespace-nowrap
232
- overflow-hidden
233
- ${colClassName}
234
- ${styles.GRID_CELL_CLASSNAME}
235
- ${styles.GRID_CELL_PX}
236
- ${styles.GRID_CELL_PY}
237
- `}
256
+ className={textClassName}
238
257
  {...elementProps}
239
258
  {...propsToPass}
240
259
  >{value}</TextNative>;
@@ -0,0 +1,23 @@
1
+ import {
2
+ Text,
3
+ } from '@project-components/Gluestack';
4
+ import UiGlobals from '../../UiGlobals';
5
+
6
+ export default function MeterTypeText(props) {
7
+ const styles = UiGlobals.styles;
8
+
9
+ let className = `
10
+ Text
11
+ flex-1
12
+ px-3
13
+ py-2
14
+ ${styles.FORM_TEXT_CLASSNAME}
15
+ `;
16
+ if (props.className) {
17
+ className += ' ' + props.className;
18
+ }
19
+ return <Text
20
+ {...props}
21
+ className={className}
22
+ >{props.value ? 'Hours' : 'Miles'}</Text>;
23
+ };
@@ -0,0 +1,98 @@
1
+ import {
2
+ Linking,
3
+ } from 'react-native';
4
+ import {
5
+ BoxNative,
6
+ Text,
7
+ TextNative,
8
+ } from '@project-components/Gluestack';
9
+ import {
10
+ UI_MODE_WEB,
11
+ } from '../../Constants/UiModes.js';
12
+ import UiGlobals from '../../UiGlobals.js';
13
+ import withComponent from '../Hoc/withComponent.js';
14
+ import _ from 'lodash';
15
+
16
+ function TextWithLinksElement(props) {
17
+ const {
18
+ value: text,
19
+ } = props,
20
+ styles = UiGlobals.styles,
21
+ openLink = (url) => {
22
+ Linking.openURL(url);
23
+ },
24
+ extractLinks = (text) => {
25
+
26
+ if (_.isNil(text) || _.isEmpty(text)) {
27
+ return [];
28
+ }
29
+ const
30
+ regex = /\b(?:https?|ftp):\/\/\S+/g,
31
+ links = text.match(regex) || [];
32
+
33
+ return links.map((link, ix) => ({
34
+ link,
35
+ key: `link_${ix}`,
36
+ }));
37
+ },
38
+ renderTextWithLinks = () => {
39
+ const links = extractLinks(text);
40
+ let modifiedText = text;
41
+
42
+ if (_.isNil(modifiedText) || _.isEmpty(modifiedText)) {
43
+ return null;
44
+ }
45
+
46
+ links.forEach(({ link, key }) => {
47
+ modifiedText = modifiedText.replace(link, key);
48
+ });
49
+
50
+ const
51
+ textClassName = `
52
+ TextWithLinks-Text
53
+ text-base
54
+ overflow-hidden
55
+ `,
56
+ textSegments = modifiedText.split(/(link_\d+)/);
57
+ if (textSegments.length === 1) {
58
+ return <Text className={textClassName}>{modifiedText}</Text>;
59
+ }
60
+
61
+ return textSegments.map((segment, ix) => {
62
+ const foundLink = links.find(({ key }) => segment === key);
63
+ let ret = <Text key={ix} className={textClassName}>{segment}</Text>;
64
+
65
+ if (foundLink) {
66
+ ret = <TextNative
67
+ key={foundLink.key}
68
+ className={`
69
+ text-blue-600
70
+ ${textClassName}
71
+ `}
72
+ onPress={() => openLink(foundLink.link)}
73
+ >{foundLink.link}</TextNative>;
74
+ }
75
+ return ret;
76
+ });
77
+ };
78
+
79
+ const elementProps = {};
80
+ if (UiGlobals.mode === UI_MODE_WEB) {
81
+ elementProps.textOverflow = 'ellipsis';
82
+ }
83
+ let className = `
84
+ overflow-auto
85
+ min-h-[40px]
86
+ px-3
87
+ py-2
88
+ `;
89
+ if (props.className) {
90
+ className += ` ${props.className}`;
91
+ }
92
+ return <BoxNative
93
+ className={className}
94
+ {...props}
95
+ >{renderTextWithLinks()}</BoxNative>;
96
+ };
97
+
98
+ export default withComponent(TextWithLinksElement);
@@ -218,6 +218,8 @@ import Input from './Form/Field/Input.js';
218
218
  import IntervalsCombo from './Form/Field/Combo/IntervalsCombo.js';
219
219
  import Json from './Form/Field/Json.js';
220
220
  import Label from './Form/Label.js';
221
+ import MeterTypesCombo from './Form/Field/Combo/MeterTypesCombo.js';
222
+ import MeterTypeText from './Viewer/MeterTypeText.js';
221
223
  import MonthsCombo from './Form/Field/Combo/MonthsCombo.js';
222
224
  import Number from './Form/Field/Number.js';
223
225
  import NumberRange from './Filter/NumberRange.js';
@@ -231,6 +233,7 @@ import TabPanel from './Panel/TabPanel.js';
231
233
  import Tag from './Form/Field/Tag/Tag.js';
232
234
  import TextArea from './Form/Field/TextArea.js';
233
235
  import Text from './Form/Field/Text.js';
236
+ import TextWithLinks from './Viewer/TextWithLinks.js';
234
237
  import TimezonesCombo from './Form/Field/Combo/TimezonesCombo.js';
235
238
  import Toggle from './Form/Field/Toggle.js';
236
239
  import Toolbar from './Toolbar/Toolbar.js';
@@ -458,6 +461,8 @@ const components = {
458
461
  IntervalsCombo,
459
462
  Json,
460
463
  Label,
464
+ MeterTypesCombo,
465
+ MeterTypeText,
461
466
  MonthsCombo,
462
467
  Number,
463
468
  NumberRange,
@@ -471,6 +476,7 @@ const components = {
471
476
  Tag,
472
477
  Text,
473
478
  TextArea,
479
+ TextWithLinks,
474
480
  TimezonesCombo,
475
481
  Toggle,
476
482
  Toolbar,
@@ -0,0 +1,2 @@
1
+ export const METER_TYPES__HOURS = 1;
2
+ export const METER_TYPES__MILES = 2;