@onehat/ui 0.3.36 → 0.3.37
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 +1 -1
- package/src/Components/Form/Form.js +190 -171
- package/src/Components/Grid/Grid.js +40 -21
- package/src/Components/Hoc/withEditor.js +5 -1
- package/src/Components/Hoc/withSideEditor.js +4 -0
- package/src/Components/Hoc/withWindowedEditor.js +4 -0
- package/src/Components/Icons/Excel.js +14 -0
- package/src/Components/Report/Report.js +124 -0
- package/src/Components/Viewer/Viewer.js +88 -83
- package/src/Functions/buildAdditionalButtons.js +43 -0
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect, useState, useRef, isValidElement, } from 'react';
|
|
2
|
+
import { View, } from 'react-native';
|
|
2
3
|
import {
|
|
3
4
|
Box,
|
|
4
5
|
Column,
|
|
@@ -28,6 +29,7 @@ import withEditor from '../Hoc/withEditor.js';
|
|
|
28
29
|
import withPdfButton from '../Hoc/withPdfButton.js';
|
|
29
30
|
import inArray from '../../Functions/inArray.js';
|
|
30
31
|
import getComponentFromType from '../../Functions/getComponentFromType.js';
|
|
32
|
+
import buildAdditionalButtons from '../../Functions/buildAdditionalButtons.js';
|
|
31
33
|
import Button from '../Buttons/Button.js';
|
|
32
34
|
import IconButton from '../Buttons/IconButton.js';
|
|
33
35
|
import AngleLeft from '../Icons/AngleLeft.js';
|
|
@@ -38,6 +40,8 @@ import Footer from '../Layout/Footer.js';
|
|
|
38
40
|
import Label from '../Form/Label.js';
|
|
39
41
|
import _ from 'lodash';
|
|
40
42
|
|
|
43
|
+
const CONTAINER_THRESHOLD = 900;
|
|
44
|
+
|
|
41
45
|
// TODO: memoize field Components
|
|
42
46
|
|
|
43
47
|
// Modes:
|
|
@@ -73,6 +77,7 @@ function Form(props) {
|
|
|
73
77
|
submitBtnLabel,
|
|
74
78
|
onSubmit,
|
|
75
79
|
additionalEditButtons,
|
|
80
|
+
additionalFooterButtons,
|
|
76
81
|
|
|
77
82
|
// sizing of outer container
|
|
78
83
|
h,
|
|
@@ -113,6 +118,7 @@ function Form(props) {
|
|
|
113
118
|
isSingle = !isMultiple, // for convenience
|
|
114
119
|
forceUpdate = useForceUpdate(),
|
|
115
120
|
[previousRecord, setPreviousRecord] = useState(record),
|
|
121
|
+
[containerWidth, setContainerWidth] = useState(),
|
|
116
122
|
initialValues = _.merge(startingValues, (record && !record.isDestroyed ? record.submitValues : {})),
|
|
117
123
|
defaultValues = isMultiple ? getNullFieldValues(initialValues, Repository) : initialValues, // when multiple entities, set all default values to null
|
|
118
124
|
{
|
|
@@ -267,9 +273,9 @@ function Form(props) {
|
|
|
267
273
|
return <Row>{elements}</Row>;
|
|
268
274
|
},
|
|
269
275
|
buildFromItems = () => {
|
|
270
|
-
return _.map(items, (item, ix) =>
|
|
276
|
+
return _.map(items, (item, ix) => buildFromItem(item, ix, columnDefaults));
|
|
271
277
|
},
|
|
272
|
-
|
|
278
|
+
buildFromItem = (item, ix, defaults) => {
|
|
273
279
|
let {
|
|
274
280
|
type,
|
|
275
281
|
title,
|
|
@@ -321,9 +327,26 @@ function Form(props) {
|
|
|
321
327
|
if (_.isEmpty(items)) {
|
|
322
328
|
return null;
|
|
323
329
|
}
|
|
330
|
+
if (type === 'Column') {
|
|
331
|
+
if (containerWidth < CONTAINER_THRESHOLD) {
|
|
332
|
+
// everything is in one column
|
|
333
|
+
if (propsToPass.hasOwnProperty('flex')) {
|
|
334
|
+
delete propsToPass.flex;
|
|
335
|
+
}
|
|
336
|
+
if (propsToPass.hasOwnProperty('width')) {
|
|
337
|
+
delete propsToPass.width;
|
|
338
|
+
}
|
|
339
|
+
if (propsToPass.hasOwnProperty('w')) {
|
|
340
|
+
delete propsToPass.w;
|
|
341
|
+
}
|
|
342
|
+
propsToPass.w = '100%';
|
|
343
|
+
propsToPass.mb = 1;
|
|
344
|
+
}
|
|
345
|
+
propsToPass.pl = 3;
|
|
346
|
+
}
|
|
324
347
|
const itemDefaults = item.defaults;
|
|
325
348
|
children = _.map(items, (item, ix) => {
|
|
326
|
-
return
|
|
349
|
+
return buildFromItem(item, ix, itemDefaults);
|
|
327
350
|
});
|
|
328
351
|
return <Element key={ix} title={title} {...itemDefaults} {...propsToPass} {...editorTypeProps}>{children}</Element>;
|
|
329
352
|
}
|
|
@@ -432,6 +455,14 @@ function Form(props) {
|
|
|
432
455
|
|
|
433
456
|
}
|
|
434
457
|
}
|
|
458
|
+
|
|
459
|
+
if (item.additionalEditButtons) {
|
|
460
|
+
element = <Row flex={1} flexWrap="wrap">
|
|
461
|
+
{element}
|
|
462
|
+
{buildAdditionalButtons(item.additionalEditButtons, self, { fieldState, formSetValue, formGetValues, formState })}
|
|
463
|
+
</Row>;
|
|
464
|
+
}
|
|
465
|
+
|
|
435
466
|
if (label && editorType !== EDITOR_TYPE__INLINE) {
|
|
436
467
|
const labelProps = {};
|
|
437
468
|
if (defaults?.labelWidth) {
|
|
@@ -485,43 +516,6 @@ function Form(props) {
|
|
|
485
516
|
}
|
|
486
517
|
return components;
|
|
487
518
|
},
|
|
488
|
-
buildAdditionalButtons = (configs) => {
|
|
489
|
-
const additionalButtons = [];
|
|
490
|
-
_.each(additionalEditButtons, (config) => {
|
|
491
|
-
const {
|
|
492
|
-
key,
|
|
493
|
-
text,
|
|
494
|
-
handler,
|
|
495
|
-
icon,
|
|
496
|
-
isDisabled,
|
|
497
|
-
color = '#fff',
|
|
498
|
-
} = config,
|
|
499
|
-
buttonProps = {};
|
|
500
|
-
if (key) {
|
|
501
|
-
buttonProps.key = key;
|
|
502
|
-
buttonProps.reference = key;
|
|
503
|
-
}
|
|
504
|
-
if (handler) {
|
|
505
|
-
buttonProps.onPress = handler;
|
|
506
|
-
}
|
|
507
|
-
if (icon) {
|
|
508
|
-
buttonProps.leftIcon = <Icon as={icon} color="#fff" size="sm" />;
|
|
509
|
-
}
|
|
510
|
-
if (isDisabled) {
|
|
511
|
-
buttonProps.isDisabled = isDisabled;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
const button = <Button
|
|
515
|
-
color={color}
|
|
516
|
-
ml={2}
|
|
517
|
-
parent={self}
|
|
518
|
-
reference={key}
|
|
519
|
-
{...buttonProps}
|
|
520
|
-
>{text}</Button>;
|
|
521
|
-
additionalButtons.push(button);
|
|
522
|
-
});
|
|
523
|
-
return additionalButtons;
|
|
524
|
-
},
|
|
525
519
|
onSubmitError = (errors, e) => {
|
|
526
520
|
debugger;
|
|
527
521
|
if (editorType === EDITOR_TYPE__INLINE) {
|
|
@@ -542,6 +536,13 @@ function Form(props) {
|
|
|
542
536
|
const values = record.submitValues;
|
|
543
537
|
reset(values);
|
|
544
538
|
}
|
|
539
|
+
},
|
|
540
|
+
onLayoutDecorated = (e) => {
|
|
541
|
+
if (onLayout) {
|
|
542
|
+
onLayout(e);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
setContainerWidth(e.nativeEvent.layout.width);
|
|
545
546
|
};
|
|
546
547
|
|
|
547
548
|
useEffect(() => {
|
|
@@ -596,148 +597,166 @@ function Form(props) {
|
|
|
596
597
|
sizeProps.maxHeight = maxHeight;
|
|
597
598
|
}
|
|
598
599
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
600
|
+
let formComponents,
|
|
601
|
+
editor,
|
|
602
|
+
additionalButtons,
|
|
603
|
+
isSaveDisabled = false,
|
|
604
|
+
isSubmitDisabled = false,
|
|
605
|
+
savingProps = {};
|
|
604
606
|
|
|
607
|
+
if (containerWidth) { // we need to render this component twice in order to get the container width. Skip this on first render
|
|
608
|
+
|
|
609
|
+
if (isSaving) {
|
|
610
|
+
savingProps.borderTopWidth = 2;
|
|
611
|
+
savingProps.borderTopColor = '#f00';
|
|
612
|
+
}
|
|
605
613
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
}
|
|
614
|
+
if (editorType === EDITOR_TYPE__INLINE) {
|
|
615
|
+
formComponents = buildFromColumnsConfig();
|
|
616
|
+
editor = <ScrollView
|
|
617
|
+
horizontal={true}
|
|
618
|
+
flex={1}
|
|
619
|
+
bg="#fff"
|
|
620
|
+
py={1}
|
|
621
|
+
borderTopWidth={3}
|
|
622
|
+
borderBottomWidth={5}
|
|
623
|
+
borderTopColor="primary.100"
|
|
624
|
+
borderBottomColor="primary.100"
|
|
625
|
+
>{formComponents}</ScrollView>;
|
|
626
|
+
// } else if (editorType === EDITOR_TYPE__PLAIN) {
|
|
627
|
+
// formComponents = buildFromItems();
|
|
628
|
+
// const formAncillaryComponents = buildAncillary();
|
|
629
|
+
// editor = <>
|
|
630
|
+
// <Column p={4}>{formComponents}</Column>
|
|
631
|
+
// <Column pt={4}>{formAncillaryComponents}</Column>
|
|
632
|
+
// </>;
|
|
633
|
+
} else {
|
|
634
|
+
formComponents = buildFromItems();
|
|
635
|
+
const formAncillaryComponents = buildAncillary();
|
|
636
|
+
editor = <ScrollView _web={{ minHeight, }} width="100%" pb={1}>
|
|
637
|
+
{containerWidth >= CONTAINER_THRESHOLD ? <Row p={4} pl={0}>{formComponents}</Row> : null}
|
|
638
|
+
{containerWidth < CONTAINER_THRESHOLD ? <Column p={4}>{formComponents}</Column> : null}
|
|
639
|
+
<Column m={2} pt={4}>{formAncillaryComponents}</Column>
|
|
640
|
+
</ScrollView>;
|
|
641
|
+
}
|
|
635
642
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
643
|
+
let editorModeF;
|
|
644
|
+
switch(editorMode) {
|
|
645
|
+
case EDITOR_MODE__VIEW:
|
|
646
|
+
editorModeF = 'View';
|
|
647
|
+
break;
|
|
648
|
+
case EDITOR_MODE__ADD:
|
|
649
|
+
editorModeF = 'Add';
|
|
650
|
+
break;
|
|
651
|
+
case EDITOR_MODE__EDIT:
|
|
652
|
+
editorModeF = isMultiple ? 'Edit Multiple' : 'Edit';
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
648
655
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
isSaveDisabled = true;
|
|
657
|
-
}
|
|
656
|
+
if (!_.isEmpty(formState.errors)) {
|
|
657
|
+
isSaveDisabled = true;
|
|
658
|
+
isSubmitDisabled = true;
|
|
659
|
+
}
|
|
660
|
+
if (_.isEmpty(formState.dirtyFields) && !record?.isRemotePhantom) {
|
|
661
|
+
isSaveDisabled = true;
|
|
662
|
+
}
|
|
658
663
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
+
if (editorType === EDITOR_TYPE__INLINE) {
|
|
665
|
+
buttonGroupProps.position = 'fixed';
|
|
666
|
+
buttonGroupProps.left = 10; // TODO: I would prefer to have this be centered, but it's a lot more complex than just making it stick to the left
|
|
667
|
+
footerProps.alignItems = 'flex-start';
|
|
668
|
+
}
|
|
664
669
|
|
|
665
|
-
|
|
670
|
+
additionalButtons = buildAdditionalButtons(additionalEditButtons);
|
|
671
|
+
}
|
|
666
672
|
|
|
667
|
-
return <Column {...sizeProps} onLayout={
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
<Button
|
|
672
|
-
key="backBtn"
|
|
673
|
-
onPress={onBack}
|
|
674
|
-
leftIcon={<Icon as={AngleLeft} color="#fff" size="sm" />}
|
|
675
|
-
color="#fff"
|
|
676
|
-
>Back</Button>}
|
|
677
|
-
{isSingle && editorMode === EDITOR_MODE__EDIT && onViewMode &&
|
|
678
|
-
<Button
|
|
679
|
-
key="viewBtn"
|
|
680
|
-
onPress={onViewMode}
|
|
681
|
-
leftIcon={<Icon as={Eye} color="#fff" size="sm" />}
|
|
682
|
-
color="#fff"
|
|
683
|
-
>To View</Button>}
|
|
684
|
-
</Row>
|
|
685
|
-
{editorMode === EDITOR_MODE__EDIT && !_.isEmpty(additionalButtons) &&
|
|
686
|
-
<Row p={4} alignItems="center" justifyContent="flex-end">
|
|
687
|
-
{additionalButtons}
|
|
688
|
-
</Row>}
|
|
689
|
-
|
|
690
|
-
{editor}
|
|
691
|
-
|
|
692
|
-
<Footer justifyContent="flex-end" {...footerProps} {...savingProps}>
|
|
693
|
-
{onDelete && editorMode === EDITOR_MODE__EDIT && isSingle &&
|
|
694
|
-
<Row flex={1} justifyContent="flex-start">
|
|
673
|
+
return <Column {...sizeProps} onLayout={onLayoutDecorated} ref={formRef}>
|
|
674
|
+
{containerWidth && <>
|
|
675
|
+
<Row px={4} pt={4} alignItems="center" justifyContent="flex-end">
|
|
676
|
+
{isSingle && editorMode === EDITOR_MODE__EDIT && onBack &&
|
|
695
677
|
<Button
|
|
696
|
-
key="
|
|
697
|
-
onPress={
|
|
698
|
-
|
|
699
|
-
_hover={{
|
|
700
|
-
bg: 'warningHover',
|
|
701
|
-
}}
|
|
678
|
+
key="backBtn"
|
|
679
|
+
onPress={onBack}
|
|
680
|
+
leftIcon={<Icon as={AngleLeft} color="#fff" size="sm" />}
|
|
702
681
|
color="#fff"
|
|
703
|
-
>
|
|
682
|
+
>Back</Button>}
|
|
683
|
+
{isSingle && editorMode === EDITOR_MODE__EDIT && onViewMode &&
|
|
684
|
+
<Button
|
|
685
|
+
key="viewBtn"
|
|
686
|
+
onPress={onViewMode}
|
|
687
|
+
leftIcon={<Icon as={Eye} color="#fff" size="sm" />}
|
|
688
|
+
color="#fff"
|
|
689
|
+
>To View</Button>}
|
|
690
|
+
</Row>
|
|
691
|
+
{editorMode === EDITOR_MODE__EDIT && !_.isEmpty(additionalButtons) &&
|
|
692
|
+
<Row p={4} alignItems="center" justifyContent="flex-end" flexWrap="wrap">
|
|
693
|
+
{additionalButtons}
|
|
704
694
|
</Row>}
|
|
705
|
-
|
|
706
|
-
{
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
variant="ghost"
|
|
719
|
-
onPress={onCancel}
|
|
720
|
-
color="#fff"
|
|
721
|
-
>Cancel</Button>}
|
|
722
|
-
{!isEditorViewOnly && onSave && <Button
|
|
723
|
-
key="saveBtn"
|
|
724
|
-
onPress={(e) => handleSubmit(onSaveDecorated, onSubmitError)(e)}
|
|
725
|
-
isDisabled={isSaveDisabled}
|
|
726
|
-
color="#fff"
|
|
727
|
-
>{editorMode === EDITOR_MODE__ADD ? 'Add' : 'Save'}</Button>}
|
|
728
|
-
{onSubmit && <Button
|
|
729
|
-
key="submitBtn"
|
|
730
|
-
onPress={(e) => handleSubmit(onSubmitDecorated, onSubmitError)(e)}
|
|
731
|
-
isDisabled={isSubmitDisabled}
|
|
695
|
+
|
|
696
|
+
{editor}
|
|
697
|
+
|
|
698
|
+
<Footer justifyContent="flex-end" {...footerProps} {...savingProps}>
|
|
699
|
+
{onDelete && editorMode === EDITOR_MODE__EDIT && isSingle &&
|
|
700
|
+
<Row flex={1} justifyContent="flex-start">
|
|
701
|
+
<Button
|
|
702
|
+
key="deleteBtn"
|
|
703
|
+
onPress={onDelete}
|
|
704
|
+
bg="warning"
|
|
705
|
+
_hover={{
|
|
706
|
+
bg: 'warningHover',
|
|
707
|
+
}}
|
|
732
708
|
color="#fff"
|
|
733
|
-
>
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
709
|
+
>Delete</Button>
|
|
710
|
+
</Row>}
|
|
711
|
+
|
|
712
|
+
{!isEditorViewOnly &&
|
|
713
|
+
<IconButton
|
|
714
|
+
key="resetBtn"
|
|
715
|
+
onPress={() => {
|
|
716
|
+
if (onReset) {
|
|
717
|
+
onReset();
|
|
718
|
+
}
|
|
719
|
+
reset();
|
|
720
|
+
}}
|
|
721
|
+
icon={<Rotate color="#fff" />}
|
|
722
|
+
/>}
|
|
723
|
+
{!isEditorViewOnly && isSingle && onCancel &&
|
|
724
|
+
<Button
|
|
725
|
+
key="cancelBtn"
|
|
726
|
+
variant="ghost"
|
|
727
|
+
onPress={onCancel}
|
|
728
|
+
color="#fff"
|
|
729
|
+
>Cancel</Button>}
|
|
730
|
+
{!isEditorViewOnly && onSave &&
|
|
731
|
+
<Button
|
|
732
|
+
key="saveBtn"
|
|
733
|
+
onPress={(e) => handleSubmit(onSaveDecorated, onSubmitError)(e)}
|
|
734
|
+
isDisabled={isSaveDisabled}
|
|
735
|
+
color="#fff"
|
|
736
|
+
>{editorMode === EDITOR_MODE__ADD ? 'Add' : 'Save'}</Button>}
|
|
737
|
+
{onSubmit &&
|
|
738
|
+
<Button
|
|
739
|
+
key="submitBtn"
|
|
740
|
+
onPress={(e) => handleSubmit(onSubmitDecorated, onSubmitError)(e)}
|
|
741
|
+
isDisabled={isSubmitDisabled}
|
|
742
|
+
color="#fff"
|
|
743
|
+
>{submitBtnLabel || 'Submit'}</Button>}
|
|
744
|
+
|
|
745
|
+
{isEditorViewOnly && onClose && editorType !== EDITOR_TYPE__SIDE &&
|
|
746
|
+
<Button
|
|
747
|
+
key="closeBtn"
|
|
748
|
+
onPress={onClose}
|
|
749
|
+
color="#fff"
|
|
750
|
+
>Close</Button>}
|
|
751
|
+
|
|
752
|
+
{additionalFooterButtons && _.map(additionalFooterButtons, (props) => {
|
|
753
|
+
return <Button
|
|
754
|
+
{...props}
|
|
755
|
+
onPress={(e) => handleSubmit(props.onPress, onSubmitError)(e)}
|
|
756
|
+
>{props.text}</Button>;
|
|
757
|
+
})}
|
|
758
|
+
</Footer>
|
|
759
|
+
</>}
|
|
741
760
|
</Column>;
|
|
742
761
|
}
|
|
743
762
|
|
|
@@ -73,6 +73,7 @@ function GridComponent(props) {
|
|
|
73
73
|
},
|
|
74
74
|
flatListProps = {},
|
|
75
75
|
// enableEditors = false,
|
|
76
|
+
loadOnRender = true,
|
|
76
77
|
pullToRefresh = true,
|
|
77
78
|
hideNavColumn = true,
|
|
78
79
|
noneFoundText,
|
|
@@ -147,7 +148,9 @@ function GridComponent(props) {
|
|
|
147
148
|
forceUpdate = useForceUpdate(),
|
|
148
149
|
containerRef = useRef(),
|
|
149
150
|
gridRef = useRef(),
|
|
151
|
+
gridContainerRef = useRef(),
|
|
150
152
|
isAddingRef = useRef(),
|
|
153
|
+
[isRendered, setIsRendered] = useState(false),
|
|
151
154
|
[isReady, setIsReady] = useState(false),
|
|
152
155
|
[isLoading, setIsLoading] = useState(false),
|
|
153
156
|
[localColumnsConfig, setLocalColumnsConfigRaw] = useState([]),
|
|
@@ -620,30 +623,46 @@ function GridComponent(props) {
|
|
|
620
623
|
setDragRowSlot(null);
|
|
621
624
|
},
|
|
622
625
|
onLayout = (e) => {
|
|
623
|
-
if (disableAdjustingPageSizeToHeight || !Repository || CURRENT_MODE !== UI_MODE_WEB || !gridRef.current || isAddingRef.current) {
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
const
|
|
628
|
-
gr = gridRef.current,
|
|
629
|
-
scrollableNode = gr.getScrollableNode(),
|
|
630
|
-
scrollableNodeBoundingBox = scrollableNode.getBoundingClientRect(),
|
|
631
|
-
scrollableNodeHeight = scrollableNodeBoundingBox.height,
|
|
632
|
-
firstRow = scrollableNode.children[0].children[showHeaders ? 1: 0];
|
|
633
626
|
|
|
634
|
-
|
|
635
|
-
|
|
627
|
+
let doLoad = false;
|
|
628
|
+
if (!isRendered) {
|
|
629
|
+
setIsRendered(true);
|
|
630
|
+
if (loadOnRender && Repository && !Repository.isLoaded && !Repository.isLoading && !Repository.isAutoLoad) {
|
|
631
|
+
doLoad = true; // first time in onLayout only!
|
|
632
|
+
}
|
|
636
633
|
}
|
|
637
634
|
|
|
638
|
-
const
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
635
|
+
const adjustPageSizeToHeight = !!(disableAdjustingPageSizeToHeight || !Repository || CURRENT_MODE !== UI_MODE_WEB || !gridRef.current || isAddingRef.current);
|
|
636
|
+
if (adjustPageSizeToHeight) {
|
|
637
|
+
// this currently only works on web
|
|
638
|
+
const
|
|
639
|
+
gr = gridContainerRef.current,
|
|
640
|
+
// scrollableNode = gr.getScrollableNode(),
|
|
641
|
+
// scrollableNodeBoundingBox = scrollableNode.getBoundingClientRect(),
|
|
642
|
+
// scrollableNodeHeight = scrollableNodeBoundingBox.height,
|
|
643
|
+
// firstRow = scrollableNode.children[0].children[showHeaders ? 1: 0];
|
|
644
|
+
height = gr.getBoundingClientRect().height;
|
|
645
|
+
// IDEALLY, we want the grid to load right away with appropriate limits.
|
|
646
|
+
// Currently, it's been loading once, then doing layout then loading again with correct limit.
|
|
647
|
+
// How do we get the right limit before it renders??
|
|
648
|
+
// Estimate based on (container height -header -footer) / avg height? This won't work for rows that exceed the avg height.
|
|
649
|
+
// Maybe we do that avg at first, and if it exceeds, then we do another query to lose the later ones, which are hidden anyway.
|
|
650
|
+
// It'll only do that once. Better to hide the offscreen ones, than to show gap at first, and later fill it
|
|
651
|
+
// if (firstRow) { // TODO: this assumes there is a row there already, which is wrong!
|
|
652
|
+
// const
|
|
653
|
+
// rowHeight = firstRow.getBoundingClientRect().height,
|
|
654
|
+
// rowsPerContainer = Math.floor(scrollableNodeHeight / rowHeight);
|
|
655
|
+
// let pageSize = rowsPerContainer;
|
|
656
|
+
// if (showHeaders) {
|
|
657
|
+
// pageSize--;
|
|
658
|
+
// }
|
|
659
|
+
// if (pageSize !== Repository.pageSize) {
|
|
660
|
+
// Repository.setPageSize(pageSize);
|
|
661
|
+
// }
|
|
662
|
+
// }
|
|
644
663
|
}
|
|
645
|
-
if (
|
|
646
|
-
Repository.
|
|
664
|
+
if (doLoad) {
|
|
665
|
+
Repository.load();
|
|
647
666
|
}
|
|
648
667
|
},
|
|
649
668
|
debouncedOnLayout = useCallback(_.debounce(onLayout, 500), []);
|
|
@@ -827,7 +846,7 @@ function GridComponent(props) {
|
|
|
827
846
|
>
|
|
828
847
|
{topToolbar}
|
|
829
848
|
|
|
830
|
-
<Column w="100%" flex={1} minHeight={40} borderTopWidth={isLoading ? 2 : 1} borderTopColor={isLoading ? '#f00' : 'trueGray.300'} onClick={() => {
|
|
849
|
+
<Column ref={gridContainerRef} w="100%" flex={1} minHeight={40} borderTopWidth={isLoading ? 2 : 1} borderTopColor={isLoading ? '#f00' : 'trueGray.300'} onClick={() => {
|
|
831
850
|
if (!isDragMode && !isInlineEditorShown) {
|
|
832
851
|
deselectAll();
|
|
833
852
|
}
|
|
@@ -138,7 +138,11 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
138
138
|
setEditorMode(EDITOR_MODE__EDIT);
|
|
139
139
|
setIsEditorShown(true);
|
|
140
140
|
},
|
|
141
|
-
onDelete = async (
|
|
141
|
+
onDelete = async (args) => {
|
|
142
|
+
let cb = null;
|
|
143
|
+
if (_.isFunction(args)) {
|
|
144
|
+
cb = args;
|
|
145
|
+
}
|
|
142
146
|
if (_.isEmpty(selection) || (_.isArray(selection) && (selection.length > 1 || selection[0]?.isDestroyed))) {
|
|
143
147
|
return;
|
|
144
148
|
}
|
|
@@ -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 384 512" {...props}>
|
|
9
|
+
<Path d="M64 0C28.7 0 0 28.7 0 64v384c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zm192 0v128h128L256 0zM155.7 250.2l36.3 51.9 36.3-51.9c7.6-10.9 22.6-13.5 33.4-5.9s13.5 22.6 5.9 33.4L221.3 344l46.4 66.2c7.6 10.9 5 25.8-5.9 33.4s-25.8 5-33.4-5.9L192 385.8l-36.3 51.9c-7.6 10.9-22.6 13.5-33.4 5.9s-13.5-22.6-5.9-33.4l46.3-66.2-46.4-66.2c-7.6-10.9-5-25.8 5.9-33.4s25.8-5 33.4 5.9z" />
|
|
10
|
+
</Icon>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default SvgComponent
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Column,
|
|
4
|
+
Icon,
|
|
5
|
+
Row,
|
|
6
|
+
Text,
|
|
7
|
+
} from 'native-base';
|
|
8
|
+
import { EDITOR_TYPE__PLAIN } from '../../Constants/Editor';
|
|
9
|
+
import {
|
|
10
|
+
UI_MODE_WEB,
|
|
11
|
+
CURRENT_MODE,
|
|
12
|
+
} from '../../Constants/UiModes.js';
|
|
13
|
+
import Form from '../Form/Form.js';
|
|
14
|
+
import withComponent from '../Hoc/withComponent.js';
|
|
15
|
+
import ChartLine from '../Icons/ChartLine.js';
|
|
16
|
+
import Pdf from '../Icons/Pdf.js';
|
|
17
|
+
import Excel from '../Icons/Excel.js';
|
|
18
|
+
import UiGlobals from '../../UiGlobals.js';
|
|
19
|
+
import _ from 'lodash';
|
|
20
|
+
|
|
21
|
+
const
|
|
22
|
+
PDF = 'PDF',
|
|
23
|
+
EXCEL = 'PhpOffice';
|
|
24
|
+
|
|
25
|
+
function Report(props) {
|
|
26
|
+
if (CURRENT_MODE !== UI_MODE_WEB) {
|
|
27
|
+
return <Text>Reports are web only!</Text>;
|
|
28
|
+
}
|
|
29
|
+
const {
|
|
30
|
+
title,
|
|
31
|
+
description,
|
|
32
|
+
reportId,
|
|
33
|
+
// icon,
|
|
34
|
+
disablePdf = false,
|
|
35
|
+
disableExcel = false,
|
|
36
|
+
includePresets = false,
|
|
37
|
+
showReportHeaders = true,
|
|
38
|
+
h = '300px',
|
|
39
|
+
} = props,
|
|
40
|
+
styles = UiGlobals.styles,
|
|
41
|
+
url = UiGlobals.baseURL + 'Reports/getReport',
|
|
42
|
+
buttons = [],
|
|
43
|
+
downloadWithFetch = (data) => {
|
|
44
|
+
const options = {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: {
|
|
47
|
+
'Content-Type': 'application/json',
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify(data),
|
|
50
|
+
};
|
|
51
|
+
fetch(url, options)
|
|
52
|
+
.then( res => res.blob() )
|
|
53
|
+
.then( blob => {
|
|
54
|
+
const
|
|
55
|
+
winName = 'ReportWindow',
|
|
56
|
+
opts = 'resizable=yes,height=600,width=800,location=0,menubar=0,scrollbars=1',
|
|
57
|
+
externalWindow = window.open('', winName, opts),
|
|
58
|
+
file = externalWindow.URL.createObjectURL(blob);
|
|
59
|
+
externalWindow.location.assign(file);
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
getReport = (reportType, data) => {
|
|
63
|
+
const params = {
|
|
64
|
+
report_id: reportId,
|
|
65
|
+
outputFileType: reportType,
|
|
66
|
+
showReportHeaders,
|
|
67
|
+
// download_token, // not sure this is needed
|
|
68
|
+
...data,
|
|
69
|
+
},
|
|
70
|
+
closeWindow = reportType === EXCEL;
|
|
71
|
+
|
|
72
|
+
downloadWithFetch(params, closeWindow);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const propsIcon = props._icon || {};
|
|
76
|
+
propsIcon.size = 60;
|
|
77
|
+
propsIcon.px = 5;
|
|
78
|
+
let icon = props.icon;
|
|
79
|
+
if (_.isEmpty(icon)) {
|
|
80
|
+
icon = ChartLine;
|
|
81
|
+
}
|
|
82
|
+
if (React.isValidElement(icon)) {
|
|
83
|
+
if (!_.isEmpty(propsIcon)) {
|
|
84
|
+
icon = React.cloneElement(icon, {...propsIcon});
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
icon = <Icon as={icon} {...propsIcon} />;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!disableExcel) {
|
|
91
|
+
buttons.push({
|
|
92
|
+
key: 'ExcelBtn',
|
|
93
|
+
text: 'Download Excel',
|
|
94
|
+
leftIcon: <Icon as={Excel} size="md" color="#fff" />,
|
|
95
|
+
onPress: (data) => getReport(EXCEL, data),
|
|
96
|
+
ml: 1,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (!disablePdf) {
|
|
100
|
+
buttons.push({
|
|
101
|
+
key: 'pdfBtn',
|
|
102
|
+
text: 'Download PDF',
|
|
103
|
+
leftIcon: <Icon as={Pdf} size="md" color="#fff" />,
|
|
104
|
+
onPress: (data) => getReport(PDF, data),
|
|
105
|
+
ml: 1,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return <Column w="100%" borderWidth={1} borderColor="primary.300" pt={4} mb={3}>
|
|
109
|
+
<Row>
|
|
110
|
+
{icon && <Column>{icon}</Column>}
|
|
111
|
+
<Column>
|
|
112
|
+
<Text fontSize="2xl">{title}</Text>
|
|
113
|
+
<Text fontSize="sm">{description}</Text>
|
|
114
|
+
</Column>
|
|
115
|
+
</Row>
|
|
116
|
+
<Form
|
|
117
|
+
type={EDITOR_TYPE__PLAIN}
|
|
118
|
+
additionalFooterButtons={buttons}
|
|
119
|
+
{...props._form}
|
|
120
|
+
/>
|
|
121
|
+
</Column>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export default withComponent(Report);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useRef, } from 'react';
|
|
1
|
+
import { useRef, useState, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Column,
|
|
4
4
|
Icon,
|
|
@@ -14,12 +14,15 @@ import withComponent from '../Hoc/withComponent.js';
|
|
|
14
14
|
import withPdfButton from '../Hoc/withPdfButton.js';
|
|
15
15
|
import inArray from '../../Functions/inArray.js';
|
|
16
16
|
import getComponentFromType from '../../Functions/getComponentFromType.js';
|
|
17
|
+
import buildAdditionalButtons from '../../Functions/buildAdditionalButtons.js';
|
|
17
18
|
import Button from '../Buttons/Button.js';
|
|
18
19
|
import Label from '../Form/Label.js';
|
|
19
20
|
import Pencil from '../Icons/Pencil.js';
|
|
20
21
|
import Footer from '../Layout/Footer.js';
|
|
21
22
|
import _ from 'lodash';
|
|
22
23
|
|
|
24
|
+
const CONTAINER_THRESHOLD = 900;
|
|
25
|
+
|
|
23
26
|
function Viewer(props) {
|
|
24
27
|
const {
|
|
25
28
|
viewerCanDelete = false,
|
|
@@ -48,13 +51,14 @@ function Viewer(props) {
|
|
|
48
51
|
} = props,
|
|
49
52
|
scrollViewRef = useRef(),
|
|
50
53
|
isMultiple = _.isArray(record),
|
|
54
|
+
[containerWidth, setContainerWidth] = useState(),
|
|
51
55
|
isSideEditor = editorType === EDITOR_TYPE__SIDE,
|
|
52
56
|
styles = UiGlobals.styles,
|
|
53
57
|
flex = props.flex || 1,
|
|
54
58
|
buildFromItems = () => {
|
|
55
|
-
return _.map(items, (item, ix) =>
|
|
59
|
+
return _.map(items, (item, ix) => buildFromItem(item, ix, columnDefaults));
|
|
56
60
|
},
|
|
57
|
-
|
|
61
|
+
buildFromItem = (item, ix, defaults) => {
|
|
58
62
|
let {
|
|
59
63
|
type,
|
|
60
64
|
title,
|
|
@@ -90,9 +94,26 @@ function Viewer(props) {
|
|
|
90
94
|
if (_.isEmpty(items)) {
|
|
91
95
|
return null;
|
|
92
96
|
}
|
|
97
|
+
if (type === 'Column') {
|
|
98
|
+
if (containerWidth < CONTAINER_THRESHOLD) {
|
|
99
|
+
// everything is in one column
|
|
100
|
+
if (propsToPass.hasOwnProperty('flex')) {
|
|
101
|
+
delete propsToPass.flex;
|
|
102
|
+
}
|
|
103
|
+
if (propsToPass.hasOwnProperty('width')) {
|
|
104
|
+
delete propsToPass.width;
|
|
105
|
+
}
|
|
106
|
+
if (propsToPass.hasOwnProperty('w')) {
|
|
107
|
+
delete propsToPass.w;
|
|
108
|
+
}
|
|
109
|
+
propsToPass.w = '100%';
|
|
110
|
+
propsToPass.mb = 1;
|
|
111
|
+
}
|
|
112
|
+
propsToPass.pl = 3;
|
|
113
|
+
}
|
|
93
114
|
const defaults = item.defaults;
|
|
94
115
|
children = _.map(items, (item, ix) => {
|
|
95
|
-
return
|
|
116
|
+
return buildFromItem(item, ix, defaults);
|
|
96
117
|
});
|
|
97
118
|
return <Element key={ix} title={title} {...defaults} {...propsToPass} {...editorTypeProps}>{children}</Element>;
|
|
98
119
|
}
|
|
@@ -121,6 +142,14 @@ function Viewer(props) {
|
|
|
121
142
|
{...propsToPass}
|
|
122
143
|
{...editorTypeProps}
|
|
123
144
|
/>;
|
|
145
|
+
|
|
146
|
+
if (item.additionalViewButtons) {
|
|
147
|
+
element = <Row flexWrap="wrap">
|
|
148
|
+
{element}
|
|
149
|
+
{buildAdditionalButtons(item.additionalViewButtons, self)}
|
|
150
|
+
</Row>;
|
|
151
|
+
}
|
|
152
|
+
|
|
124
153
|
if (label) {
|
|
125
154
|
const labelProps = {};
|
|
126
155
|
if (defaults?.labelWidth) {
|
|
@@ -169,42 +198,8 @@ function Viewer(props) {
|
|
|
169
198
|
}
|
|
170
199
|
return components;
|
|
171
200
|
},
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
_.each(additionalViewButtons, (config) => {
|
|
175
|
-
const {
|
|
176
|
-
key,
|
|
177
|
-
text,
|
|
178
|
-
handler,
|
|
179
|
-
icon,
|
|
180
|
-
isDisabled,
|
|
181
|
-
color = '#fff',
|
|
182
|
-
} = config,
|
|
183
|
-
buttonProps = {};
|
|
184
|
-
if (key) {
|
|
185
|
-
buttonProps.key = key;
|
|
186
|
-
buttonProps.reference = key;
|
|
187
|
-
}
|
|
188
|
-
if (handler) {
|
|
189
|
-
buttonProps.onPress = handler;
|
|
190
|
-
}
|
|
191
|
-
if (icon) {
|
|
192
|
-
buttonProps.leftIcon = <Icon as={icon} color="#fff" size="sm" />;
|
|
193
|
-
}
|
|
194
|
-
if (isDisabled) {
|
|
195
|
-
buttonProps.isDisabled = isDisabled;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const button = <Button
|
|
199
|
-
color={color}
|
|
200
|
-
ml={2}
|
|
201
|
-
parent={self}
|
|
202
|
-
reference={key}
|
|
203
|
-
{...buttonProps}
|
|
204
|
-
>{text}</Button>;
|
|
205
|
-
additionalButtons.push(button);
|
|
206
|
-
});
|
|
207
|
-
return additionalButtons;
|
|
201
|
+
onLayout = (e) => {
|
|
202
|
+
setContainerWidth(e.nativeEvent.layout.width);
|
|
208
203
|
};
|
|
209
204
|
|
|
210
205
|
if (self) {
|
|
@@ -213,52 +208,62 @@ function Viewer(props) {
|
|
|
213
208
|
|
|
214
209
|
const
|
|
215
210
|
showDeleteBtn = onDelete && viewerCanDelete,
|
|
216
|
-
showCloseBtn = !isSideEditor
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
color="#fff"
|
|
228
|
-
>To Edit</Button>
|
|
229
|
-
</Row>}
|
|
230
|
-
|
|
231
|
-
{!_.isEmpty(additionalButtons) &&
|
|
232
|
-
<Row p={2} alignItems="center" justifyContent="flex-end">
|
|
233
|
-
{additionalButtons}
|
|
234
|
-
</Row>}
|
|
211
|
+
showCloseBtn = !isSideEditor;
|
|
212
|
+
let additionalButtons = null,
|
|
213
|
+
viewerComponents = null,
|
|
214
|
+
ancillaryComponents = null;
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
if (containerWidth) { // we need to render this component twice in order to get the container width. Skip this on first render
|
|
218
|
+
additionalButtons = buildAdditionalButtons(additionalViewButtons);
|
|
219
|
+
viewerComponents = buildFromItems();
|
|
220
|
+
ancillaryComponents = buildAncillary();
|
|
221
|
+
}
|
|
235
222
|
|
|
236
|
-
|
|
223
|
+
return <Column flex={flex} {...props} onLayout={onLayout}>
|
|
224
|
+
{containerWidth && <>
|
|
225
|
+
{onEditMode && <Row px={4} pt={4} alignItems="center" justifyContent="flex-end">
|
|
226
|
+
<Button
|
|
227
|
+
key="editBtn"
|
|
228
|
+
onPress={onEditMode}
|
|
229
|
+
leftIcon={<Icon as={Pencil} color="#fff" size="sm" />}
|
|
230
|
+
color="#fff"
|
|
231
|
+
>To Edit</Button>
|
|
232
|
+
</Row>}
|
|
233
|
+
{!_.isEmpty(additionalButtons) &&
|
|
234
|
+
<Row p={4} alignItems="center" justifyContent="flex-end" flexWrap="wrap">
|
|
235
|
+
{additionalButtons}
|
|
236
|
+
</Row>}
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
<ScrollView _web={{ height: 1 }} width="100%" pb={1} ref={scrollViewRef}>
|
|
239
|
+
<Column>
|
|
240
|
+
{containerWidth >= CONTAINER_THRESHOLD ? <Row p={4} pl={0}>{viewerComponents}</Row> : null}
|
|
241
|
+
{containerWidth < CONTAINER_THRESHOLD ? <Column p={4}>{viewerComponents}</Column> : null}
|
|
242
|
+
<Column m={2} pt={4}>{ancillaryComponents}</Column>
|
|
243
|
+
</Column>
|
|
244
|
+
</ScrollView>
|
|
245
|
+
{(showDeleteBtn || showCloseBtn) &&
|
|
246
|
+
<Footer justifyContent="flex-end">
|
|
247
|
+
{showDeleteBtn &&
|
|
248
|
+
<Row flex={1} justifyContent="flex-start">
|
|
249
|
+
<Button
|
|
250
|
+
key="deleteBtn"
|
|
251
|
+
onPress={onDelete}
|
|
252
|
+
bg="warning"
|
|
253
|
+
_hover={{
|
|
254
|
+
bg: 'warningHover',
|
|
255
|
+
}}
|
|
256
|
+
color="#fff"
|
|
257
|
+
>Delete</Button>
|
|
258
|
+
</Row>}
|
|
259
|
+
{showCloseBtn && <Button
|
|
260
|
+
key="closeBtn"
|
|
261
|
+
onPress={onClose}
|
|
262
|
+
color="#fff"
|
|
263
|
+
>Close</Button>}
|
|
264
|
+
</Footer>}
|
|
239
265
|
|
|
240
|
-
|
|
241
|
-
</ScrollView>
|
|
242
|
-
{(showDeleteBtn || showCloseBtn) &&
|
|
243
|
-
<Footer justifyContent="flex-end">
|
|
244
|
-
{showDeleteBtn &&
|
|
245
|
-
<Row flex={1} justifyContent="flex-start">
|
|
246
|
-
<Button
|
|
247
|
-
key="deleteBtn"
|
|
248
|
-
onPress={onDelete}
|
|
249
|
-
bg="warning"
|
|
250
|
-
_hover={{
|
|
251
|
-
bg: 'warningHover',
|
|
252
|
-
}}
|
|
253
|
-
color="#fff"
|
|
254
|
-
>Delete</Button>
|
|
255
|
-
</Row>}
|
|
256
|
-
{showCloseBtn && <Button
|
|
257
|
-
key="closeBtn"
|
|
258
|
-
onPress={onClose}
|
|
259
|
-
color="#fff"
|
|
260
|
-
>Close</Button>}
|
|
261
|
-
</Footer>}
|
|
266
|
+
</>}
|
|
262
267
|
</Column>;
|
|
263
268
|
}
|
|
264
269
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Icon,
|
|
3
|
+
} from 'native-base';
|
|
4
|
+
import Button from '../Components/Buttons/Button.js';
|
|
5
|
+
import _ from 'lodash';
|
|
6
|
+
|
|
7
|
+
export default function buildAdditionalButtons(configs, self, handlerArgs = {}) {
|
|
8
|
+
const additionalButtons = [];
|
|
9
|
+
_.each(configs, (config) => {
|
|
10
|
+
const {
|
|
11
|
+
key,
|
|
12
|
+
text,
|
|
13
|
+
handler,
|
|
14
|
+
icon,
|
|
15
|
+
isDisabled,
|
|
16
|
+
color = '#fff',
|
|
17
|
+
} = config,
|
|
18
|
+
buttonProps = {
|
|
19
|
+
key,
|
|
20
|
+
reference: key,
|
|
21
|
+
};
|
|
22
|
+
if (handler) {
|
|
23
|
+
buttonProps.onPress = () => handler(handlerArgs);
|
|
24
|
+
}
|
|
25
|
+
if (icon) {
|
|
26
|
+
buttonProps.leftIcon = <Icon as={icon} color="#fff" size="sm" />;
|
|
27
|
+
}
|
|
28
|
+
if (isDisabled) {
|
|
29
|
+
buttonProps.isDisabled = isDisabled;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const button = <Button
|
|
33
|
+
color={color}
|
|
34
|
+
ml={2}
|
|
35
|
+
mb={2}
|
|
36
|
+
parent={self}
|
|
37
|
+
reference={key}
|
|
38
|
+
{...buttonProps}
|
|
39
|
+
>{text}</Button>;
|
|
40
|
+
additionalButtons.push(button);
|
|
41
|
+
});
|
|
42
|
+
return additionalButtons;
|
|
43
|
+
}
|