@onehat/ui 0.3.58 → 0.3.60

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,8 @@
1
- import { useState, } from 'react';
1
+ import { useState, useRef, } from 'react';
2
2
  import {
3
3
  Column,
4
4
  Modal,
5
5
  Row,
6
- Text,
7
6
  } from 'native-base';
8
7
  import {
9
8
  EDITOR_TYPE__WINDOWED,
@@ -12,49 +11,11 @@ import withAlert from '../../../Hoc/withAlert.js';
12
11
  import withComponent from '../../../Hoc/withComponent.js';
13
12
  import withData from '../../../Hoc/withData.js';
14
13
  import withValue from '../../../Hoc/withValue.js';
15
- import IconButton from '../../../Buttons/IconButton.js';
16
- import Eye from '../../../Icons/Eye.js';
17
- import Xmark from '../../../Icons/Xmark.js';
14
+ import ValueBox from './ValueBox.js';
18
15
  import Combo, { ComboEditor } from '../Combo/Combo.js';
19
16
  import _ from 'lodash';
20
17
 
21
18
 
22
- function ValueBox(props) {
23
- const {
24
- text,
25
- onView,
26
- onDelete,
27
- } = props;
28
- return <Row
29
- borderWidth={1}
30
- borderColor="trueGray.400"
31
- borderRadius="md"
32
- mr={1}
33
- bg="trueGray.200"
34
- alignItems="center"
35
- >
36
- <IconButton
37
- _icon={{
38
- as: Eye,
39
- color: 'trueGray.600',
40
- size: 'sm',
41
- }}
42
- onPress={onView}
43
- h="100%"
44
- />
45
- <Text color="trueGray.600" mr={onDelete ? 0 : 2}>{text}</Text>
46
- {onDelete &&
47
- <IconButton
48
- _icon={{
49
- as: Xmark,
50
- color: 'trueGray.600',
51
- size: 'sm',
52
- }}
53
- onPress={onDelete}
54
- h="100%"
55
- />}
56
- </Row>;
57
- }
58
19
 
59
20
  function TagComponent(props) {
60
21
 
@@ -67,6 +28,9 @@ function TagComponent(props) {
67
28
  // parent Form
68
29
  onChangeValue,
69
30
 
31
+ // withAlert
32
+ alert,
33
+
70
34
  // withComponent
71
35
  self,
72
36
 
@@ -75,8 +39,15 @@ function TagComponent(props) {
75
39
  setValue,
76
40
  ...propsToPass // break connection between Tag and Combo props
77
41
  } = props,
42
+ ignoreNextComboValueChangeRef = useRef(false),
78
43
  [isViewerShown, setIsViewerShown] = useState(false),
79
44
  [viewerSelection, setViewerSelection] = useState(false),
45
+ getIgnoreNextComboValueChange = () => {
46
+ return ignoreNextComboValueChangeRef.current;
47
+ },
48
+ setIgnoreNextComboValueChange = (bool) => {
49
+ ignoreNextComboValueChangeRef.current = bool;
50
+ },
80
51
  onViewerClose = () => setIsViewerShown(false),
81
52
  onView = async (item, e) => {
82
53
  const
@@ -101,27 +72,63 @@ function TagComponent(props) {
101
72
  setViewerSelection([record]);
102
73
  setIsViewerShown(true);
103
74
  },
104
- onAdd = (item, e) => {
75
+ clearComboValue = () => {
76
+ setIgnoreNextComboValueChange(true); // we're clearing out the value of the underlying Combo, so ignore it when this combo submits the new value change
77
+ self.children.combo.clear();
78
+ },
79
+ onChangeComboValue = (comboValue) => {
80
+ if (getIgnoreNextComboValueChange()) {
81
+ setIgnoreNextComboValueChange(false);
82
+ return;
83
+ }
84
+
105
85
  // make sure value doesn't already exist
106
86
  let exists = false;
107
87
  _.each(value, (val) => {
108
- if (val.id === item.getId()) {
88
+ if (val.id === comboValue) {
109
89
  exists = true;
110
90
  return false; // break
111
91
  }
112
92
  });
113
93
  if (exists) {
94
+ clearComboValue();
114
95
  alert('Value already exists!');
115
96
  return;
116
97
  }
117
98
 
99
+ // The value we get from combo is a simple int
100
+ // Convert this to id and displayValue from either Repository or data array.
101
+ const
102
+ Repository = props.Repository,
103
+ data = props.data,
104
+ idIx = props.idIx,
105
+ displayIx = props.displayIx,
106
+ id = comboValue;
107
+ let item,
108
+ displayValue;
109
+ if (Repository) {
110
+ item = Repository.getById(id);
111
+ if (!item) {
112
+ throw Error('item not found');
113
+ }
114
+ displayValue = item.displayValue;
115
+ } else {
116
+ item = _.find(data, (datum) => datum[idIx] === id);
117
+ if (!item) {
118
+ throw Error('item not found');
119
+ }
120
+ displayValue = item[displayIx];
121
+ }
122
+
123
+
118
124
  // add new value
119
125
  const newValue = _.clone(value); // so we trigger a re-render
120
126
  newValue.push({
121
- id: item.getId(),
122
- text: item.getDisplayValue(),
127
+ id,
128
+ text: displayValue,
123
129
  })
124
130
  setValue(newValue);
131
+ clearComboValue();
125
132
  },
126
133
  onDelete = (val) => {
127
134
  // Remove from value array
@@ -174,7 +181,9 @@ function TagComponent(props) {
174
181
  <WhichCombo
175
182
  Repository={props.Repository}
176
183
  Editor={props.Editor}
177
- onRowPress={onAdd}
184
+ onChangeValue={onChangeComboValue}
185
+ parent={self}
186
+ reference="combo"
178
187
  />}
179
188
  </Column>
180
189
  {isViewerShown &&
@@ -0,0 +1,45 @@
1
+ import {
2
+ Row,
3
+ Text,
4
+ } from 'native-base';
5
+ import IconButton from '../../../Buttons/IconButton.js';
6
+ import Eye from '../../../Icons/Eye.js';
7
+ import Xmark from '../../../Icons/Xmark.js';
8
+ import _ from 'lodash';
9
+
10
+ export default function ValueBox(props) {
11
+ const {
12
+ text,
13
+ onView,
14
+ onDelete,
15
+ } = props;
16
+ return <Row
17
+ borderWidth={1}
18
+ borderColor="trueGray.400"
19
+ borderRadius="md"
20
+ mr={1}
21
+ bg="trueGray.200"
22
+ alignItems="center"
23
+ >
24
+ <IconButton
25
+ _icon={{
26
+ as: Eye,
27
+ color: 'trueGray.600',
28
+ size: 'sm',
29
+ }}
30
+ onPress={onView}
31
+ h="100%"
32
+ />
33
+ <Text color="trueGray.600" mr={onDelete ? 0 : 2}>{text}</Text>
34
+ {onDelete &&
35
+ <IconButton
36
+ _icon={{
37
+ as: Xmark,
38
+ color: 'trueGray.600',
39
+ size: 'sm',
40
+ }}
41
+ onPress={onDelete}
42
+ h="100%"
43
+ />}
44
+ </Row>;
45
+ }
@@ -71,6 +71,7 @@ function Form(props) {
71
71
  footerProps = {},
72
72
  buttonGroupProps = {}, // buttons in footer
73
73
  checkIsEditingDisabled = true,
74
+ disableLabels = false,
74
75
  onBack,
75
76
  onReset,
76
77
  onViewMode,
@@ -295,6 +296,9 @@ function Form(props) {
295
296
  if (isHidden) {
296
297
  return null;
297
298
  }
299
+ if (type === 'DisplayField') {
300
+ isEditable = false;
301
+ }
298
302
  const propertyDef = name && Repository?.getSchema().getPropertyDefinition(name);
299
303
  if (!useAdditionalEditButtons) {
300
304
  item = _.omit(item, 'additionalEditButtons');
@@ -322,17 +326,21 @@ function Form(props) {
322
326
  type = 'Text';
323
327
  }
324
328
  }
329
+ const isCombo = type?.match && type.match(/Combo/);
325
330
  if (item.hasOwnProperty('autoLoad')) {
326
331
  editorTypeProps.autoLoad = item.autoLoad;
327
332
  } else {
328
- if (type?.match && type.match(/Combo$/) && Repository?.isRemote && !Repository?.isLoaded) {
333
+ if (isCombo && Repository?.isRemote && !Repository?.isLoaded) {
329
334
  editorTypeProps.autoLoad = true;
330
335
  }
331
336
  }
337
+ if (isCombo && _.isNil(propsToPass.showXButton)) {
338
+ editorTypeProps.showXButton = true;
339
+ }
332
340
  const Element = getComponentFromType(type);
333
341
  let children;
334
-
335
- if (inArray(type, ['Column', 'FieldSet'])) {
342
+
343
+ if (inArray(type, ['Column', 'Row', 'FieldSet'])) {
336
344
  if (_.isEmpty(items)) {
337
345
  return null;
338
346
  }
@@ -353,6 +361,9 @@ function Form(props) {
353
361
  }
354
362
  propsToPass.pl = 3;
355
363
  }
364
+ if (type === 'Row') {
365
+ propsToPass.w = '100%';
366
+ }
356
367
  const itemDefaults = item.defaults;
357
368
  children = _.map(items, (item, ix) => {
358
369
  return buildFromItem(item, ix, itemDefaults);
@@ -372,7 +383,7 @@ function Form(props) {
372
383
  reference={name}
373
384
  {...propsToPass}
374
385
  />;
375
- if (label) {
386
+ if (!disableLabels && label) {
376
387
  const labelProps = {};
377
388
  if (defaults?.labelWidth) {
378
389
  labelProps.w = defaults.labelWidth;
@@ -479,19 +490,24 @@ function Form(props) {
479
490
  </Row>;
480
491
  }
481
492
 
482
- if (label && editorType !== EDITOR_TYPE__INLINE) {
493
+ let requiredIndicator = null;
494
+ if (propertyDef?.validator?.spec && !propertyDef.validator.spec.optional) {
495
+ requiredIndicator = <Text color="#f00" fontSize="30px" pr={1}>*</Text>;
496
+ }
497
+ if (!disableLabels && label && editorType !== EDITOR_TYPE__INLINE) {
483
498
  const labelProps = {};
484
499
  if (defaults?.labelWidth) {
485
500
  labelProps.w = defaults.labelWidth;
486
501
  }
487
- let requiredIndicator = null;
488
- if (propertyDef?.validator?.spec && !propertyDef.validator.spec.optional) {
489
- requiredIndicator = <Text color="#f00" pr={1}>*</Text>;
490
- }
491
502
  element = <Row w="100%" py={1}>
492
503
  <Label {...labelProps}>{requiredIndicator}{label}</Label>
493
504
  {element}
494
505
  </Row>;
506
+ } else if (disableLabels && requiredIndicator) {
507
+ element = <Row w="100%" py={1}>
508
+ {requiredIndicator}
509
+ {element}
510
+ </Row>;
495
511
  }
496
512
 
497
513
  const dirtyIcon = isDirty ? <Icon as={Pencil} size="2xs" color="trueGray.300" position="absolute" top="2px" left="2px" /> : null;
@@ -736,8 +752,7 @@ function Form(props) {
736
752
  }
737
753
 
738
754
  return <Column {...sizeProps} onLayout={onLayoutDecorated} ref={formRef}>
739
- {containerWidth && <>
740
-
755
+ {!!containerWidth && <>
741
756
  {editorType === EDITOR_TYPE__INLINE &&
742
757
  <ScrollView
743
758
  horizontal={true}
@@ -779,7 +794,12 @@ function Form(props) {
779
794
  }
780
795
  reset();
781
796
  }}
782
- icon={<Rotate color="#fff" />}
797
+ icon={Rotate}
798
+ _icon={{
799
+ color: !formState.isDirty ? 'trueGray.400' : '#000',
800
+ }}
801
+ isDisabled={!formState.isDirty}
802
+ mr={2}
783
803
  />}
784
804
 
785
805
  {showCancelBtn &&
@@ -5,6 +5,7 @@ import {
5
5
  Pressable,
6
6
  Icon,
7
7
  Row,
8
+ ScrollView,
8
9
  Text,
9
10
  } from 'native-base';
10
11
  import {
@@ -97,7 +98,7 @@ function GridComponent(props) {
97
98
  additionalToolbarButtons = [],
98
99
  h,
99
100
  flex,
100
- bg,
101
+ bg = '#fff',
101
102
 
102
103
  // withComponent
103
104
  self,
@@ -177,8 +178,8 @@ function GridComponent(props) {
177
178
  }
178
179
  const
179
180
  {
180
- shiftKey,
181
- metaKey,
181
+ shiftKey = false,
182
+ metaKey = false,
182
183
  } = e;
183
184
  let allowToggle = allowToggleSelection;
184
185
  if (metaKey) {
@@ -277,24 +278,31 @@ function GridComponent(props) {
277
278
  if (isHeaderRow || isDragMode) {
278
279
  return
279
280
  }
280
- switch (e.detail) {
281
- case 1: // single click
282
- onRowClick(item, e); // sets selection
283
- if (onEditorRowClick) {
284
- onEditorRowClick(item, index, e);
285
- }
286
- break;
287
- case 2: // double click
288
- if (!isSelected) { // If a row was already selected when double-clicked, the first click will deselect it,
289
- onRowClick(item, e); // so reselect it
290
- }
291
- if (onEdit) {
292
- onEdit();
293
- }
294
- break;
295
- case 3: // triple click
296
- break;
297
- default:
281
+ if (CURRENT_MODE === UI_MODE_WEB) {
282
+ switch (e.detail) {
283
+ case 1: // single click
284
+ onRowClick(item, e); // sets selection
285
+ if (onEditorRowClick) {
286
+ onEditorRowClick(item, index, e);
287
+ }
288
+ break;
289
+ case 2: // double click
290
+ if (!isSelected) { // If a row was already selected when double-clicked, the first click will deselect it,
291
+ onRowClick(item, e); // so reselect it
292
+ }
293
+ if (onEdit) {
294
+ onEdit();
295
+ }
296
+ break;
297
+ case 3: // triple click
298
+ break;
299
+ default:
300
+ }
301
+ } else if (CURRENT_MODE === UI_MODE_REACT_NATIVE) {
302
+ onRowClick(item, e); // sets selection
303
+ if (onEditorRowClick) {
304
+ onEditorRowClick(item, index, e);
305
+ }
298
306
  }
299
307
  }}
300
308
  onLongPress={(e) => {
@@ -877,43 +885,40 @@ function GridComponent(props) {
877
885
  deselectAll();
878
886
  }
879
887
  }}>
880
- {!entities?.length ? <NoRecordsFound text={noneFoundText} onRefresh={onRefresh} /> :
881
- <FlatList
882
- ref={gridRef}
883
- // ListHeaderComponent={listHeaderComponent}
884
- // ListFooterComponent={listFooterComponent}
885
- scrollEnabled={true}
886
- nestedScrollEnabled={true}
887
- contentContainerStyle={{
888
- overflow: 'auto',
889
- borderWidth: isDragMode ? styles.REORDER_BORDER_WIDTH : 0,
890
- borderColor: isDragMode ? styles.REORDER_BORDER_COLOR : null,
891
- borderStyle: styles.REORDER_BORDER_STYLE,
892
- flex: 1,
893
- }}
894
- refreshing={isLoading}
895
- onRefresh={pullToRefresh ? onRefresh : null}
896
- progressViewOffset={100}
897
- data={rowData}
898
- keyExtractor={(item) => {
899
- let id;
900
- if (item.id) {
901
- id = item.id;
902
- } else if (fields) {
903
- id = item[idIx];
904
- }
905
- return String(id);
906
- }}
907
- // getItemLayout={(data, index) => ( // an optional optimization that allows skipping the measurement of dynamic content if you know the size (height or width) of items ahead of time. getItemLayout is efficient if you have fixed size items
908
- // {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}
909
- // )}
910
- // numColumns={1}
911
- initialNumToRender={initialNumToRender}
912
- initialScrollIndex={0}
913
- renderItem={renderRow}
914
- bg="trueGray.100"
915
- {...flatListProps}
916
- />}
888
+ {!entities?.length ?
889
+ <NoRecordsFound text={noneFoundText} onRefresh={onRefresh} /> :
890
+ <ScrollView flex={1} w="100%">
891
+ <FlatList
892
+ ref={gridRef}
893
+ scrollEnabled={false}
894
+ nestedScrollEnabled={true}
895
+ contentContainerStyle={{
896
+ overflow: 'auto',
897
+ borderWidth: isDragMode ? styles.REORDER_BORDER_WIDTH : 0,
898
+ borderColor: isDragMode ? styles.REORDER_BORDER_COLOR : null,
899
+ borderStyle: styles.REORDER_BORDER_STYLE,
900
+ flex: 1,
901
+ }}
902
+ refreshing={isLoading}
903
+ onRefresh={pullToRefresh ? onRefresh : null}
904
+ progressViewOffset={100}
905
+ data={rowData}
906
+ keyExtractor={(item) => {
907
+ let id;
908
+ if (item.id) {
909
+ id = item.id;
910
+ } else if (fields) {
911
+ id = item[idIx];
912
+ }
913
+ return String(id);
914
+ }}
915
+ initialNumToRender={initialNumToRender}
916
+ initialScrollIndex={0}
917
+ renderItem={renderRow}
918
+ bg="trueGray.100"
919
+ {...flatListProps}
920
+ />
921
+ </ScrollView>}
917
922
  </Column>
918
923
 
919
924
  {listFooterComponent}
@@ -146,11 +146,13 @@ export default function GridRow(props) {
146
146
  if (_.isFunction(value)) {
147
147
  return value(key);
148
148
  }
149
-
149
+ const elementProps = {};
150
+ if (UiGlobals.mode === UI_MODE_WEB) {
151
+ elementProps.textOverflow = 'ellipsis';
152
+ }
150
153
  return <Text
151
154
  key={key}
152
155
  overflow="hidden"
153
- textOverflow="ellipsis"
154
156
  alignSelf="center"
155
157
  style={{
156
158
  userSelect: 'none',
@@ -160,6 +162,7 @@ export default function GridRow(props) {
160
162
  py={styles.GRID_CELL_PY}
161
163
  numberOfLines={1}
162
164
  ellipsizeMode="head"
165
+ {...elementProps}
163
166
  {...propsToPass}
164
167
  >{value}</Text>;
165
168
  });
@@ -26,6 +26,8 @@ export default function NoRecordsFound(props) {
26
26
  style: {
27
27
  fontSize: 16,
28
28
  },
29
+ color: 'trueGray.400',
30
+ mr: 1,
29
31
  }}
30
32
  onPress={onRefresh}
31
33
  variant="ghost"
@@ -10,6 +10,7 @@ import {
10
10
  } from 'native-base';
11
11
  import {
12
12
  ALERT_MODE_OK,
13
+ ALERT_MODE_YES,
13
14
  ALERT_MODE_YES_NO,
14
15
  ALERT_MODE_CUSTOM,
15
16
  } from '../../Constants/Alert.js';
@@ -27,6 +28,7 @@ export default function withAlert(WrappedComponent) {
27
28
  [isAlertShown, setIsAlertShown] = useState(false),
28
29
  [title, setTitle] = useState(''),
29
30
  [message, setMessage] = useState(''),
31
+ [canClose, setCanClose] = useState(true),
30
32
  [includeCancel, setIncludeCancel] = useState(false),
31
33
  [okCallback, setOkCallback] = useState(),
32
34
  [yesCallback, setYesCallback] = useState(),
@@ -35,7 +37,7 @@ export default function withAlert(WrappedComponent) {
35
37
  [mode, setMode] = useState(ALERT_MODE_OK),
36
38
  autoFocusRef = useRef(null),
37
39
  cancelRef = useRef(null),
38
- onAlert = (arg1, okCallback, includeCancel = false) => {
40
+ onAlert = (arg1, okCallback, includeCancel = false, canClose = true) => {
39
41
  clearAll();
40
42
  if (_.isString(arg1)) {
41
43
  setMode(ALERT_MODE_OK);
@@ -43,6 +45,7 @@ export default function withAlert(WrappedComponent) {
43
45
  setMessage(arg1);
44
46
  setOkCallback(() => okCallback);
45
47
  setIncludeCancel(includeCancel);
48
+ setCanClose(canClose);
46
49
  } else if (_.isPlainObject(arg1)) {
47
50
  // custom
48
51
  const {
@@ -50,12 +53,14 @@ export default function withAlert(WrappedComponent) {
50
53
  message,
51
54
  buttons,
52
55
  includeCancel,
56
+ canClose,
53
57
  } = arg1;
54
58
  setMode(ALERT_MODE_CUSTOM);
55
59
  setTitle(title);
56
60
  setMessage(message);
57
61
  setCustomButtons(buttons);
58
62
  setIncludeCancel(includeCancel);
63
+ setCanClose(canClose);
59
64
  }
60
65
  showAlert();
61
66
  },
@@ -66,6 +71,7 @@ export default function withAlert(WrappedComponent) {
66
71
  setMessage(message);
67
72
  setIncludeCancel(includeCancel);
68
73
  setYesCallback(() => callback);
74
+ setNoCallback(null);
69
75
  showAlert();
70
76
  },
71
77
  onCancel = () => {
@@ -123,6 +129,15 @@ export default function withAlert(WrappedComponent) {
123
129
  color="#fff"
124
130
  >OK</Button>);
125
131
  break;
132
+ case ALERT_MODE_YES:
133
+ buttons.push(<Button
134
+ key="yesBtn"
135
+ ref={autoFocusRef}
136
+ onPress={onYes}
137
+ color="#fff"
138
+ colorScheme="danger"
139
+ >Yes</Button>);
140
+ break;
126
141
  case ALERT_MODE_YES_NO:
127
142
  buttons.push(<Button
128
143
  key="noBtn"
@@ -161,7 +176,7 @@ export default function withAlert(WrappedComponent) {
161
176
  onClose={() => setIsAlertShown(false)}
162
177
  >
163
178
  <AlertDialog.Content>
164
- <AlertDialog.CloseButton />
179
+ {canClose && <AlertDialog.CloseButton />}
165
180
  <AlertDialog.Header>{title}</AlertDialog.Header>
166
181
  <AlertDialog.Body>
167
182
  <Row>
@@ -536,7 +536,9 @@ export default function withFilters(WrappedComponent) {
536
536
  },
537
537
  ]}
538
538
  onCancel={(e) => {
539
- // Just close the modal
539
+ setIsFilterSelectorShown(false);
540
+ }}
541
+ onClose={(e) => {
540
542
  setIsFilterSelectorShown(false);
541
543
  }}
542
544
  onSave={(data, e) => {
@@ -28,6 +28,9 @@ export default function withValue(WrappedComponent) {
28
28
  isValueAlwaysArray = false,
29
29
  isValueAsStringifiedJson = false,
30
30
 
31
+ // withComponent
32
+ self,
33
+
31
34
  // withData
32
35
  Repository,
33
36
  idIx,
@@ -120,6 +123,11 @@ export default function withValue(WrappedComponent) {
120
123
  }, []);
121
124
  }
122
125
 
126
+ if (self) {
127
+ self.setValue = setValue;
128
+ self.value = getLocalValue();
129
+ }
130
+
123
131
 
124
132
  // Convert localValue to normal JS primitives for field components
125
133
  let convertedValue = getLocalValue();
@@ -0,0 +1,14 @@
1
+ // Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.
2
+ import * as React from "react"
3
+ import Svg, { Path } from "react-native-svg"
4
+ import { Icon } from 'native-base';
5
+
6
+ function SvgComponent(props) {
7
+ return (
8
+ <Icon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" {...props}>
9
+ <Path d="M512 32H160c-35.35 0-64 28.65-64 64v224c0 35.35 28.65 64 64 64h352c35.35 0 64-28.65 64-64V96c0-35.35-28.7-64-64-64zm16 288c0 8.822-7.178 16-16 16h-16L386.7 175.1c-3-4.4-8-7.1-13.4-7.1a15.978 15.978 0 00-13.31 7.125l-62.74 94.11L274.9 238.6c-3-4.2-7.8-6.6-12.9-6.6a16.007 16.007 0 00-12.93 6.574L176 336h-16c-8.822 0-16-7.178-16-16V96c0-8.822 7.178-16 16-16h352c8.822 0 16 7.178 16 16v224zM224 112c-17.67 0-32 14.33-32 32s14.33 32 32 32c17.68 0 32-14.33 32-32s-14.3-32-32-32zm232 368H120C53.83 480 0 426.2 0 360V120c0-13.2 10.75-24 24-24s24 10.8 24 24v240c0 39.7 32.3 72 72 72h336c13.25 0 24 10.75 24 24s-10.7 24-24 24z" />
10
+ </Icon>
11
+ )
12
+ }
13
+
14
+ export default SvgComponent
@@ -1,3 +1,4 @@
1
1
  export const ALERT_MODE_OK = 'ALERT_MODE_OK';
2
+ export const ALERT_MODE_YES = 'ALERT_MODE_YES';
2
3
  export const ALERT_MODE_YES_NO = 'ALERT_MODE_YES_NO';
3
4
  export const ALERT_MODE_CUSTOM = 'ALERT_MODE_CUSTOM';
@@ -0,0 +1,3 @@
1
+ export default function delay(ms = 1000) {
2
+ return new Promise(resolve => setTimeout(resolve, ms));
3
+ }
@@ -0,0 +1,18 @@
1
+ export default function isVideo(mimetype) {
2
+ switch(mimetype) {
3
+ case 'video/quicktime':
4
+ case 'video/mp4':
5
+ case 'video/mpeg':
6
+ case 'video/ogg':
7
+ case 'video/webm':
8
+ case 'video/mp2t':
9
+ case 'video/3gpp':
10
+ case 'video/3gpp2':
11
+ case 'video/x-msvideo':
12
+ case 'video/x-ms-wmv':
13
+ case 'video/x-flv':
14
+ case 'application/x-mpegURL':
15
+ return true;
16
+ }
17
+ return false;
18
+ }