@developer_tribe/react-builder 1.0.3 → 1.0.4

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 (102) hide show
  1. package/dist/android.svg +43 -0
  2. package/dist/apple.svg +16 -0
  3. package/dist/attributes-editor/Field.d.ts +2 -1
  4. package/dist/attributes-editor/SizeField.d.ts +9 -0
  5. package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +1 -0
  6. package/dist/build-components/Button/ButtonProps.generated.d.ts +1 -0
  7. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +1 -0
  8. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +1 -0
  9. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +1 -0
  10. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +1 -0
  11. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +1 -0
  12. package/dist/build-components/Image/ImageProps.generated.d.ts +1 -0
  13. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +1 -0
  14. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +1 -1
  15. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +1 -0
  16. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +2 -3
  17. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +1 -0
  18. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +2 -1
  19. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +1 -0
  20. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +1 -0
  21. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +1 -0
  22. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +1 -0
  23. package/dist/build-components/Text/TextProps.generated.d.ts +1 -0
  24. package/dist/build-components/View/ViewProps.generated.d.ts +1 -0
  25. package/dist/build-components/patterns.generated.d.ts +194 -57
  26. package/dist/components/JsonTextEditor.d.ts +9 -0
  27. package/dist/index.cjs.js +5 -5
  28. package/dist/index.cjs.js.map +1 -1
  29. package/dist/index.esm.js +5 -5
  30. package/dist/index.esm.js.map +1 -1
  31. package/dist/pages/tabs/SideTool.d.ts +2 -1
  32. package/dist/store.d.ts +2 -0
  33. package/dist/styles.css +1 -1
  34. package/dist/utils/extractImageStyle.d.ts +2 -1
  35. package/dist/utils/extractViewStyle.d.ts +1 -2
  36. package/dist/utils/selection.d.ts +7 -0
  37. package/dist/utils/useMergedStyle.d.ts +2 -0
  38. package/package.json +2 -5
  39. package/src/.DS_Store +0 -0
  40. package/src/AttributesEditor.tsx +7 -2
  41. package/src/RenderPage.tsx +10 -6
  42. package/src/attributes-editor/Field.tsx +48 -160
  43. package/src/attributes-editor/SizeField.tsx +184 -0
  44. package/src/attributes-editor/SpecialCategorySection.tsx +10 -3
  45. package/src/build-components/BackgroundImage/BackgroundImage.tsx +7 -17
  46. package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +1 -0
  47. package/src/build-components/Button/Button.tsx +7 -9
  48. package/src/build-components/Button/ButtonProps.generated.ts +1 -0
  49. package/src/build-components/Carousel/Carousel.tsx +7 -9
  50. package/src/build-components/Carousel/CarouselProps.generated.ts +1 -0
  51. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +1 -0
  52. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +1 -0
  53. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +1 -0
  54. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +1 -0
  55. package/src/build-components/Image/Image.tsx +11 -18
  56. package/src/build-components/Image/ImageProps.generated.ts +1 -0
  57. package/src/build-components/Image/pattern.json +1 -9
  58. package/src/build-components/Onboard/OnboardProps.generated.ts +1 -0
  59. package/src/build-components/OnboardButton/OnboardButton.tsx +0 -3
  60. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +1 -1
  61. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +1 -0
  62. package/src/build-components/OnboardDot/OnboardDot.tsx +59 -39
  63. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +2 -3
  64. package/src/build-components/OnboardDot/pattern.json +2 -18
  65. package/src/build-components/OnboardFooter/OnboardFooter.tsx +28 -15
  66. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +1 -0
  67. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +2 -1
  68. package/src/build-components/OnboardItem/OnboardItem.tsx +1 -11
  69. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +1 -0
  70. package/src/build-components/OnboardProvider/OnboardProvider.tsx +1 -8
  71. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +1 -0
  72. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +1 -0
  73. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +1 -0
  74. package/src/build-components/Text/Text.tsx +9 -15
  75. package/src/build-components/Text/TextProps.generated.ts +1 -0
  76. package/src/build-components/View/View.tsx +7 -9
  77. package/src/build-components/View/ViewProps.generated.ts +1 -0
  78. package/src/build-components/View/pattern.json +9 -1
  79. package/src/build-components/patterns.generated.ts +194 -57
  80. package/src/components/Builder.tsx +61 -17
  81. package/src/components/DeviceNavigationBar.tsx +0 -1
  82. package/src/components/EditorHeader.tsx +11 -1
  83. package/src/components/JsonTextEditor.tsx +185 -0
  84. package/src/mockOS/components/MockOSRouter.tsx +6 -0
  85. package/src/mockOS/context/MockOSContext.tsx +0 -5
  86. package/src/mockOS/managers/mockPermissionManager.ts +0 -4
  87. package/src/mockOS/managers/navigationManager.ts +1 -6
  88. package/src/modals/ColorModal.tsx +103 -25
  89. package/src/modals/LocalicationModal.tsx +4 -5
  90. package/src/modals/Modal.tsx +8 -1
  91. package/src/pages/ProjectPage.tsx +7 -1
  92. package/src/pages/tabs/SideTool.tsx +10 -9
  93. package/src/store.ts +5 -0
  94. package/src/styles/base/_global.scss +5 -0
  95. package/src/styles/components/_editor-shell.scss +4 -2
  96. package/src/styles/modals/_color-modal.scss +30 -1
  97. package/src/styles/utilities/_carousel.scss +9 -8
  98. package/src/utils/extractImageStyle.ts +3 -6
  99. package/src/utils/extractTextStyle.ts +2 -81
  100. package/src/utils/extractViewStyle.ts +20 -15
  101. package/src/utils/selection.ts +24 -0
  102. package/src/utils/useMergedStyle.ts +16 -0
@@ -5,6 +5,10 @@ import useNode from '../useNode';
5
5
  import { useLogRender } from '../../utils/useLogRender';
6
6
  import { extractViewStyle } from '../../utils/extractViewStyle';
7
7
  import { useRenderStore } from '../../store';
8
+ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
9
+ import { useMergedStyle } from '../../utils/useMergedStyle';
10
+ import { parseColor } from '../../utils/parseColor';
11
+ import { parseSize } from '../../size-matters';
8
12
 
9
13
  function OnboardDot({ node }: OnboardDotComponentProps) {
10
14
  useLogRender('OnboardDot');
@@ -17,10 +21,14 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
17
21
  const dotType = node.attributes?.dotType || 'normal_dot';
18
22
  const GHOST_DOT_DARK_COLOR = '#E4E5E7';
19
23
  const GHOST_DOT_LIGHT_COLOR = '#F7F7F9';
20
- const { appConfig, projectColors } = useRenderStore((s) => ({
21
- appConfig: s.appConfig,
22
- projectColors: s.projectColors,
23
- }));
24
+ const { previewMode, current, appConfig, projectColors } = useRenderStore(
25
+ (s) => ({
26
+ previewMode: s.previewMode,
27
+ current: s.current,
28
+ appConfig: s.appConfig,
29
+ projectColors: s.projectColors,
30
+ }),
31
+ );
24
32
  const isDark = appConfig.theme === 'dark';
25
33
 
26
34
  // OnboardDot specific attributes
@@ -28,23 +36,43 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
28
36
  ? GHOST_DOT_DARK_COLOR
29
37
  : GHOST_DOT_LIGHT_COLOR;
30
38
  const inactiveDotOpacity = node.attributes?.inactive_dot_opacity ?? 0.3;
31
- const dotStyle = node.attributes?.dot_style;
32
- const containerStyle = node.attributes?.container_style;
33
39
  const activeDotColor = node.attributes?.active_dot_color;
40
+ const resolvedActiveDotColor = useMemo(
41
+ () => parseColor(activeDotColor, { appConfig, projectColors }),
42
+ [activeDotColor, appConfig, projectColors],
43
+ );
34
44
 
35
- const style = useMemo(() => {
36
- const baseStyle = extractViewStyle(node, { appConfig, projectColors });
37
- // Merge container_style if provided
38
- if (containerStyle) {
39
- try {
40
- const parsedContainerStyle = JSON.parse(containerStyle);
41
- Object.assign(baseStyle, parsedContainerStyle);
42
- } catch (e) {
43
- // Invalid JSON, ignore
44
- }
45
- }
46
- return baseStyle;
47
- }, [node, containerStyle, appConfig, projectColors]);
45
+ const baseStyle = useMemo(() => {
46
+ let innerStyle = extractViewStyle(node, { appConfig, projectColors });
47
+ delete innerStyle.flexDirection;
48
+ return innerStyle;
49
+ }, [node, appConfig, projectColors]);
50
+ const isSelected = isNodeSelected({ previewMode, current, node });
51
+ const style = useMergedStyle(
52
+ baseStyle,
53
+ isSelected ? SELECTED_OUTLINE_STYLE : undefined,
54
+ );
55
+ const expandingDotWidthRaw = node.attributes?.expanding_dot_width;
56
+ const expandingDotWidthOverride = useMemo(() => {
57
+ const parsed = parseSize(expandingDotWidthRaw);
58
+ if (parsed === undefined) return undefined;
59
+
60
+ // `parseSize` may return number (px) or a string (e.g. "50%").
61
+ const cssWidth =
62
+ typeof parsed === 'number'
63
+ ? `${parsed}px`
64
+ : typeof parsed === 'string'
65
+ ? parsed
66
+ : undefined;
67
+
68
+ if (!cssWidth) return undefined;
69
+
70
+ return {
71
+ // Controls the actual dot diameter (`.embla__dot:after`).
72
+ ['--embla-dot-size' as any]: cssWidth,
73
+ } as React.CSSProperties;
74
+ }, [expandingDotWidthRaw]);
75
+ const containerStyle = useMergedStyle(style, expandingDotWidthOverride);
48
76
 
49
77
  const onboardApi = useContext(onboardContext);
50
78
  const emblaApi = onboardApi?.emblaApi;
@@ -72,34 +100,24 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
72
100
  };
73
101
  }, [emblaApi]);
74
102
 
75
- // Parse dot_style if provided
76
- const parsedDotStyle = useMemo(() => {
77
- if (!dotStyle) return {};
78
- try {
79
- return JSON.parse(dotStyle);
80
- } catch (e) {
81
- return {};
82
- }
83
- }, [dotStyle]);
84
-
85
103
  return (
86
104
  <div
87
105
  attribute-name={attributeName}
88
106
  attribute-key={attributeKey}
89
107
  className={`embla__dots embla__dots--${dotType}`}
90
- style={style}
108
+ style={containerStyle}
91
109
  >
92
110
  {scrollSnaps.map((snap, index) => {
93
- const isSelected = selectedIndex === index;
111
+ const isDotSelected = selectedIndex === index;
94
112
  const dotStyles: React.CSSProperties = {
95
- ...parsedDotStyle,
96
- opacity: isSelected ? 1 : inactiveDotOpacity,
113
+ opacity: isDotSelected ? 1 : inactiveDotOpacity,
97
114
  };
98
115
 
99
- if (activeDotColor && isSelected) {
100
- dotStyles.color = activeDotColor;
101
- } else if (!isSelected) {
102
- dotStyles.color = inactiveDotColor;
116
+ if (resolvedActiveDotColor && isDotSelected) {
117
+ // Style the actual visual dot (rendered via `.embla__dot:after`) using a CSS variable.
118
+ (dotStyles as any)['--embla-dot-color'] = resolvedActiveDotColor;
119
+ } else if (!isDotSelected) {
120
+ (dotStyles as any)['--embla-dot-color'] = inactiveDotColor;
103
121
  }
104
122
 
105
123
  return (
@@ -108,10 +126,12 @@ function OnboardDot({ node }: OnboardDotComponentProps) {
108
126
  onClick={() => {
109
127
  emblaApi?.scrollTo(snap);
110
128
  }}
111
- className={`embla__dot ${isSelected ? 'embla__dot--selected' : ''}`}
129
+ className={`embla__dot ${isDotSelected ? 'embla__dot--selected' : ''}`}
112
130
  style={dotStyles}
131
+ aria-label={`Go to slide ${index + 1}`}
132
+ aria-current={isDotSelected ? 'true' : undefined}
113
133
  >
114
- {isSelected ? '●' : '○'}
134
+ {/* Dot visuals are rendered via CSS (`.embla__dot:after`). */}
115
135
  </button>
116
136
  );
117
137
  })}
@@ -36,6 +36,7 @@ export interface OnboardDotPropsGenerated {
36
36
  borderRadius?: string;
37
37
  width?: string;
38
38
  height?: string;
39
+ flex?: number;
39
40
  position?: PositionOptionType;
40
41
  top?: string;
41
42
  bottom?: string;
@@ -44,9 +45,7 @@ export interface OnboardDotPropsGenerated {
44
45
  zIndex?: number;
45
46
  dotType?: DotTypeOptionType;
46
47
  inactive_dot_opacity?: number;
47
- expanding_dot_width?: number;
48
- dot_style?: string;
49
- container_style?: string;
48
+ expanding_dot_width?: string;
50
49
  active_dot_color?: string;
51
50
  };
52
51
  }
@@ -15,9 +15,7 @@
15
15
  "liquid_like"
16
16
  ],
17
17
  "inactive_dot_opacity": "number",
18
- "expanding_dot_width": "number",
19
- "dot_style": "string",
20
- "container_style": "string",
18
+ "expanding_dot_width": "size",
21
19
  "active_dot_color": "color",
22
20
  "flexDirection": "never",
23
21
  "alignItems": "never",
@@ -50,26 +48,12 @@
50
48
  "specialCategory": null,
51
49
  "sort": 3
52
50
  },
53
- "dot_style": {
54
- "label": "Dot Style",
55
- "description": "Custom style for each dot.",
56
- "category": "style",
57
- "specialCategory": null,
58
- "sort": 4
59
- },
60
- "container_style": {
61
- "label": "Container Style",
62
- "description": "Style for the dot wrapper.",
63
- "category": "style",
64
- "specialCategory": null,
65
- "sort": 5
66
- },
67
51
  "active_dot_color": {
68
52
  "label": "Active Dot Color",
69
53
  "description": "Color of the active dot.",
70
54
  "category": "style",
71
55
  "specialCategory": null,
72
- "sort": 6
56
+ "sort": 4
73
57
  }
74
58
  }
75
59
  }
@@ -6,6 +6,8 @@ import { parseSize } from '../../size-matters';
6
6
  import { extractTextStyle } from '../../utils/extractTextStyle';
7
7
  import { extractViewStyle } from '../../utils/extractViewStyle';
8
8
  import { useLogRender } from '../../utils/useLogRender';
9
+ import { isNodeSelected } from '../../utils/selection';
10
+ import { useMergedStyle } from '../../utils/useMergedStyle';
9
11
 
10
12
  type Segment =
11
13
  | { type: 'text'; value: string }
@@ -92,19 +94,23 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
92
94
  node = useNode(node);
93
95
  const attributeName =
94
96
  (node as any)?.sourceType ?? node.type ?? 'OnboardFooter';
95
- const { appConfig, projectColors } = useRenderStore((s) => ({
96
- appConfig: s.appConfig,
97
- projectColors: s.projectColors,
98
- }));
97
+ const { appConfig, projectColors, previewMode, current } = useRenderStore(
98
+ (s) => ({
99
+ appConfig: s.appConfig,
100
+ projectColors: s.projectColors,
101
+ previewMode: s.previewMode,
102
+ current: s.current,
103
+ }),
104
+ );
99
105
  const { localication, defaultLanguage } = appConfig;
100
106
  const t = (key?: string) =>
101
107
  key ? (localication?.[defaultLanguage ?? 'en']?.[key] ?? key) : '';
102
108
 
103
109
  const text = t(node?.attributes?.textLocalizationKey);
104
- const textStyle: React.CSSProperties = extractTextStyle(node, {
105
- appConfig,
106
- projectColors,
107
- });
110
+ const textStyle = useMemo(
111
+ () => extractTextStyle(node, { appConfig, projectColors }),
112
+ [node, appConfig, projectColors],
113
+ );
108
114
  const viewStyle = useMemo(
109
115
  () => extractViewStyle(node, { appConfig, projectColors }),
110
116
  [node, appConfig, projectColors],
@@ -116,19 +122,26 @@ function OnboardFooter({ node }: OnboardFooterComponentProps) {
116
122
  });
117
123
 
118
124
  const paddingHorizontal = parseSize(node?.attributes?.paddingHorizontal);
125
+ const layoutStyle = useMemo<React.CSSProperties>(
126
+ () => ({
127
+ paddingLeft: paddingHorizontal,
128
+ paddingRight: paddingHorizontal,
129
+ textAlign: 'center',
130
+ }),
131
+ [paddingHorizontal],
132
+ );
133
+
134
+ const isSelected = isNodeSelected({ previewMode, current, node });
135
+ const baseStyle = useMergedStyle(viewStyle, textStyle);
136
+ const paddedStyle = useMergedStyle(baseStyle, layoutStyle);
119
137
  const generatedId = useId();
120
138
  const attributeKey = node.key ?? generatedId;
121
139
  return (
122
140
  <div
123
141
  attribute-name={attributeName}
124
142
  attribute-key={attributeKey}
125
- style={{
126
- ...viewStyle,
127
- ...textStyle,
128
- paddingLeft: paddingHorizontal,
129
- paddingRight: paddingHorizontal,
130
- textAlign: 'center',
131
- }}
143
+ className={isSelected ? 'rb-node-selected' : undefined}
144
+ style={paddedStyle}
132
145
  >
133
146
  {!!text &&
134
147
  (() => {
@@ -60,6 +60,7 @@ export interface OnboardFooterPropsGenerated {
60
60
  borderRadius?: string;
61
61
  width?: string;
62
62
  height?: string;
63
+ flex?: number;
63
64
  position?: PositionOptionType;
64
65
  top?: string;
65
66
  bottom?: string;
@@ -26,7 +26,6 @@ export interface OnboardImagePropsGenerated {
26
26
  width?: string;
27
27
  height?: string;
28
28
  resizeMode?: ResizeModeOptionType;
29
- borderRadius?: string;
30
29
  scrollable?: boolean;
31
30
  flexDirection?: FlexDirectionOptionType;
32
31
  alignItems?: AlignItemsOptionType;
@@ -46,6 +45,8 @@ export interface OnboardImagePropsGenerated {
46
45
  marginLeft?: string;
47
46
  marginRight?: string;
48
47
  backgroundColor?: string;
48
+ borderRadius?: string;
49
+ flex?: number;
49
50
  position?: PositionOptionType;
50
51
  top?: string;
51
52
  bottom?: string;
@@ -13,9 +13,6 @@ function OnboardItem({ node }: OnboardItemComponentProps) {
13
13
  const generatedId = useId();
14
14
  const attributeName = (node as any)?.sourceType ?? node.type ?? 'OnboardItem';
15
15
  const attributeKey = node.key ?? generatedId;
16
- const flexDirection = node.attributes?.flexDirection;
17
- const display = node.attributes?.display;
18
- const paddingHorizontal = parseSize(node.attributes?.paddingHorizontal);
19
16
  const { appConfig, projectColors } = useRenderStore((s) => ({
20
17
  appConfig: s.appConfig,
21
18
  projectColors: s.projectColors,
@@ -29,14 +26,7 @@ function OnboardItem({ node }: OnboardItemComponentProps) {
29
26
  attribute-name={attributeName}
30
27
  attribute-key={attributeKey}
31
28
  className="embla__slide"
32
- style={{
33
- ...viewStyle,
34
- gap: parseSize(node.attributes?.gap),
35
- flexDirection,
36
- display,
37
- paddingRight: paddingHorizontal,
38
- paddingLeft: paddingHorizontal,
39
- }}
29
+ style={viewStyle}
40
30
  >
41
31
  {node.children && <RenderNode node={node.children} />}
42
32
  </div>
@@ -44,6 +44,7 @@ export interface OnboardItemPropsGenerated {
44
44
  borderRadius?: string;
45
45
  width?: string;
46
46
  height?: string;
47
+ flex?: number;
47
48
  position?: PositionOptionType;
48
49
  top?: string;
49
50
  bottom?: string;
@@ -23,7 +23,6 @@ function OnboardProvider({ node }: OnboardProviderComponentProps) {
23
23
  const generatedId = useId();
24
24
  const attributeName =
25
25
  (node as any)?.sourceType ?? node.type ?? 'OnboardProvider';
26
- const device = useRenderStore((s) => s.device);
27
26
  const { appConfig, projectColors } = useRenderStore((s) => ({
28
27
  appConfig: s.appConfig,
29
28
  projectColors: s.projectColors,
@@ -92,13 +91,7 @@ function OnboardProvider({ node }: OnboardProviderComponentProps) {
92
91
  attribute-name={attributeName}
93
92
  attribute-key={attributeKey}
94
93
  className="carousel-provider"
95
- style={{
96
- ...viewStyle,
97
- paddingTop: node.attributes?.paddingTop,
98
- paddingRight: node.attributes?.paddingRight,
99
- paddingBottom: node.attributes?.paddingBottom,
100
- paddingLeft: node.attributes?.paddingLeft,
101
- }}
94
+ style={viewStyle}
102
95
  >
103
96
  <div className="embla">
104
97
  <div className="embla__viewport" ref={emblaRef}>
@@ -43,6 +43,7 @@ export interface OnboardProviderPropsGenerated {
43
43
  borderRadius?: never;
44
44
  width?: string;
45
45
  height?: string;
46
+ flex?: number;
46
47
  position?: PositionOptionType;
47
48
  top?: string;
48
49
  bottom?: string;
@@ -60,6 +60,7 @@ export interface OnboardSubtitlePropsGenerated {
60
60
  borderRadius?: string;
61
61
  width?: string;
62
62
  height?: string;
63
+ flex?: number;
63
64
  position?: PositionOptionType;
64
65
  top?: string;
65
66
  bottom?: string;
@@ -60,6 +60,7 @@ export interface OnboardTitlePropsGenerated {
60
60
  borderRadius?: string;
61
61
  width?: string;
62
62
  height?: string;
63
+ flex?: number;
63
64
  position?: PositionOptionType;
64
65
  top?: string;
65
66
  bottom?: string;
@@ -3,8 +3,9 @@ import type { TextComponentProps } from './TextProps.generated';
3
3
  import useNode from '../useNode';
4
4
  import { useRenderStore } from '../../store';
5
5
  import { extractTextStyle } from '../../utils/extractTextStyle';
6
- import { extractViewStyle } from '../../utils/extractViewStyle';
7
6
  import { useLogRender } from '../../utils/useLogRender';
7
+ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
8
+ import { useMergedStyle } from '../../utils/useMergedStyle';
8
9
 
9
10
  function Text({ node }: TextComponentProps) {
10
11
  useLogRender('Text');
@@ -22,22 +23,15 @@ function Text({ node }: TextComponentProps) {
22
23
  );
23
24
  const { defaultLanguage, localication } = appConfig;
24
25
  const keyOrText: string = node.children as string;
25
- const textStyle = extractTextStyle(node, { appConfig, projectColors });
26
- const viewStyle = useMemo(
27
- () => extractViewStyle(node, { appConfig, projectColors }),
26
+ const textStyle = useMemo(
27
+ () => extractTextStyle(node, { appConfig, projectColors }),
28
28
  [node, appConfig, projectColors],
29
29
  );
30
- const isSelected =
31
- previewMode &&
32
- !!current &&
33
- (current as any)?.key &&
34
- (node as any)?.key &&
35
- (current as any).key === (node as any).key;
36
- const style = {
37
- ...viewStyle,
38
- ...textStyle,
39
- ...(isSelected ? { outline: '2px solid #2684FF' } : {}),
40
- };
30
+ const isSelected = isNodeSelected({ previewMode, current, node });
31
+ const style = useMergedStyle(
32
+ textStyle,
33
+ isSelected ? SELECTED_OUTLINE_STYLE : undefined,
34
+ );
41
35
 
42
36
  return (
43
37
  <p
@@ -56,6 +56,7 @@ export interface TextPropsGenerated {
56
56
  borderRadius?: string;
57
57
  width?: string;
58
58
  height?: string;
59
+ flex?: number;
59
60
  position?: PositionOptionType;
60
61
  top?: string;
61
62
  bottom?: string;
@@ -6,6 +6,8 @@ import useNode from '../useNode';
6
6
  import { useRenderStore } from '../../store';
7
7
  import { extractViewStyle } from '../../utils/extractViewStyle';
8
8
  import { useLogRender } from '../../utils/useLogRender';
9
+ import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
10
+ import { useMergedStyle } from '../../utils/useMergedStyle';
9
11
 
10
12
  export function View({ node }: ViewComponentProps) {
11
13
  useLogRender('View');
@@ -25,15 +27,11 @@ export function View({ node }: ViewComponentProps) {
25
27
  () => extractViewStyle(node, { appConfig, projectColors }),
26
28
  [node, appConfig, projectColors],
27
29
  );
28
- const isSelected =
29
- previewMode &&
30
- !!current &&
31
- (current as any)?.key &&
32
- (node as any)?.key &&
33
- (current as any).key === (node as any).key;
34
- const viewStyle = isSelected
35
- ? { ...baseStyle, outline: '2px solid #2684FF' }
36
- : baseStyle;
30
+ const isSelected = isNodeSelected({ previewMode, current, node });
31
+ const viewStyle = useMergedStyle(
32
+ baseStyle,
33
+ isSelected ? SELECTED_OUTLINE_STYLE : undefined,
34
+ );
37
35
  return (
38
36
  <div
39
37
  attribute-name={attributeName}
@@ -43,6 +43,7 @@ export interface ViewPropsGenerated {
43
43
  borderRadius?: string;
44
44
  width?: string;
45
45
  height?: string;
46
+ flex?: number;
46
47
  position?: PositionOptionType;
47
48
  top?: string;
48
49
  bottom?: string;
@@ -34,6 +34,7 @@
34
34
  "borderRadius": "size",
35
35
  "width": "size",
36
36
  "height": "size",
37
+ "flex": "number",
37
38
  "position": ["relative", "absolute"],
38
39
  "top": "size",
39
40
  "bottom": "size",
@@ -255,12 +256,19 @@
255
256
  "sort": 1,
256
257
  "preferedScale": "vs"
257
258
  },
259
+ "flex": {
260
+ "label": "Flex",
261
+ "description": "Flex grow factor (e.g. 1 fills available space).",
262
+ "category": "container",
263
+ "specialCategory": "size",
264
+ "sort": 2
265
+ },
258
266
  "position": {
259
267
  "label": "Position",
260
268
  "description": "Sets layout positioning mode.",
261
269
  "category": "container",
262
270
  "specialCategory": null,
263
- "sort": 2
271
+ "sort": 3
264
272
  },
265
273
  "top": {
266
274
  "label": "Top",