agora-appbuilder-core 4.0.25 → 4.0.26-beta-1

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.
@@ -33,11 +33,12 @@ import {ClientRoleType} from '../../agora-rn-uikit';
33
33
  import LiveStreamControls from './livestream/views/LiveStreamControls';
34
34
  import {
35
35
  BREAKPOINTS,
36
- CustomToolbarSort,
37
36
  isWeb,
38
37
  isWebInternal,
39
- useIsDesktop,
40
- updateToolbarDefaultConfig,
38
+ CustomToolbarMerge,
39
+ CustomToolbarSorting,
40
+ MergeMoreButtonFields,
41
+ CustomToolbarSort,
41
42
  } from '../utils/common';
42
43
  import {RoomInfoContextInterface, useRoomInfo} from './room-info/useRoomInfo';
43
44
  import LocalEndcall from '../subComponents/LocalEndCall';
@@ -70,9 +71,9 @@ import useGetName from '../utils/useGetName';
70
71
  import Toolbar from '../atoms/Toolbar';
71
72
  import ToolbarItem from '../atoms/ToolbarItem';
72
73
  import {
73
- ToolbarCustomItem,
74
- ToolbarDefaultItem,
75
- ToolbarDefaultItemConfig,
74
+ ToolbarBottomPresetProps,
75
+ ToolbarItemHide,
76
+ ToolbarMoreButtonFields,
76
77
  } from '../atoms/ToolbarPreset';
77
78
 
78
79
  import {BoardColor, whiteboardContext} from './whiteboard/WhiteboardConfigure';
@@ -108,6 +109,7 @@ import {
108
109
  import {LogSource, logger} from '../logger/AppBuilderLogger';
109
110
  import {useModal} from '../utils/useModal';
110
111
  import ViewRecordingsModal from './recordings/ViewRecordingsModal';
112
+ import {filterObject} from '../utils/index';
111
113
 
112
114
  export const useToggleWhiteboard = () => {
113
115
  const {
@@ -250,7 +252,7 @@ export const WhiteboardListener = () => {
250
252
  return null;
251
253
  };
252
254
 
253
- const MoreButton = () => {
255
+ const MoreButton = (props: {fields: ToolbarMoreButtonFields}) => {
254
256
  const noiseCancellationLabel = useString(toolbarItemNoiseCancellationText)();
255
257
  const whiteboardLabel = useString<boolean>(toolbarItemWhiteboardText);
256
258
  const captionLabel = useString<boolean>(toolbarItemCaptionText);
@@ -317,6 +319,8 @@ const MoreButton = () => {
317
319
  //AINS
318
320
  if ($config.ENABLE_NOISE_CANCELLATION) {
319
321
  actionMenuitems.push({
322
+ componentName: 'noise-cancellation',
323
+ order: 0,
320
324
  toggleStatus: isNoiseSupressionEnabled === ToggleState.enabled,
321
325
  disabled:
322
326
  isNoiseSupressionEnabled === ToggleState.disabling ||
@@ -349,6 +353,8 @@ const MoreButton = () => {
349
353
  };
350
354
  if ($config.ENABLE_VIRTUAL_BACKGROUND && !$config.AUDIO_ROOM) {
351
355
  actionMenuitems.push({
356
+ componentName: 'virtual-background',
357
+ order: 1,
352
358
  isBase64Icon: true,
353
359
  //@ts-ignore
354
360
  icon: 'vb',
@@ -449,6 +455,8 @@ const MoreButton = () => {
449
455
 
450
456
  if (isHost && $config.ENABLE_WHITEBOARD && isWebInternal()) {
451
457
  actionMenuitems.push({
458
+ componentName: 'whiteboard',
459
+ order: 2,
452
460
  disabled: WhiteboardDisabled,
453
461
  isBase64Icon: true,
454
462
  //@ts-ignore
@@ -467,6 +475,8 @@ const MoreButton = () => {
467
475
 
468
476
  if ($config.ENABLE_STT && $config.ENABLE_CAPTION) {
469
477
  actionMenuitems.push({
478
+ componentName: 'caption',
479
+ order: 3,
470
480
  icon: `${isCaptionON ? 'captions-off' : 'captions'}`,
471
481
  iconColor: $config.SECONDARY_ACTION_COLOR,
472
482
  textColor: $config.FONT_COLOR,
@@ -495,6 +505,8 @@ const MoreButton = () => {
495
505
 
496
506
  if ($config.ENABLE_MEETING_TRANSCRIPT) {
497
507
  actionMenuitems.push({
508
+ componentName: 'transcript',
509
+ order: 4,
498
510
  icon: 'transcript',
499
511
  iconColor: $config.SECONDARY_ACTION_COLOR,
500
512
  textColor: $config.FONT_COLOR,
@@ -531,6 +543,8 @@ const MoreButton = () => {
531
543
 
532
544
  if (isHost && $config.CLOUD_RECORDING && isWeb()) {
533
545
  actionMenuitems.push({
546
+ componentName: 'view-recordings',
547
+ order: 5,
534
548
  icon: 'play-circle',
535
549
  iconColor: $config.SECONDARY_ACTION_COLOR,
536
550
  textColor: $config.FONT_COLOR,
@@ -541,134 +555,165 @@ const MoreButton = () => {
541
555
  });
542
556
  }
543
557
 
544
- if (globalWidth <= BREAKPOINTS.sm) {
545
- actionMenuitems.push({
546
- icon: 'participants',
547
- iconColor: $config.SECONDARY_ACTION_COLOR,
548
- textColor: $config.FONT_COLOR,
549
- title: peopleLabel,
550
- callback: () => {
551
- setActionMenuVisible(false);
552
- setSidePanel(SidePanelType.Participants);
553
- },
554
- });
555
- actionMenuitems.push({
556
- icon: 'chat-nav',
557
- iconColor: $config.SECONDARY_ACTION_COLOR,
558
- textColor: $config.FONT_COLOR,
559
- title: chatLabel,
560
- callback: () => {
561
- setActionMenuVisible(false);
562
- setChatType(ChatType.Group);
563
- setSidePanel(SidePanelType.Chat);
564
- },
565
- });
566
-
567
- if ($config.SCREEN_SHARING) {
568
- if (
569
- !(
558
+ actionMenuitems.push({
559
+ hide: w => {
560
+ return w >= BREAKPOINTS.lg ? true : false;
561
+ },
562
+ componentName: 'participant',
563
+ order: 6,
564
+ icon: 'participants',
565
+ iconColor: $config.SECONDARY_ACTION_COLOR,
566
+ textColor: $config.FONT_COLOR,
567
+ title: peopleLabel,
568
+ callback: () => {
569
+ setActionMenuVisible(false);
570
+ setSidePanel(SidePanelType.Participants);
571
+ },
572
+ });
573
+
574
+ actionMenuitems.push({
575
+ hide: w => {
576
+ return w >= BREAKPOINTS.lg ? true : false;
577
+ },
578
+ componentName: 'chat',
579
+ order: 7,
580
+ icon: 'chat-nav',
581
+ iconColor: $config.SECONDARY_ACTION_COLOR,
582
+ textColor: $config.FONT_COLOR,
583
+ title: chatLabel,
584
+ callback: () => {
585
+ setActionMenuVisible(false);
586
+ setChatType(ChatType.Group);
587
+ setSidePanel(SidePanelType.Chat);
588
+ },
589
+ });
590
+
591
+ if ($config.SCREEN_SHARING) {
592
+ if (
593
+ !(
594
+ rtcProps.role == ClientRoleType.ClientRoleAudience &&
595
+ $config.EVENT_MODE &&
596
+ !$config.RAISE_HAND
597
+ )
598
+ ) {
599
+ actionMenuitems.push({
600
+ hide: w => {
601
+ return w >= BREAKPOINTS.sm ? true : false;
602
+ },
603
+ componentName: 'screenshare',
604
+ order: 8,
605
+ disabled:
570
606
  rtcProps.role == ClientRoleType.ClientRoleAudience &&
571
607
  $config.EVENT_MODE &&
572
- !$config.RAISE_HAND
573
- )
574
- ) {
575
- actionMenuitems.push({
576
- disabled:
577
- rtcProps.role == ClientRoleType.ClientRoleAudience &&
578
- $config.EVENT_MODE &&
579
- $config.RAISE_HAND &&
580
- !isHost,
581
- icon: isScreenshareActive ? 'stop-screen-share' : 'screen-share',
582
- iconColor: isScreenshareActive
583
- ? $config.SEMANTIC_ERROR
584
- : $config.SECONDARY_ACTION_COLOR,
585
- textColor: isScreenshareActive
586
- ? $config.SEMANTIC_ERROR
587
- : $config.FONT_COLOR,
588
- title: screenShareButton(isScreenshareActive),
589
- callback: () => {
590
- setActionMenuVisible(false);
591
- isScreenshareActive ? stopScreenshare() : startScreenshare();
592
- },
593
- });
594
- }
595
- }
596
- if (isHost && $config.CLOUD_RECORDING) {
597
- actionMenuitems.push({
598
- disabled: inProgress,
599
- icon: isRecordingActive ? 'stop-recording' : 'recording',
600
- iconColor: isRecordingActive
608
+ $config.RAISE_HAND &&
609
+ !isHost,
610
+ icon: isScreenshareActive ? 'stop-screen-share' : 'screen-share',
611
+ iconColor: isScreenshareActive
601
612
  ? $config.SEMANTIC_ERROR
602
613
  : $config.SECONDARY_ACTION_COLOR,
603
- textColor: isRecordingActive
614
+ textColor: isScreenshareActive
604
615
  ? $config.SEMANTIC_ERROR
605
616
  : $config.FONT_COLOR,
606
- title: recordingButton(isRecordingActive),
617
+ title: screenShareButton(isScreenshareActive),
607
618
  callback: () => {
608
619
  setActionMenuVisible(false);
609
- if (!isRecordingActive) {
610
- startRecording();
611
- } else {
612
- setShowStopRecordingPopup(true);
613
- }
620
+ isScreenshareActive ? stopScreenshare() : startScreenshare();
614
621
  },
615
622
  });
616
623
  }
617
624
  }
618
-
619
- if (globalWidth <= BREAKPOINTS.md) {
625
+ if (isHost && $config.CLOUD_RECORDING) {
620
626
  actionMenuitems.push({
621
- //below icon key is dummy value
622
- icon: 'grid',
623
- externalIconString: layouts[layout]?.icon,
624
- isExternalIcon: true,
625
- iconColor: $config.SECONDARY_ACTION_COLOR,
626
- textColor: $config.FONT_COLOR,
627
- title: layoutLabel,
628
- callback: () => {
629
- //setShowLayoutOption(true);
627
+ hide: w => {
628
+ return w >= BREAKPOINTS.sm ? true : false;
630
629
  },
631
- onHoverCallback: isHovered => {
632
- setShowLayoutOption(isHovered);
633
- },
634
- onHoverContent: (
635
- <LayoutIconDropdown
636
- onHoverPlaceHolder="vertical"
637
- setShowDropdown={() => {}}
638
- showDropdown={true}
639
- modalPosition={
640
- globalWidth <= BREAKPOINTS.sm
641
- ? {bottom: 65, left: -150}
642
- : {bottom: 20, left: -150}
643
- }
644
- caretPosition={{bottom: 45, right: -10}}
645
- />
646
- ),
647
- });
648
- actionMenuitems.push({
649
- icon: 'share',
650
- iconColor: $config.SECONDARY_ACTION_COLOR,
651
- textColor: $config.FONT_COLOR,
652
- title: inviteLabel,
630
+ componentName: 'recording',
631
+ order: 9,
632
+ disabled: inProgress,
633
+ icon: isRecordingActive ? 'stop-recording' : 'recording',
634
+ iconColor: isRecordingActive
635
+ ? $config.SEMANTIC_ERROR
636
+ : $config.SECONDARY_ACTION_COLOR,
637
+ textColor: isRecordingActive
638
+ ? $config.SEMANTIC_ERROR
639
+ : $config.FONT_COLOR,
640
+ title: recordingButton(isRecordingActive),
653
641
  callback: () => {
654
642
  setActionMenuVisible(false);
655
- setShowInvitePopup(true);
643
+ if (!isRecordingActive) {
644
+ startRecording();
645
+ } else {
646
+ setShowStopRecordingPopup(true);
647
+ }
656
648
  },
657
649
  });
658
650
  }
659
651
 
660
- if (globalWidth <= BREAKPOINTS.sm) {
661
- actionMenuitems.push({
662
- icon: 'settings',
663
- iconColor: $config.SECONDARY_ACTION_COLOR,
664
- textColor: $config.FONT_COLOR,
665
- title: settingsLabel,
666
- callback: () => {
667
- setActionMenuVisible(false);
668
- setSidePanel(SidePanelType.Settings);
669
- },
670
- });
671
- }
652
+ actionMenuitems.push({
653
+ hide: w => {
654
+ return w >= BREAKPOINTS.lg ? true : false;
655
+ },
656
+ componentName: 'layout',
657
+ order: 10,
658
+ //below icon key is dummy value
659
+ icon: 'grid',
660
+ externalIconString: layouts[layout]?.icon,
661
+ isExternalIcon: true,
662
+ iconColor: $config.SECONDARY_ACTION_COLOR,
663
+ textColor: $config.FONT_COLOR,
664
+ title: layoutLabel,
665
+ callback: () => {
666
+ //setShowLayoutOption(true);
667
+ },
668
+ onHoverCallback: isHovered => {
669
+ setShowLayoutOption(isHovered);
670
+ },
671
+ onHoverContent: (
672
+ <LayoutIconDropdown
673
+ onHoverPlaceHolder="vertical"
674
+ setShowDropdown={() => {}}
675
+ showDropdown={true}
676
+ modalPosition={
677
+ globalWidth <= BREAKPOINTS.lg
678
+ ? {bottom: 65, left: -150}
679
+ : {bottom: 20, left: -150}
680
+ }
681
+ caretPosition={{bottom: 45, right: -10}}
682
+ />
683
+ ),
684
+ });
685
+
686
+ actionMenuitems.push({
687
+ hide: w => {
688
+ return w >= BREAKPOINTS.lg ? true : false;
689
+ },
690
+ componentName: 'invite',
691
+ order: 11,
692
+ icon: 'share',
693
+ iconColor: $config.SECONDARY_ACTION_COLOR,
694
+ textColor: $config.FONT_COLOR,
695
+ title: inviteLabel,
696
+ callback: () => {
697
+ setActionMenuVisible(false);
698
+ setShowInvitePopup(true);
699
+ },
700
+ });
701
+
702
+ actionMenuitems.push({
703
+ hide: w => {
704
+ return w >= BREAKPOINTS.lg ? true : false;
705
+ },
706
+ componentName: 'settings',
707
+ order: 12,
708
+ icon: 'settings',
709
+ iconColor: $config.SECONDARY_ACTION_COLOR,
710
+ textColor: $config.FONT_COLOR,
711
+ title: settingsLabel,
712
+ callback: () => {
713
+ setActionMenuVisible(false);
714
+ setSidePanel(SidePanelType.Settings);
715
+ },
716
+ });
672
717
 
673
718
  useEffect(() => {
674
719
  if (isHovered) {
@@ -717,6 +762,30 @@ const MoreButton = () => {
717
762
  }
718
763
  };
719
764
 
765
+ const {width, height} = useWindowDimensions();
766
+
767
+ const isHidden = (hide: ToolbarItemHide = false) => {
768
+ try {
769
+ return typeof hide === 'boolean'
770
+ ? hide
771
+ : typeof hide === 'function'
772
+ ? hide(width, height)
773
+ : false;
774
+ } catch (error) {
775
+ console.log('debugging isHidden error', error);
776
+ return false;
777
+ }
778
+ };
779
+
780
+ const moreButtonFields = props?.fields || {};
781
+
782
+ const ActionMenuItems = MergeMoreButtonFields(
783
+ actionMenuitems,
784
+ moreButtonFields,
785
+ )
786
+ ?.filter(i => !isHidden(i))
787
+ ?.sort(CustomToolbarSort);
788
+
720
789
  return (
721
790
  <>
722
791
  <LanguageSelectorPopup
@@ -739,7 +808,7 @@ const MoreButton = () => {
739
808
  bottom: 8,
740
809
  left: 0,
741
810
  }}
742
- items={actionMenuitems}
811
+ items={ActionMenuItems}
743
812
  />
744
813
  <div
745
814
  onMouseEnter={() => {
@@ -851,9 +920,7 @@ export const SwitchCameraToolbarItem = () => {
851
920
  };
852
921
 
853
922
  export const ScreenShareToolbarItem = () => {
854
- const {width} = useWindowDimensions();
855
923
  return (
856
- width > BREAKPOINTS.sm &&
857
924
  $config.SCREEN_SHARING &&
858
925
  !isMobileOrTablet() && (
859
926
  <ToolbarItem testID="screenShare-btn">
@@ -863,12 +930,10 @@ export const ScreenShareToolbarItem = () => {
863
930
  );
864
931
  };
865
932
  export const RecordingToolbarItem = () => {
866
- const {width} = useWindowDimensions();
867
933
  const {
868
934
  data: {isHost},
869
935
  } = useRoomInfo();
870
936
  return (
871
- width > BREAKPOINTS.sm &&
872
937
  isHost &&
873
938
  $config.CLOUD_RECORDING && (
874
939
  <ToolbarItem testID="recording-btn">
@@ -878,7 +943,9 @@ export const RecordingToolbarItem = () => {
878
943
  );
879
944
  };
880
945
 
881
- export const MoreButtonToolbarItem = () => {
946
+ export const MoreButtonToolbarItem = (props?: {
947
+ fields?: ToolbarMoreButtonFields;
948
+ }) => {
882
949
  const {width} = useWindowDimensions();
883
950
  const {
884
951
  data: {isHost},
@@ -890,7 +957,7 @@ export const MoreButtonToolbarItem = () => {
890
957
  forceUpdate();
891
958
  }, [isHost]);
892
959
 
893
- return width < BREAKPOINTS.md ||
960
+ return width < BREAKPOINTS.lg ||
894
961
  ($config.ENABLE_STT &&
895
962
  $config.ENABLE_CAPTION &&
896
963
  (isHost || (!isHost && isSTTActive))) ||
@@ -904,7 +971,7 @@ export const MoreButtonToolbarItem = () => {
904
971
  ) : (
905
972
  <></>
906
973
  )}
907
- <MoreButton />
974
+ <MoreButton fields={props?.fields} />
908
975
  </ToolbarItem>
909
976
  ) : (
910
977
  <WhiteboardListener />
@@ -924,91 +991,78 @@ export const LocalEndcallToolbarItem = (
924
991
  );
925
992
  };
926
993
 
927
- const defaultItems: ToolbarDefaultItem[] = [
928
- {
994
+ const defaultItems: ToolbarBottomPresetProps['items'] = {
995
+ layout: {
929
996
  align: 'start',
930
997
  component: LayoutToolbarItem,
931
- componentName: 'layout',
932
998
  order: 0,
933
- hide: 'no',
999
+ hide: w => {
1000
+ return w < BREAKPOINTS.lg ? true : false;
1001
+ },
934
1002
  },
935
- {
1003
+ invite: {
936
1004
  align: 'start',
937
1005
  component: InviteToolbarItem,
938
- componentName: 'invite',
939
1006
  order: 1,
940
- hide: 'no',
1007
+ hide: w => {
1008
+ return w < BREAKPOINTS.lg ? true : false;
1009
+ },
941
1010
  },
942
- {
1011
+ 'raise-hand': {
943
1012
  align: 'center',
944
1013
  component: RaiseHandToolbarItem,
945
- componentName: 'raise-hand',
946
1014
  order: 0,
947
- hide: 'no',
948
1015
  },
949
- {
1016
+ 'local-audio': {
950
1017
  align: 'center',
951
1018
  component: LocalAudioToolbarItem,
952
- componentName: 'local-audio',
953
1019
  order: 1,
954
- hide: 'no',
955
1020
  },
956
- {
1021
+ 'local-video': {
957
1022
  align: 'center',
958
1023
  component: LocalVideoToolbarItem,
959
- componentName: 'local-video',
960
1024
  order: 2,
961
- hide: 'no',
962
1025
  },
963
- {
1026
+ 'switch-camera': {
964
1027
  align: 'center',
965
1028
  component: SwitchCameraToolbarItem,
966
- componentName: 'switch-camera',
967
1029
  order: 3,
968
- hide: 'no',
969
1030
  },
970
- {
1031
+ screenshare: {
971
1032
  align: 'center',
972
1033
  component: ScreenShareToolbarItem,
973
- componentName: 'screenshare',
974
1034
  order: 4,
975
- hide: 'no',
1035
+ hide: w => {
1036
+ return w < BREAKPOINTS.sm ? true : false;
1037
+ },
976
1038
  },
977
- {
1039
+ recording: {
978
1040
  align: 'center',
979
1041
  component: RecordingToolbarItem,
980
- componentName: 'recording',
981
1042
  order: 5,
982
- hide: 'no',
1043
+ hide: w => {
1044
+ return w < BREAKPOINTS.sm ? true : false;
1045
+ },
983
1046
  },
984
- {
1047
+ more: {
985
1048
  align: 'center',
986
1049
  component: MoreButtonToolbarItem,
987
- componentName: 'more',
988
1050
  order: 6,
989
- hide: 'no',
990
1051
  },
991
- {
1052
+ 'end-call': {
992
1053
  align: 'center',
993
- componentName: 'end-call',
994
1054
  component: LocalEndcallToolbarItem,
995
1055
  order: 7,
996
- hide: 'no',
997
1056
  },
998
- ];
1057
+ };
999
1058
 
1000
1059
  export interface ControlsProps {
1001
- customItems?: ToolbarCustomItem[];
1060
+ items?: ToolbarBottomPresetProps['items'];
1002
1061
  includeDefaultItems?: boolean;
1003
- defaultItemsConfig?: ToolbarDefaultItemConfig;
1004
1062
  }
1005
1063
  const Controls = (props: ControlsProps) => {
1006
- const {
1007
- customItems = [],
1008
- includeDefaultItems = true,
1009
- defaultItemsConfig = {},
1010
- } = props;
1011
- const {width} = useWindowDimensions();
1064
+ const {items = {}, includeDefaultItems = true} = props;
1065
+ const {width, height} = useWindowDimensions();
1012
1066
  const {defaultContent} = useContent();
1013
1067
  const {setLanguage, setMeetingTranscript, setIsSTTActive} = useCaption();
1014
1068
  const defaultContentRef = React.useRef(defaultContent);
@@ -1021,11 +1075,7 @@ const Controls = (props: ControlsProps) => {
1021
1075
  username: string;
1022
1076
  }>(sttSpokenLanguageToastSubHeading);
1023
1077
 
1024
- const {
1025
- data: {isHost},
1026
- sttLanguage,
1027
- isSTTActive,
1028
- } = useRoomInfo();
1078
+ const {sttLanguage, isSTTActive} = useRoomInfo();
1029
1079
 
1030
1080
  React.useEffect(() => {
1031
1081
  defaultContentRef.current = defaultContent;
@@ -1103,70 +1153,91 @@ const Controls = (props: ControlsProps) => {
1103
1153
  setIsSTTActive(isSTTActive);
1104
1154
  }, [isSTTActive]);
1105
1155
 
1106
- const ToastIcon = ({color}) => (
1107
- <View style={{marginRight: 12, alignSelf: 'center', width: 24, height: 24}}>
1108
- <ImageIcon iconType="plain" tintColor={color} name={'lang-select'} />
1109
- </View>
1110
- );
1111
-
1112
- const isHidden = i => {
1113
- return i?.hide === 'yes';
1156
+ const isHidden = (hide: ToolbarItemHide = false) => {
1157
+ try {
1158
+ return typeof hide === 'boolean'
1159
+ ? hide
1160
+ : typeof hide === 'function'
1161
+ ? hide(width, height)
1162
+ : false;
1163
+ } catch (error) {
1164
+ console.log('debugging isHidden error', error);
1165
+ return false;
1166
+ }
1114
1167
  };
1115
- const customStartItems = customItems
1116
- ?.concat(
1117
- includeDefaultItems
1118
- ? updateToolbarDefaultConfig(defaultItems, defaultItemsConfig)
1119
- : [],
1120
- )
1121
- ?.filter(i => i?.align === 'start' && !isHidden(i))
1122
- ?.sort(CustomToolbarSort);
1123
1168
 
1124
- const customCenterItems = customItems
1125
- ?.concat(
1126
- includeDefaultItems
1127
- ? updateToolbarDefaultConfig(defaultItems, defaultItemsConfig)
1128
- : [],
1129
- )
1130
- ?.filter(i => i?.align === 'center' && !isHidden(i))
1131
- ?.sort(CustomToolbarSort);
1169
+ const mergedItems = CustomToolbarMerge(
1170
+ includeDefaultItems ? defaultItems : {},
1171
+ items,
1172
+ );
1132
1173
 
1133
- const customEndItems = customItems
1134
- ?.concat(
1135
- includeDefaultItems
1136
- ? updateToolbarDefaultConfig(defaultItems, defaultItemsConfig)
1137
- : [],
1138
- )
1139
- ?.filter(i => i?.align === 'end' && !isHidden(i))
1140
- ?.sort(CustomToolbarSort);
1174
+ const startItems = filterObject(
1175
+ mergedItems,
1176
+ ([_, v]) => v?.align === 'start' && !isHidden(v?.hide),
1177
+ );
1178
+ const centerItems = filterObject(
1179
+ mergedItems,
1180
+ ([_, v]) => v?.align === 'center' && !isHidden(v?.hide),
1181
+ );
1182
+ const endItems = filterObject(
1183
+ mergedItems,
1184
+ ([_, v]) => v?.align === 'end' && !isHidden(v?.hide),
1185
+ );
1186
+
1187
+ const startItemsOrdered = CustomToolbarSorting(startItems);
1188
+ const centerItemsOrdered = CustomToolbarSorting(centerItems);
1189
+ const endItemsOrdered = CustomToolbarSorting(endItems);
1141
1190
 
1142
1191
  const renderContent = (
1143
- items: ToolbarCustomItem[],
1192
+ orderedKeys: string[],
1144
1193
  type: 'start' | 'center' | 'end',
1145
1194
  ) => {
1146
- return items?.map((item, index) => {
1147
- const ToolbarItem = item?.component;
1148
- if (ToolbarItem) {
1149
- return <ToolbarItem key={`bottom-toolbar-${type}` + index} />;
1195
+ const renderContentItem = [];
1196
+ let index = 0;
1197
+ orderedKeys.forEach(keyName => {
1198
+ index = index + 1;
1199
+ let ToolbarComponent = null;
1200
+ let ToolbarComponentProps = {};
1201
+ if (type === 'start') {
1202
+ ToolbarComponent = startItems[keyName]?.component;
1203
+ if (keyName === 'more') {
1204
+ ToolbarComponentProps = startItems[keyName]?.fields;
1205
+ }
1206
+ } else if (type === 'center') {
1207
+ ToolbarComponent = centerItems[keyName]?.component;
1208
+ if (keyName === 'more') {
1209
+ ToolbarComponentProps = centerItems[keyName]?.fields;
1210
+ }
1150
1211
  } else {
1151
- return null;
1212
+ ToolbarComponent = endItems[keyName]?.component;
1213
+ if (keyName === 'more') {
1214
+ ToolbarComponentProps = endItems[keyName]?.fields;
1215
+ }
1216
+ }
1217
+ if (ToolbarComponent) {
1218
+ renderContentItem.push(
1219
+ <ToolbarComponent
1220
+ key={`top-toolbar-${type}` + index}
1221
+ fields={ToolbarComponentProps}
1222
+ />,
1223
+ );
1152
1224
  }
1153
1225
  });
1226
+
1227
+ return renderContentItem;
1154
1228
  };
1229
+
1155
1230
  return (
1156
1231
  <Toolbar>
1157
- {width >= BREAKPOINTS.md && (
1158
- <View style={[style.startContent]}>
1159
- {renderContent(customStartItems, 'start')}
1160
- </View>
1161
- )}
1162
- <View style={[style.centerContent]}>
1163
- {renderContent(customCenterItems, 'center')}
1232
+ <View style={style.startContent}>
1233
+ {renderContent(startItemsOrdered, 'start')}
1234
+ </View>
1235
+ <View style={style.centerContent}>
1236
+ {renderContent(centerItemsOrdered, 'center')}
1237
+ </View>
1238
+ <View style={style.endContent}>
1239
+ {renderContent(endItemsOrdered, 'end')}
1164
1240
  </View>
1165
- {width >= BREAKPOINTS.md && (
1166
- <View style={style.endContent}>
1167
- {renderContent(customEndItems, 'end')}
1168
- </View>
1169
- )}
1170
1241
  </Toolbar>
1171
1242
  );
1172
1243
  };