@developer_tribe/react-builder 1.2.39 → 1.2.41

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.
Files changed (93) hide show
  1. package/dist/attributes-editor/FallbackLocalizationField.d.ts +6 -0
  2. package/dist/build-components/NavigationBarColor/NavigationBarColorProps.generated.d.ts +1 -40
  3. package/dist/build-components/StatusBarColor/StatusBarColorProps.generated.d.ts +1 -1
  4. package/dist/build-components/patterns.generated.d.ts +21 -344
  5. package/dist/components/BuilderProvider.d.ts +1 -0
  6. package/dist/components/DeviceButton.d.ts +4 -1
  7. package/dist/index.cjs.js +1 -1
  8. package/dist/index.cjs.js.map +1 -1
  9. package/dist/index.esm.js +1 -1
  10. package/dist/index.esm.js.map +1 -1
  11. package/dist/index.web.cjs.js +4 -4
  12. package/dist/index.web.cjs.js.map +1 -1
  13. package/dist/index.web.d.ts +8 -0
  14. package/dist/index.web.esm.js +4 -4
  15. package/dist/index.web.esm.js.map +1 -1
  16. package/dist/mockOS/context/MockOSContext.d.ts +3 -1
  17. package/dist/product-base/types.d.ts +3 -0
  18. package/dist/size-matters/index.d.ts +1 -1
  19. package/dist/store.d.ts +31 -0
  20. package/dist/styles.css +1 -1
  21. package/dist/types/Device.d.ts +5 -0
  22. package/dist/types/PreviewConfig.d.ts +1 -1
  23. package/dist/utils/extractTextStyle/extractTextStyle.d.ts +1 -0
  24. package/dist/utils/extractViewStyle/extractViewStyle.d.ts +1 -0
  25. package/package.json +1 -1
  26. package/scripts/prebuild/assets/prompt_scheme.md +7 -0
  27. package/scripts/public/bin.js +0 -0
  28. package/src/DeviceMockFrame.tsx +8 -0
  29. package/src/RenderPage.tsx +3 -0
  30. package/src/assets/devices.json +747 -183
  31. package/src/assets/meta.json +1 -1
  32. package/src/assets/prompt-scheme-onboard.generated.ts +1 -1
  33. package/src/assets/prompt-scheme-paywall.generated.ts +1 -1
  34. package/src/assets/samples/carousel-sample.json +30 -26
  35. package/src/assets/samples/paywall-1.json +31 -31
  36. package/src/assets/samples/paywall-2.json +28 -28
  37. package/src/assets/samples/paywall-app-delete-offer.json +29 -29
  38. package/src/assets/samples/paywall-app-open-offer.json +29 -29
  39. package/src/assets/samples/paywall-back-offer.json +28 -28
  40. package/src/assets/samples/paywall-notification-offer.json +28 -28
  41. package/src/assets/samples/simple-1.json +4 -4
  42. package/src/assets/samples/simple-2.json +25 -25
  43. package/src/assets/samples/unmigrated-builder-1.1.1.json +7 -7
  44. package/src/assets/samples/unmigrated-builder1.json +4 -4
  45. package/src/assets/samples/unvalidated-builder1.json +4 -4
  46. package/src/assets/samples/unvalidated-crash1.json +2 -2
  47. package/src/assets/samples/unvalidated-crashcomponent1.json +2 -2
  48. package/src/assets/samples/vpn-onboard-1.json +30 -30
  49. package/src/assets/samples/vpn-onboard-2.json +30 -30
  50. package/src/assets/samples/vpn-onboard-3.json +27 -27
  51. package/src/assets/samples/vpn-onboard-4.json +27 -27
  52. package/src/assets/samples/vpn-onboard-5.json +40 -40
  53. package/src/assets/samples/vpn-onboard-6.json +30 -30
  54. package/src/assets/samples/vpn-onboard-7.json +29 -29
  55. package/src/attribute-analyser/style/web/useExtractImageStyle.ts +8 -3
  56. package/src/attribute-analyser/style/web/useExtractViewStyle.ts +8 -3
  57. package/src/attributes-editor/AttributesEditorView.tsx +17 -6
  58. package/src/attributes-editor/FallbackLocalizationField.tsx +384 -0
  59. package/src/build-components/CarouselDots/CarouselDots.tsx +8 -3
  60. package/src/build-components/Main/Main.tsx +3 -1
  61. package/src/build-components/NavigationBarColor/NavigationBarColor.tsx +15 -1
  62. package/src/build-components/NavigationBarColor/NavigationBarColorProps.generated.ts +1 -52
  63. package/src/build-components/NavigationBarColor/pattern.json +11 -2
  64. package/src/build-components/OnboardDot/OnboardDot.tsx +3 -2
  65. package/src/build-components/PaywallCloseButton/pattern.json +1 -0
  66. package/src/build-components/StatusBarColor/StatusBarColor.tsx +15 -1
  67. package/src/build-components/StatusBarColor/StatusBarColorProps.generated.ts +1 -1
  68. package/src/build-components/StatusBarColor/pattern.json +10 -1
  69. package/src/build-components/patterns.generated.ts +25 -364
  70. package/src/components/BottomBar.tsx +135 -31
  71. package/src/components/BuilderProvider.tsx +1 -0
  72. package/src/components/DeviceButton.tsx +35 -0
  73. package/src/components/EditorHeader.tsx +16 -1
  74. package/src/hooks/useLocalize.ts +3 -1
  75. package/src/hooks/useSafeAreaViewStyle.ts +24 -4
  76. package/src/index.web.ts +19 -0
  77. package/src/mockOS/context/MockOSContext.tsx +41 -13
  78. package/src/modals/DeviceSelectorModal.tsx +94 -10
  79. package/src/modals/InspectModal.tsx +112 -4
  80. package/src/product-base/buildPaywallLocalizationParams.ts +3 -0
  81. package/src/product-base/extractAndroidParams.ts +38 -8
  82. package/src/product-base/types.ts +3 -0
  83. package/src/size-matters/index.ts +15 -9
  84. package/src/store.ts +66 -0
  85. package/src/styles/modals/_product-edit-modal.scss +2 -2
  86. package/src/types/Device.ts +5 -0
  87. package/src/types/PreviewConfig.ts +6 -0
  88. package/src/utils/analyseNodeByPatterns.ts +6 -2
  89. package/src/utils/extractTextStyle/extractTextStyle.ts +3 -1
  90. package/src/utils/extractTextStyle/extractTextStyleNative.ts +1 -1
  91. package/src/utils/extractViewStyle/extractViewStyle.ts +19 -5
  92. package/src/utils/extractViewStyle/extractViewStyleNative.ts +5 -1
  93. package/src/utils/replaceLocalizationParams.ts +5 -7
@@ -4507,364 +4507,14 @@ export const patterns = [
4507
4507
  description: 'description',
4508
4508
  children: 'never',
4509
4509
  attributes: {
4510
- scrollable: 'boolean',
4511
- styles: {
4512
- flexDirection: ['row', 'column'],
4513
- flexWrap: ['nowrap', 'wrap', 'wrap-reverse'],
4514
- alignItems: [
4515
- 'flex-start',
4516
- 'center',
4517
- 'flex-end',
4518
- 'stretch',
4519
- 'baseline',
4520
- ],
4521
- justifyContent: [
4522
- 'flex-start',
4523
- 'center',
4524
- 'flex-end',
4525
- 'space-between',
4526
- 'space-around',
4527
- 'space-evenly',
4528
- ],
4529
- gap: 'size',
4530
- padding: 'size',
4531
- paddingHorizontal: 'size',
4532
- paddingVertical: 'size',
4533
- paddingTop: 'size',
4534
- paddingBottom: 'size',
4535
- paddingLeft: 'size',
4536
- paddingRight: 'size',
4537
- margin: 'size',
4538
- marginHorizontal: 'size',
4539
- marginVertical: 'size',
4540
- marginTop: 'size',
4541
- marginBottom: 'size',
4542
- marginLeft: 'size',
4543
- marginRight: 'size',
4544
- backgroundColor: 'color',
4545
- borderRadius: 'size',
4546
- width: 'size',
4547
- minWidth: 'size',
4548
- maxWidth: 'size',
4549
- height: 'size',
4550
- minHeight: 'size',
4551
- maxHeight: 'size',
4552
- flex: 'number',
4553
- position: ['relative', 'absolute'],
4554
- top: 'size',
4555
- bottom: 'size',
4556
- left: 'size',
4557
- right: 'size',
4558
- zIndex: 'number',
4559
- },
4560
- testID: 'string',
4510
+ styles: { backgroundColor: 'color' },
4511
+ translucent: 'boolean',
4561
4512
  },
4562
4513
  },
4563
4514
  meta: {
4564
4515
  desiredParent: ['all'],
4565
4516
  label: 'Navigation Bar Color',
4566
4517
  description: 'Sets the OS navigation bar background color.',
4567
- specialCategories: {
4568
- padding: {
4569
- label: 'Padding',
4570
- description: 'Uniform padding on all sides.',
4571
- category: 'container',
4572
- sort: 1,
4573
- },
4574
- margin: {
4575
- label: 'Margin',
4576
- description: 'Uniform margin on all sides.',
4577
- category: 'container',
4578
- sort: 2,
4579
- },
4580
- size: {
4581
- label: 'Size',
4582
- description: 'Fixed dimensions.',
4583
- category: 'container',
4584
- sort: 3,
4585
- },
4586
- offset: {
4587
- label: 'Offset',
4588
- description: 'Absolute positioning offsets.',
4589
- category: 'container',
4590
- sort: 4,
4591
- },
4592
- },
4593
- attributes: {
4594
- scrollable: {
4595
- label: 'Scrollable',
4596
- description: 'Turns scroll interaction on.',
4597
- category: 'container',
4598
- specialCategory: null,
4599
- sort: -1,
4600
- },
4601
- styles: {
4602
- backgroundColor: {
4603
- label: 'Background Color',
4604
- description: 'Background fill color.',
4605
- category: 'style',
4606
- specialCategory: null,
4607
- sort: 20,
4608
- },
4609
- borderRadius: {
4610
- label: 'Border Radius',
4611
- description: 'Corner rounding amount.',
4612
- category: 'style',
4613
- specialCategory: null,
4614
- sort: 21,
4615
- preferredScale: 's',
4616
- },
4617
- flexDirection: {
4618
- label: 'Flex Direction',
4619
- description: 'Sets row or column layout.',
4620
- category: 'container',
4621
- specialCategory: null,
4622
- sort: 4,
4623
- },
4624
- flexWrap: {
4625
- label: 'Flex Wrap',
4626
- description: 'Controls whether flex items wrap to multiple lines.',
4627
- category: 'container',
4628
- specialCategory: null,
4629
- sort: 4.5,
4630
- },
4631
- alignItems: {
4632
- label: 'Align Items',
4633
- description: 'Controls cross-axis alignment.',
4634
- category: 'container',
4635
- specialCategory: null,
4636
- sort: 3,
4637
- },
4638
- justifyContent: {
4639
- label: 'Justify Content',
4640
- description: 'Controls main-axis alignment.',
4641
- category: 'container',
4642
- specialCategory: null,
4643
- sort: 5,
4644
- },
4645
- gap: {
4646
- label: 'Gap',
4647
- description: 'Space between children.',
4648
- category: 'container',
4649
- specialCategory: null,
4650
- sort: 10,
4651
- preferredScale: 's',
4652
- },
4653
- padding: {
4654
- label: 'Padding',
4655
- description: 'Uniform padding on all sides.',
4656
- category: 'container',
4657
- specialCategory: 'padding',
4658
- sort: 6,
4659
- preferredScale: 's',
4660
- },
4661
- paddingHorizontal: {
4662
- label: 'Padding Horizontal',
4663
- description: 'Left and right padding.',
4664
- category: 'container',
4665
- specialCategory: 'padding',
4666
- sort: 7,
4667
- preferredScale: 's',
4668
- },
4669
- paddingVertical: {
4670
- label: 'Padding Vertical',
4671
- description: 'Top and bottom padding.',
4672
- category: 'container',
4673
- specialCategory: 'padding',
4674
- sort: 8,
4675
- preferredScale: 'vs',
4676
- },
4677
- paddingTop: {
4678
- label: 'Padding Top',
4679
- description: 'Top padding only.',
4680
- category: 'container',
4681
- specialCategory: 'padding',
4682
- sort: 9,
4683
- preferredScale: 'vs',
4684
- },
4685
- paddingBottom: {
4686
- label: 'Padding Bottom',
4687
- description: 'Bottom padding only.',
4688
- category: 'container',
4689
- specialCategory: 'padding',
4690
- sort: 10,
4691
- preferredScale: 'vs',
4692
- },
4693
- paddingLeft: {
4694
- label: 'Padding Left',
4695
- description: 'Left padding only.',
4696
- category: 'container',
4697
- specialCategory: 'padding',
4698
- sort: 11,
4699
- preferredScale: 's',
4700
- },
4701
- paddingRight: {
4702
- label: 'Padding Right',
4703
- description: 'Right padding only.',
4704
- category: 'container',
4705
- specialCategory: 'padding',
4706
- sort: 12,
4707
- preferredScale: 's',
4708
- },
4709
- margin: {
4710
- label: 'Margin',
4711
- description: 'Uniform margin on all sides.',
4712
- category: 'container',
4713
- specialCategory: 'margin',
4714
- sort: 13,
4715
- preferredScale: 's',
4716
- },
4717
- marginHorizontal: {
4718
- label: 'Margin Horizontal',
4719
- description: 'Left and right margin.',
4720
- category: 'container',
4721
- specialCategory: 'margin',
4722
- sort: 14,
4723
- preferredScale: 's',
4724
- },
4725
- marginVertical: {
4726
- label: 'Margin Vertical',
4727
- description: 'Top and bottom margin.',
4728
- category: 'container',
4729
- specialCategory: 'margin',
4730
- sort: 15,
4731
- preferredScale: 'vs',
4732
- },
4733
- marginTop: {
4734
- label: 'Margin Top',
4735
- description: 'Top margin only.',
4736
- category: 'container',
4737
- specialCategory: 'margin',
4738
- sort: 16,
4739
- preferredScale: 'vs',
4740
- },
4741
- marginBottom: {
4742
- label: 'Margin Bottom',
4743
- description: 'Bottom margin only.',
4744
- category: 'container',
4745
- specialCategory: 'margin',
4746
- sort: 17,
4747
- preferredScale: 'vs',
4748
- },
4749
- marginLeft: {
4750
- label: 'Margin Left',
4751
- description: 'Left margin only.',
4752
- category: 'container',
4753
- specialCategory: 'margin',
4754
- sort: 18,
4755
- preferredScale: 's',
4756
- },
4757
- marginRight: {
4758
- label: 'Margin Right',
4759
- description: 'Right margin only.',
4760
- category: 'container',
4761
- specialCategory: 'margin',
4762
- sort: 19,
4763
- preferredScale: 's',
4764
- },
4765
- width: {
4766
- label: 'Width',
4767
- description: 'Fixed width value.',
4768
- category: 'container',
4769
- specialCategory: 'size',
4770
- sort: 0,
4771
- preferredScale: 's',
4772
- },
4773
- minWidth: {
4774
- label: 'Min Width',
4775
- description: 'Minimum width constraint.',
4776
- category: 'container',
4777
- specialCategory: 'size',
4778
- sort: 1,
4779
- preferredScale: 's',
4780
- },
4781
- maxWidth: {
4782
- label: 'Max Width',
4783
- description: 'Maximum width constraint.',
4784
- category: 'container',
4785
- specialCategory: 'size',
4786
- sort: 2,
4787
- preferredScale: 's',
4788
- },
4789
- height: {
4790
- label: 'Height',
4791
- description: 'Fixed height value.',
4792
- category: 'container',
4793
- specialCategory: 'size',
4794
- sort: 3,
4795
- preferredScale: 'vs',
4796
- },
4797
- minHeight: {
4798
- label: 'Min Height',
4799
- description: 'Minimum height constraint.',
4800
- category: 'container',
4801
- specialCategory: 'size',
4802
- sort: 4,
4803
- preferredScale: 'vs',
4804
- },
4805
- maxHeight: {
4806
- label: 'Max Height',
4807
- description: 'Maximum height constraint.',
4808
- category: 'container',
4809
- specialCategory: 'size',
4810
- sort: 5,
4811
- preferredScale: 'vs',
4812
- },
4813
- flex: {
4814
- label: 'Flex',
4815
- description: 'Flex grow factor (e.g. 1 fills available space).',
4816
- category: 'container',
4817
- specialCategory: 'size',
4818
- sort: 6,
4819
- },
4820
- position: {
4821
- label: 'Position',
4822
- description: 'Sets layout positioning mode.',
4823
- category: 'container',
4824
- specialCategory: null,
4825
- sort: 3,
4826
- },
4827
- top: {
4828
- label: 'Top',
4829
- description: 'Offset from the top edge.',
4830
- category: 'container',
4831
- specialCategory: 'offset',
4832
- sort: 22,
4833
- preferredScale: 'vs',
4834
- },
4835
- bottom: {
4836
- label: 'Bottom',
4837
- description: 'Offset from the bottom edge.',
4838
- category: 'container',
4839
- specialCategory: 'offset',
4840
- sort: 23,
4841
- preferredScale: 'vs',
4842
- },
4843
- left: {
4844
- label: 'Left',
4845
- description: 'Offset from the left edge.',
4846
- category: 'container',
4847
- specialCategory: 'offset',
4848
- sort: 24,
4849
- preferredScale: 's',
4850
- },
4851
- right: {
4852
- label: 'Right',
4853
- description: 'Offset from the right edge.',
4854
- category: 'container',
4855
- specialCategory: 'offset',
4856
- sort: 25,
4857
- preferredScale: 's',
4858
- },
4859
- zIndex: {
4860
- label: 'Z-Index',
4861
- description: 'Controls stacking order.',
4862
- category: 'container',
4863
- specialCategory: null,
4864
- sort: 26,
4865
- },
4866
- },
4867
- },
4868
4518
  styles: {
4869
4519
  backgroundColor: {
4870
4520
  label: 'Background Color',
@@ -4874,19 +4524,17 @@ export const patterns = [
4874
4524
  sort: 1,
4875
4525
  },
4876
4526
  },
4877
- },
4878
- defaults: {
4879
- styles: {
4880
- flexDirection: 'column',
4881
- position: 'relative',
4882
- zIndex: 1,
4883
- alignSelf: 'flex-start',
4884
- flexGrow: 0,
4885
- flexShrink: 0,
4886
- backgroundColor: 'THEME_COLORS.BACKGROUND',
4527
+ attributes: {
4528
+ translucent: {
4529
+ label: 'Translucent',
4530
+ description: 'Sets the navigation bar to translucent.',
4531
+ category: 'style',
4532
+ specialCategory: null,
4533
+ sort: 2,
4534
+ },
4887
4535
  },
4888
4536
  },
4889
- types: {},
4537
+ defaults: { styles: { backgroundColor: 'THEME_COLORS.BACKGROUND' } },
4890
4538
  },
4891
4539
  {
4892
4540
  schemaVersion: 2,
@@ -10058,6 +9706,7 @@ export const patterns = [
10058
9706
  alignItems: 'center',
10059
9707
  },
10060
9708
  translateCounter: 1,
9709
+ testID: 'paywall-close-button',
10061
9710
  size: 24,
10062
9711
  },
10063
9712
  types: {},
@@ -13096,7 +12745,10 @@ export const patterns = [
13096
12745
  title: 'title',
13097
12746
  description: 'description',
13098
12747
  children: 'never',
13099
- attributes: { styles: { backgroundColor: 'color' }, testID: 'string' },
12748
+ attributes: {
12749
+ styles: { backgroundColor: 'color' },
12750
+ translucent: 'boolean',
12751
+ },
13100
12752
  },
13101
12753
  meta: {
13102
12754
  desiredParent: ['all'],
@@ -13111,6 +12763,15 @@ export const patterns = [
13111
12763
  sort: 1,
13112
12764
  },
13113
12765
  },
12766
+ attributes: {
12767
+ translucent: {
12768
+ label: 'Translucent',
12769
+ description: 'Sets the status bar to translucent.',
12770
+ category: 'style',
12771
+ specialCategory: null,
12772
+ sort: 2,
12773
+ },
12774
+ },
13114
12775
  },
13115
12776
  defaults: { styles: { backgroundColor: 'THEME_COLORS.BACKGROUND' } },
13116
12777
  },
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useState } from 'react';
1
+ import React, { useMemo, useState, useCallback, useRef } from 'react';
2
2
  import { Icon } from './Icon.generated';
3
3
  import type { IconsType } from '../types/Icons.generated';
4
4
  import { useRenderStore } from '../store';
@@ -29,7 +29,6 @@ export function BottomBar({
29
29
  setData,
30
30
  project,
31
31
  }: BottomBarProps) {
32
- const rtlIcon: IconsType = 'translate';
33
32
  const magicCursorIcon: IconsType = 'magicpen';
34
33
  const debugIcon: IconsType = 'speedometer-03';
35
34
  const localizationIcon: IconsType = 'globe-01';
@@ -45,8 +44,8 @@ export function BottomBar({
45
44
  setDefaultLanguage,
46
45
  previewMode,
47
46
  setPreviewMode,
48
- isRtl,
49
47
  setIsRtl,
48
+ languageColumns,
50
49
  } = useRenderStore((s) => ({
51
50
  localization: s.localization,
52
51
  setLocalization: s.setLocalization,
@@ -56,24 +55,55 @@ export function BottomBar({
56
55
  setDefaultLanguage: s.setDefaultLanguage,
57
56
  previewMode: s.previewMode,
58
57
  setPreviewMode: s.setPreviewMode,
59
- isRtl: s.isRtl,
60
58
  setIsRtl: s.setIsRtl,
59
+ languageColumns: s.languageColumns,
61
60
  }));
62
61
 
63
62
  const [isDebugOpen, setIsDebugOpen] = useState(false);
64
63
  const [isLocalizationOpen, setIsLocalizationOpen] = useState(false);
65
64
  const [isInspectOpen, setIsInspectOpen] = useState(false);
66
65
  const [isPromptManagerOpen, setIsPromptManagerOpen] = useState(false);
66
+ const [langDropdownOpen, setLangDropdownOpen] = useState(false);
67
+ const langTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
68
+
69
+ // Use languageColumns from API, fallback to localization object keys
70
+ const availableLanguages = useMemo(() => {
71
+ if (languageColumns.length > 0) return languageColumns;
72
+ const locKeys = Object.keys(localization ?? {});
73
+ return locKeys.map((code) => ({
74
+ id: 0,
75
+ code: code.toUpperCase(),
76
+ title: code,
77
+ iso_code: code.toUpperCase(),
78
+ is_right_alignment: false,
79
+ }));
80
+ }, [languageColumns, localization]);
67
81
 
68
- const languages = useMemo(() => ['en', 'tr', 'ar'], []);
69
82
  const activeLanguage = defaultLanguage;
70
83
 
84
+ const handleSelectLanguage = useCallback(
85
+ (lang: { code: string; is_right_alignment: boolean }) => {
86
+ const code = lang.code.toLowerCase();
87
+ setDefaultLanguage(code);
88
+ setIsRtl(lang.is_right_alignment);
89
+ setLangDropdownOpen(false);
90
+ },
91
+ [setDefaultLanguage, setIsRtl],
92
+ );
93
+
94
+ const handleLangMouseEnter = () => {
95
+ if (langTimeoutRef.current) clearTimeout(langTimeoutRef.current);
96
+ setLangDropdownOpen(true);
97
+ };
98
+ const handleLangMouseLeave = () => {
99
+ langTimeoutRef.current = setTimeout(() => setLangDropdownOpen(false), 200);
100
+ };
101
+
71
102
  const handleLocalicationChange = (next: Localication) => {
72
103
  setLocalization(next);
73
104
  };
74
105
 
75
106
  const themeIsActive = theme === 'dark';
76
- const rtlIsActive = isRtl;
77
107
  const previewIsActive = previewMode;
78
108
  const themeIcon: IconsType = themeIsActive ? 'moon-bold' : 'sun';
79
109
 
@@ -90,19 +120,6 @@ export function BottomBar({
90
120
  <Icon iconType={themeIcon} size={20} color="currentColor" alt="" />
91
121
  </button>
92
122
 
93
- <button
94
- type="button"
95
- className={`rb-bottom-bar__button rb-bottom-bar__button--rtl${
96
- rtlIsActive ? ' is-active' : ''
97
- }`}
98
- aria-label="RTL"
99
- aria-pressed={rtlIsActive}
100
- onClick={() => setIsRtl(!isRtl)}
101
- >
102
- <Icon iconType={rtlIcon} size={18} color="currentColor" alt="" />
103
- <span className="rb-bottom-bar__rtl-text">RTL</span>
104
- </button>
105
-
106
123
  <button
107
124
  type="button"
108
125
  className={`rb-bottom-bar__button rb-bottom-bar__button--preview${
@@ -171,19 +188,106 @@ export function BottomBar({
171
188
 
172
189
  <div className="rb-bottom-bar__spacer" />
173
190
 
174
- <div className="rb-bottom-bar__langs" aria-label="Language">
175
- {languages.map((language) => (
176
- <button
177
- key={language}
178
- type="button"
179
- className={`rb-bottom-bar__lang${
180
- activeLanguage === language ? ' is-active' : ''
181
- }`}
182
- onClick={() => setDefaultLanguage(language)}
191
+ {/* Language selector with hover-up dropdown */}
192
+ <div
193
+ className="rb-bottom-bar__lang-selector"
194
+ onMouseEnter={handleLangMouseEnter}
195
+ onMouseLeave={handleLangMouseLeave}
196
+ style={{ position: 'relative' }}
197
+ >
198
+ <button
199
+ type="button"
200
+ className="rb-bottom-bar__lang is-active"
201
+ style={{
202
+ display: 'flex',
203
+ alignItems: 'center',
204
+ gap: 4,
205
+ }}
206
+ >
207
+ {activeLanguage.toUpperCase()}
208
+ <span style={{ fontSize: 8, opacity: 0.6 }}>▲</span>
209
+ </button>
210
+
211
+ {langDropdownOpen && availableLanguages.length > 0 && (
212
+ <div
213
+ className="rb-bottom-bar__lang-dropdown"
214
+ style={{
215
+ position: 'absolute',
216
+ bottom: '100%',
217
+ right: 0,
218
+ marginBottom: 4,
219
+ background: 'var(--rb-bg-secondary, #2a2a2a)',
220
+ border: '1px solid var(--rb-border, #444)',
221
+ borderRadius: 6,
222
+ padding: '4px 0',
223
+ minWidth: 150,
224
+ maxHeight: 260,
225
+ overflowY: 'auto',
226
+ boxShadow: '0 -4px 16px rgba(0,0,0,0.3)',
227
+ zIndex: 100,
228
+ }}
183
229
  >
184
- {language}
185
- </button>
186
- ))}
230
+ {availableLanguages.map((lang) => {
231
+ const isActive =
232
+ lang.code.toLowerCase() === activeLanguage.toLowerCase();
233
+ return (
234
+ <button
235
+ key={lang.code}
236
+ type="button"
237
+ onClick={() => handleSelectLanguage(lang)}
238
+ style={{
239
+ display: 'flex',
240
+ alignItems: 'center',
241
+ gap: 6,
242
+ width: '100%',
243
+ padding: '5px 10px',
244
+ border: 'none',
245
+ background: isActive
246
+ ? 'var(--rb-accent, #6366f1)'
247
+ : 'transparent',
248
+ color: isActive
249
+ ? '#fff'
250
+ : 'var(--rb-text-primary, #e0e0e0)',
251
+ cursor: 'pointer',
252
+ fontSize: 12,
253
+ textAlign: 'left',
254
+ }}
255
+ onMouseEnter={(e) => {
256
+ if (!isActive)
257
+ e.currentTarget.style.background =
258
+ 'var(--rb-bg-hover, #333)';
259
+ }}
260
+ onMouseLeave={(e) => {
261
+ if (!isActive)
262
+ e.currentTarget.style.background = 'transparent';
263
+ }}
264
+ >
265
+ <span
266
+ style={{
267
+ fontWeight: 600,
268
+ width: 24,
269
+ flexShrink: 0,
270
+ }}
271
+ >
272
+ {lang.code}
273
+ </span>
274
+ <span style={{ opacity: 0.7, flex: 1 }}>{lang.title}</span>
275
+ {lang.is_right_alignment && (
276
+ <span
277
+ style={{
278
+ fontSize: 9,
279
+ opacity: 0.5,
280
+ flexShrink: 0,
281
+ }}
282
+ >
283
+ RTL
284
+ </span>
285
+ )}
286
+ </button>
287
+ );
288
+ })}
289
+ </div>
290
+ )}
187
291
  </div>
188
292
  </div>
189
293
 
@@ -44,6 +44,7 @@ export type BuilderProviderParams = {
44
44
  fonts?: Fonts;
45
45
  previewMode?: boolean;
46
46
  selectedKey?: string;
47
+ device?: import('../types/Device').Device;
47
48
  };
48
49
 
49
50
  type BuilderProviderProps = {