@developer_tribe/react-builder 1.2.22 → 1.2.23

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 (100) hide show
  1. package/dist/attribute-analyser/style/native/useExtractImageStyle.d.ts +2 -2
  2. package/dist/build-components/Image/ImageProps.generated.d.ts +2 -4
  3. package/dist/build-components/NavigationBarColor/NavigationBarColor.d.ts +5 -0
  4. package/dist/build-components/NavigationBarColor/NavigationBarColorProps.generated.d.ts +54 -0
  5. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +1 -3
  6. package/dist/build-components/Separator/Separator.d.ts +5 -0
  7. package/dist/build-components/Separator/SeparatorProps.generated.d.ts +21 -0
  8. package/dist/build-components/StatusBarColor/StatusBarColor.d.ts +5 -0
  9. package/dist/build-components/StatusBarColor/StatusBarColorProps.generated.d.ts +54 -0
  10. package/dist/build-components/index.d.ts +4 -1
  11. package/dist/build-components/patterns.generated.d.ts +2105 -1253
  12. package/dist/components/AttributesEditorPanel.d.ts +1 -1
  13. package/dist/components/BuilderProvider.d.ts +1 -1
  14. package/dist/index.cjs.js +4 -4
  15. package/dist/index.cjs.js.map +1 -1
  16. package/dist/index.esm.js +4 -4
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.web.cjs.js +6 -6
  19. package/dist/index.web.cjs.js.map +1 -1
  20. package/dist/index.web.esm.js +4 -4
  21. package/dist/index.web.esm.js.map +1 -1
  22. package/dist/store.d.ts +4 -0
  23. package/dist/styles.css +1 -1
  24. package/dist/utils/attributeStyle.d.ts +9 -0
  25. package/dist/utils/extractImageStyle.d.ts +1 -1
  26. package/dist/utils/extractViewStyle/extractViewStyleNative.d.ts +1 -1
  27. package/package.json +2 -2
  28. package/src/DeviceMockFrame.tsx +8 -2
  29. package/src/assets/meta.json +1 -1
  30. package/src/assets/samples/paywall-1.json +39 -34
  31. package/src/assets/samples/paywall-2.json +39 -20
  32. package/src/assets/samples/paywall-app-delete-offer.json +40 -21
  33. package/src/assets/samples/paywall-app-open-offer.json +40 -21
  34. package/src/assets/samples/paywall-back-offer.json +40 -21
  35. package/src/assets/samples/paywall-notification-offer.json +40 -21
  36. package/src/assets/samples/vpn-onboard-1.json +84 -39
  37. package/src/assets/samples/vpn-onboard-2.json +85 -40
  38. package/src/assets/samples/vpn-onboard-3.json +84 -39
  39. package/src/assets/samples/vpn-onboard-4.json +84 -39
  40. package/src/assets/samples/vpn-onboard-5.json +102 -55
  41. package/src/assets/samples/vpn-onboard-6.json +87 -38
  42. package/src/attribute-analyser/style/native/useExtractImageStyle.ts +24 -22
  43. package/src/attribute-analyser/style/native/useExtractTextStyle.ts +9 -4
  44. package/src/attribute-analyser/style/native/useExtractViewStyle.ts +19 -7
  45. package/src/attributes-editor/useAttributesEditorModel.ts +23 -17
  46. package/src/build-components/BackgroundImage/pattern.json +9 -7
  47. package/src/build-components/CarouselDots/CarouselDots.tsx +12 -11
  48. package/src/build-components/CarouselProvider/CarouselProvider.tsx +3 -1
  49. package/src/build-components/Image/ImageProps.generated.ts +2 -4
  50. package/src/build-components/Image/pattern.json +12 -25
  51. package/src/build-components/NavigationBarColor/NavigationBarColor.tsx +39 -0
  52. package/src/build-components/NavigationBarColor/NavigationBarColorProps.generated.ts +71 -0
  53. package/src/build-components/NavigationBarColor/pattern.json +34 -0
  54. package/src/build-components/OnboardButtons/OnboardButtons.tsx +8 -10
  55. package/src/build-components/OnboardDot/OnboardDot.tsx +12 -10
  56. package/src/build-components/OnboardImage/OnboardImage.tsx +1 -1
  57. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +1 -3
  58. package/src/build-components/OnboardProvider/OnboardProvider.tsx +3 -1
  59. package/src/build-components/RenderNode.generated.tsx +15 -0
  60. package/src/build-components/Separator/Separator.tsx +41 -0
  61. package/src/build-components/Separator/SeparatorProps.generated.ts +26 -0
  62. package/src/build-components/Separator/pattern.json +59 -0
  63. package/src/build-components/StatusBarColor/StatusBarColor.tsx +39 -0
  64. package/src/build-components/StatusBarColor/StatusBarColorProps.generated.ts +71 -0
  65. package/src/build-components/StatusBarColor/pattern.json +34 -0
  66. package/src/build-components/Text/pattern.json +45 -38
  67. package/src/build-components/index.ts +15 -0
  68. package/src/build-components/patterns.generated.ts +2149 -1272
  69. package/src/build-components/useNode.ts +24 -25
  70. package/src/components/AttributesEditorPanel.tsx +4 -5
  71. package/src/components/Builder.tsx +1 -2
  72. package/src/components/BuilderProvider.tsx +40 -3
  73. package/src/components/JsonTextEditor.tsx +2 -2
  74. package/src/components/LoadingComponent.tsx +1 -1
  75. package/src/components/RenderErrorBoundary.tsx +1 -3
  76. package/src/migrations/migrations/1.1.2_extract_component_attributes_from_style.ts +3 -3
  77. package/src/modals/BenefitPresetsModal.tsx +1 -1
  78. package/src/modals/ProductPresetsModal.tsx +1 -1
  79. package/src/pages/DebugJsonPage.tsx +7 -4
  80. package/src/pages/ProjectDebug.tsx +1 -1
  81. package/src/pages/ProjectPage.tsx +31 -32
  82. package/src/pages/ProjectValidationPage.tsx +2 -2
  83. package/src/store.ts +13 -0
  84. package/src/styles/layout/_builder.scss +6 -0
  85. package/src/utils/__special_exceptions.ts +5 -5
  86. package/src/utils/analyseNode.ts +2 -2
  87. package/src/utils/analyseNodeByPatterns.ts +10 -9
  88. package/src/utils/analyseNodeStructural.ts +1 -1
  89. package/src/utils/attributeStyle.ts +26 -0
  90. package/src/utils/extractImageStyle.ts +17 -13
  91. package/src/utils/extractTextStyle/extractTextStyle.ts +7 -7
  92. package/src/utils/extractTextStyle/extractTextStyleNative.ts +10 -10
  93. package/src/utils/extractViewStyle/extractViewStyle.ts +8 -11
  94. package/src/utils/extractViewStyle/extractViewStyleNative.ts +19 -19
  95. package/src/utils/loadFontFamily.ts +14 -19
  96. package/src/utils/logRenderStore.ts +5 -4
  97. package/src/utils/nodeTree.ts +1 -1
  98. package/src/utils/patterns.ts +26 -31
  99. package/src/utils/repairNodeKeys.ts +5 -7
  100. package/src/utils/wrapNodeInMain.ts +3 -3
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared utilities for attribute/style bag access.
3
+ * schemaVersion=2 uses `attributes.styles`, legacy uses `attributes.style`.
4
+ */
5
+
6
+ import type { NodeDefaultAttribute } from '../types/Node';
7
+
8
+ /** Returns styles or style bag from attributes (schemaVersion=2 uses styles, legacy uses style). */
9
+ export function getStyleBag(
10
+ attributes: NodeDefaultAttribute | undefined,
11
+ ): Record<string, unknown> | undefined {
12
+ const record = toAttributeRecord(attributes);
13
+ const bag = record.styles ?? record.style;
14
+ return isPlainObject(bag) ? (bag as Record<string, unknown>) : undefined;
15
+ }
16
+
17
+ /** Safe indexed access to attributes. Use for reading style/direct props. */
18
+ export function toAttributeRecord(
19
+ attributes: unknown,
20
+ ): Record<string, unknown> {
21
+ return (attributes ?? {}) as Record<string, unknown>;
22
+ }
23
+
24
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
25
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
26
+ }
@@ -1,26 +1,29 @@
1
- import { ImagePropsGenerated } from '../build-components/Image/ImageProps.generated';
1
+ import {
2
+ type ImagePropsGenerated,
3
+ type ResizeModeOptionType,
4
+ } from '../build-components/Image/ImageProps.generated';
2
5
  import type { NodeData } from '../types/Node';
3
6
  import {
4
7
  extractViewStyle,
5
8
  extractViewStyleNative,
6
9
  ExtractViewStyleOptions,
7
10
  } from './extractViewStyle';
11
+ import { getStyleBag } from './attributeStyle';
8
12
 
9
13
  export function extractImageStyle<T extends ImagePropsGenerated['attributes']>(
10
14
  node: NodeData<T>,
11
15
  options: ExtractViewStyleOptions = {},
12
16
  ) {
13
17
  const attributes = node.attributes;
14
- const styleBag = (attributes as any)?.style as
15
- | Record<string, unknown>
16
- | undefined;
17
18
  const style: React.CSSProperties = {};
18
19
 
19
20
  if (!attributes) return style;
20
21
 
21
- // Map resizeMode to CSS object-fit
22
- const resizeMode = ((attributes as any)?.resizeMode ??
23
- styleBag?.resizeMode) as any;
22
+ // Map resizeMode to CSS object-fit (schemaVersion=2 uses `styles`, fallback to legacy `style`)
23
+ const stylesBag = getStyleBag(attributes) as
24
+ | ImagePropsGenerated['attributes']['style']
25
+ | undefined;
26
+ const resizeMode: ResizeModeOptionType | undefined = stylesBag?.resizeMode;
24
27
  if (resizeMode === 'cover') style.objectFit = 'cover';
25
28
  else if (resizeMode === 'contain') style.objectFit = 'contain';
26
29
  else if (resizeMode === 'stretch') style.objectFit = 'fill';
@@ -33,18 +36,19 @@ export function extractImageStyleNative<
33
36
  T extends ImagePropsGenerated['attributes'],
34
37
  >(node: NodeData<T>, options: ExtractViewStyleOptions = {}) {
35
38
  const attributes = node.attributes;
36
- const styleBag = (attributes as any)?.style as
37
- | Record<string, unknown>
38
- | undefined;
39
39
  if (!attributes) return {};
40
40
 
41
- const resizeMode = ((attributes as any)?.resizeMode ??
42
- styleBag?.resizeMode) as any;
41
+ // schemaVersion=2 uses `styles`, fallback to legacy `style`
42
+ const nativeStylesBag = getStyleBag(attributes) as
43
+ | ImagePropsGenerated['attributes']['style']
44
+ | undefined;
45
+ const resizeMode: ResizeModeOptionType | undefined =
46
+ nativeStylesBag?.resizeMode;
43
47
 
44
48
  // In RN, resizeMode is usually an Image prop, but many codebases also accept it on ImageStyle.
45
49
  // We return it here so consumers can pass it through as they prefer.
46
50
  const nativeStyle: Record<string, unknown> = {};
47
51
  if (resizeMode) nativeStyle.resizeMode = resizeMode;
48
52
 
49
- return { ...extractViewStyleNative(node, options as any), ...nativeStyle };
53
+ return { ...extractViewStyleNative(node, options), ...nativeStyle };
50
54
  }
@@ -17,6 +17,7 @@ import {
17
17
  resolveClosestFontWeightKey,
18
18
  } from '../loadFontFamily';
19
19
  import { fontsDebug } from '../fontsDebug';
20
+ import { getStyleBag, toAttributeRecord } from '../attributeStyle';
20
21
 
21
22
  const inFlightFontLoads: Map<string, Promise<void>> = new Map<
22
23
  string,
@@ -97,11 +98,10 @@ export function extractTextStyle<T extends TextPropsGenerated['attributes']>(
97
98
  options: ExtractTextStyleOptions = {},
98
99
  ) {
99
100
  const attributes = node.attributes;
100
- const styleBag = (attributes as Record<string, unknown>)?.style as
101
- | TextStyleGenerated
102
- | undefined;
101
+ const attrRecord = toAttributeRecord(attributes);
102
+ const styleBag = getStyleBag(attributes) as TextStyleGenerated | undefined;
103
103
  const get = (key: string): unknown => {
104
- const direct = (attributes as Record<string, unknown>)?.[key];
104
+ const direct = attrRecord[key];
105
105
  if (direct !== undefined && direct !== null) return direct;
106
106
  return styleBag?.[key as keyof TextStyleGenerated];
107
107
  };
@@ -199,15 +199,15 @@ export function extractTextStyle<T extends TextPropsGenerated['attributes']>(
199
199
  'textTransform',
200
200
  ]);
201
201
 
202
- const textStyle: React.CSSProperties = {};
202
+ const textStyle: Record<string, unknown> = {};
203
203
  for (const key in fullStyle) {
204
204
  const typedKey = key as keyof React.CSSProperties;
205
205
  if (textStyleProperties.has(typedKey)) {
206
- (textStyle as Record<string, unknown>)[key] = fullStyle[typedKey];
206
+ textStyle[key] = fullStyle[typedKey];
207
207
  }
208
208
  }
209
209
 
210
- return textStyle;
210
+ return textStyle as React.CSSProperties;
211
211
  }
212
212
 
213
213
  return fullStyle;
@@ -12,6 +12,7 @@ import {
12
12
  findFontDefinition,
13
13
  resolveClosestFontWeightKey,
14
14
  } from '../loadFontFamily';
15
+ import { getStyleBag, toAttributeRecord } from '../attributeStyle';
15
16
 
16
17
  export type ExtractTextStyleNativeOptions = {
17
18
  appConfig?: AppConfig;
@@ -37,11 +38,10 @@ export function extractTextStyleNative<
37
38
  T extends TextPropsGenerated['attributes'],
38
39
  >(node: NodeData<T>, options: ExtractTextStyleNativeOptions = {}) {
39
40
  const attributes = node.attributes;
40
- const styleBag = (attributes as any)?.style as
41
- | Record<string, unknown>
42
- | undefined;
41
+ const attrRecord = toAttributeRecord(attributes);
42
+ const styleBag = getStyleBag(attributes);
43
43
  const get = (key: string): unknown => {
44
- const direct = (attributes as any)?.[key];
44
+ const direct = attrRecord[key];
45
45
  if (direct !== undefined && direct !== null) return direct;
46
46
  return styleBag?.[key];
47
47
  };
@@ -58,13 +58,13 @@ export function extractTextStyleNative<
58
58
  return style;
59
59
  }
60
60
 
61
- const rawFontSize = get('fontSize') as any;
61
+ const rawFontSize = get('fontSize') as string | number | undefined;
62
62
  const parsedFontSize = parseSize(rawFontSize);
63
63
  if (typeof parsedFontSize === 'number') style.fontSize = parsedFontSize;
64
64
  else style.fontSize = fs(14);
65
65
 
66
- const fontFamily = get('fontFamily') as any;
67
- const fontWeight = get('fontWeight') as any;
66
+ const fontFamily = get('fontFamily') as string | undefined;
67
+ const fontWeight = get('fontWeight') as string | number | undefined;
68
68
  const requestedWeight = weightToNumericKey(fontWeight);
69
69
  const normalizedFontFamily =
70
70
  typeof fontFamily === 'string' && fontFamily.trim().length > 0
@@ -89,14 +89,14 @@ export function extractTextStyleNative<
89
89
  if (!normalizedFontFamily && normalizedFontWeight)
90
90
  style.fontWeight = normalizedFontWeight;
91
91
 
92
- const resolvedTextColor = parseColor(get('color') as any, {
92
+ const resolvedTextColor = parseColor(get('color') as string | undefined, {
93
93
  projectColors: options.projectColors,
94
94
  theme,
95
95
  });
96
96
  style.color = resolvedTextColor ?? fallbackColor;
97
97
 
98
- const textAlign = get('textAlign');
99
- if (textAlign) style.textAlign = textAlign as any;
98
+ const textAlign = get('textAlign') as string | undefined;
99
+ if (textAlign) style.textAlign = textAlign;
100
100
 
101
101
  const viewStyle = extractViewStyleNative(node, {
102
102
  projectColors: options.projectColors,
@@ -6,6 +6,7 @@ import type { NodeData } from '../../types/Node';
6
6
  import type { ProjectColors } from '../../types/Project';
7
7
  import { parseSize } from '../../size-matters';
8
8
  import { parseColor } from '../parseColor';
9
+ import { getStyleBag, toAttributeRecord } from '../attributeStyle';
9
10
 
10
11
  export type ExtractViewStyleOptions = {
11
12
  projectColors?: ProjectColors;
@@ -17,11 +18,10 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
17
18
  options: ExtractViewStyleOptions = {},
18
19
  ) {
19
20
  const attributes = node.attributes;
20
- const styleBag = (attributes as Record<string, unknown>)?.style as
21
- | ViewStyleGenerated
22
- | undefined;
21
+ const attrRecord = toAttributeRecord(attributes);
22
+ const styleBag = getStyleBag(attributes) as ViewStyleGenerated | undefined;
23
23
  const get = (key: string): unknown => {
24
- const direct = (attributes as Record<string, unknown>)?.[key];
24
+ const direct = attrRecord[key];
25
25
  if (direct !== undefined && direct !== null) return direct;
26
26
  return styleBag?.[key as keyof ViewStyleGenerated];
27
27
  };
@@ -112,10 +112,7 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
112
112
  );
113
113
 
114
114
  const marginHorizontalRaw =
115
- ((attributes as Record<string, unknown>).marginHorizontal as
116
- | string
117
- | number
118
- | undefined) ??
115
+ (attrRecord.marginHorizontal as string | number | undefined) ??
119
116
  (styleBag?.marginHorizontal as string | number | undefined);
120
117
  if (!isEmptySizeValue(marginHorizontalRaw)) {
121
118
  const parsed = parseSize(marginHorizontalRaw);
@@ -209,13 +206,13 @@ export function extractViewStyle<T extends ViewPropsGenerated['attributes']>(
209
206
  'overflowY',
210
207
  ]);
211
208
 
212
- const filteredStyle: React.CSSProperties = {};
209
+ const filteredStyle: Record<string, unknown> = {};
213
210
  for (const key in style) {
214
211
  const typedKey = key as keyof React.CSSProperties;
215
212
  if (viewStyleProperties.has(typedKey)) {
216
- (filteredStyle as Record<string, unknown>)[key] = style[typedKey];
213
+ filteredStyle[key] = style[typedKey];
217
214
  }
218
215
  }
219
216
 
220
- return filteredStyle;
217
+ return filteredStyle as React.CSSProperties;
221
218
  }
@@ -1,8 +1,9 @@
1
- import { ViewPropsGenerated } from '../../build-components/View/ViewProps.generated';
1
+ import type { ViewPropsGenerated } from '../../build-components/View/ViewProps.generated';
2
2
  import type { NodeData } from '../../types/Node';
3
3
  import type { ProjectColors } from '../../types/Project';
4
4
  import { parseSize } from '../../size-matters';
5
5
  import { parseColor } from '../parseColor';
6
+ import { getStyleBag, toAttributeRecord } from '../attributeStyle';
6
7
 
7
8
  export type ExtractViewStyleNativeOptions = {
8
9
  projectColors?: ProjectColors;
@@ -17,11 +18,10 @@ export function extractViewStyleNative<
17
18
  T extends ViewPropsGenerated['attributes'],
18
19
  >(node: NodeData<T>, options: ExtractViewStyleNativeOptions = {}) {
19
20
  const attributes = node.attributes;
20
- const styleBag = (attributes as any)?.style as
21
- | Record<string, unknown>
22
- | undefined;
21
+ const attrRecord = toAttributeRecord(attributes);
22
+ const styleBag = getStyleBag(attributes);
23
23
  const get = (key: string): unknown => {
24
- const direct = (attributes as any)?.[key];
24
+ const direct = attrRecord[key];
25
25
  if (direct !== undefined && direct !== null) return direct;
26
26
  return styleBag?.[key];
27
27
  };
@@ -41,18 +41,18 @@ export function extractViewStyleNative<
41
41
  // We intentionally do not map it to overflowX/Y.
42
42
 
43
43
  const flexDirection = get('flexDirection');
44
- if (flexDirection) style.flexDirection = flexDirection as any;
44
+ if (flexDirection) style.flexDirection = String(flexDirection);
45
45
  const alignItems = get('alignItems');
46
- if (alignItems) style.alignItems = alignItems as any;
46
+ if (alignItems) style.alignItems = String(alignItems);
47
47
  const justifyContent = get('justifyContent');
48
- if (justifyContent) style.justifyContent = justifyContent as any;
48
+ if (justifyContent) style.justifyContent = String(justifyContent);
49
49
 
50
50
  const setParsedSize = (property: string, rawValue: unknown) => {
51
51
  if (isEmptySizeValue(rawValue)) return;
52
- const parsed = parseSize(rawValue as any);
52
+ const parsed = parseSize(rawValue as string | number);
53
53
  // RN generally expects numbers (dp). We allow percentages for width/height-like props.
54
54
  if (typeof parsed === 'number' || typeof parsed === 'string') {
55
- (style as any)[property] = parsed;
55
+ style[property] = parsed;
56
56
  }
57
57
  };
58
58
 
@@ -68,7 +68,7 @@ export function extractViewStyleNative<
68
68
  setParsedSize('margin', get('margin'));
69
69
  setParsedSize(
70
70
  'marginHorizontal',
71
- (attributes as any)?.marginHorizontal ?? styleBag?.marginHorizontal,
71
+ attrRecord.marginHorizontal ?? styleBag?.marginHorizontal,
72
72
  );
73
73
  setParsedSize('marginVertical', get('marginVertical'));
74
74
  setParsedSize('marginTop', get('marginTop'));
@@ -76,9 +76,9 @@ export function extractViewStyleNative<
76
76
  setParsedSize('marginLeft', get('marginLeft'));
77
77
  setParsedSize('marginRight', get('marginRight'));
78
78
 
79
- const backgroundColor = get('backgroundColor') as any;
79
+ const backgroundColor = get('backgroundColor') as string | undefined;
80
80
  if (backgroundColor) {
81
- (style as any).backgroundColor =
81
+ style.backgroundColor =
82
82
  parseColor(backgroundColor, {
83
83
  projectColors: options.projectColors,
84
84
  theme: options.theme,
@@ -93,19 +93,19 @@ export function extractViewStyleNative<
93
93
  setParsedSize('minHeight', get('minHeight'));
94
94
  setParsedSize('maxHeight', get('maxHeight'));
95
95
 
96
- const flex = get('flex') as any;
97
- if (flex !== undefined) (style as any).flex = flex;
96
+ const flex = get('flex') as number | undefined;
97
+ if (flex !== undefined) style.flex = flex;
98
98
 
99
- const position = get('position') as any;
100
- if (position) (style as any).position = position;
99
+ const position = get('position') as string | undefined;
100
+ if (position) style.position = position;
101
101
 
102
102
  setParsedSize('top', get('top'));
103
103
  setParsedSize('bottom', get('bottom'));
104
104
  setParsedSize('left', get('left'));
105
105
  setParsedSize('right', get('right'));
106
106
 
107
- const zIndex = get('zIndex') as any;
108
- if (zIndex !== undefined) (style as any).zIndex = zIndex;
107
+ const zIndex = get('zIndex') as number | undefined;
108
+ if (zIndex !== undefined) style.zIndex = zIndex;
109
109
 
110
110
  return style;
111
111
  }
@@ -124,25 +124,20 @@ export async function loadFontFamily(
124
124
  // Not a browser environment (SSR / RN): do nothing.
125
125
  if (typeof document === 'undefined') return;
126
126
 
127
- const fontsApi = (document as any).fonts as FontFaceSet | undefined;
128
- if (!fontsApi || typeof (globalThis as any).FontFace !== 'function') {
127
+ const fontsApi = document.fonts;
128
+ if (!fontsApi || typeof globalThis.FontFace !== 'function') {
129
129
  throw new Error('Font loading is not supported in this environment');
130
130
  }
131
- const safeFontsApi = fontsApi as FontFaceSet;
132
131
 
133
132
  function hasLoadedFace(familyName: string, weight: string): boolean {
134
133
  try {
135
- const set = safeFontsApi as unknown as Iterable<FontFace>;
136
- for (const face of set) {
137
- const f = face as unknown as {
138
- family?: string;
139
- weight?: string;
140
- status?: string;
141
- };
134
+ for (const face of fontsApi) {
142
135
  const fam =
143
- typeof f.family === 'string' ? f.family.replace(/['"]/g, '') : '';
144
- const w = typeof f.weight === 'string' ? f.weight.trim() : '';
145
- if (fam === familyName && w === weight && f.status === 'loaded') {
136
+ typeof face.family === 'string'
137
+ ? face.family.replace(/['"]/g, '')
138
+ : '';
139
+ const w = typeof face.weight === 'string' ? face.weight.trim() : '';
140
+ if (fam === familyName && w === weight && face.status === 'loaded') {
146
141
  return true;
147
142
  }
148
143
  }
@@ -251,17 +246,17 @@ export async function loadFontFamily(
251
246
  }
252
247
 
253
248
  async function loadAndAdd(src: string | ArrayBuffer, label: string) {
254
- const face = new (globalThis as any).FontFace(name, src as any, {
249
+ const face = new FontFace(name, src, {
255
250
  weight: preferWeight,
256
251
  display: 'swap',
257
- }) as FontFace;
252
+ });
258
253
  fontsDebug.info('loadFontFamily: FontFace.load() begin', {
259
254
  familyName: name,
260
255
  weight: preferWeight,
261
256
  source: label,
262
257
  });
263
258
  const loaded = await face.load();
264
- safeFontsApi.add(loaded);
259
+ fontsApi.add(loaded);
265
260
  fontsDebug.info('loadFontFamily: loaded + added to document.fonts', {
266
261
  familyName: name,
267
262
  weight: preferWeight,
@@ -296,18 +291,18 @@ export async function loadFontFamily(
296
291
 
297
292
  try {
298
293
  const afterQuery = `${preferWeight} 16px "${name}"`;
299
- const after = safeFontsApi.check(afterQuery);
294
+ const after = fontsApi.check(afterQuery);
300
295
  fontsDebug.info('loadFontFamily: document.fonts.check after add', {
301
296
  familyName: name,
302
297
  weight: preferWeight,
303
298
  result: after,
304
299
  });
305
300
  // Force the browser to "activate" the face for this query (and reveal errors if any).
306
- if (typeof (safeFontsApi as any).load === 'function') {
301
+ if (typeof fontsApi.load === 'function') {
307
302
  fontsDebug.info('loadFontFamily: document.fonts.load begin', {
308
303
  query: afterQuery,
309
304
  });
310
- await (safeFontsApi as any).load(afterQuery);
305
+ await fontsApi.load(afterQuery);
311
306
  fontsDebug.info('loadFontFamily: document.fonts.load done', {
312
307
  query: afterQuery,
313
308
  });
@@ -67,20 +67,21 @@ export function logRenderStore(options: LogRenderStoreOptions = {}): void {
67
67
  const { label, includeLocalStorage = true, extra } = options;
68
68
 
69
69
  const state = useRenderStore.getState();
70
- const keys = Object.keys(state as Record<string, unknown>).sort();
70
+ const stateRecord = state as Record<string, unknown>;
71
+ const keys = Object.keys(stateRecord).sort();
71
72
 
72
73
  const snapshot: Record<string, unknown> = {};
73
74
  const actions: string[] = [];
74
75
 
75
76
  for (const key of keys) {
76
- const v = (state as any)[key];
77
+ const v = stateRecord[key];
77
78
  if (isFn(v)) actions.push(key);
78
79
  else snapshot[key] = v;
79
80
  }
80
81
 
81
82
  const title = `[RB Debug] Render store${label ? ` (${label})` : ''}`;
82
- const groupCollapsed = (console as any).groupCollapsed as unknown;
83
- const groupEnd = (console as any).groupEnd as unknown;
83
+ const groupCollapsed = console.groupCollapsed as unknown;
84
+ const groupEnd = console.groupEnd as unknown;
84
85
 
85
86
  if (isFn(groupCollapsed)) groupCollapsed(title);
86
87
  else {
@@ -19,7 +19,7 @@ export function deleteNodeFromTree(root: Node, target: Node): Node {
19
19
  return changed ? nextChildren : root;
20
20
  }
21
21
 
22
- const data = root as any;
22
+ const data = root as NodeData;
23
23
  if ('children' in data) {
24
24
  const prev = data.children as Node;
25
25
  if (!prev) return root;
@@ -61,7 +61,7 @@ type Pattern = {
61
61
  meta?: PatternMeta;
62
62
  };
63
63
 
64
- const patterns: Pattern[] = generatedPatterns as unknown as Pattern[];
64
+ const patterns = generatedPatterns as unknown as Pattern[];
65
65
 
66
66
  export type BuilderPlatform = 'web' | 'native';
67
67
 
@@ -86,16 +86,22 @@ export const NON_STYLE_ATTRIBUTE_KEYS = new Set<string>([
86
86
  * known non-style props (behavior flags).
87
87
  */
88
88
  export function getStyleAttributeKeySet(): Set<string> {
89
- const viewSchema = getAttributeSchema('View') ?? {};
90
- const textSchema = getAttributeSchema('Text') ?? {};
91
- const viewStyle =
92
- typeof (viewSchema as any)?.style === 'object' && (viewSchema as any)?.style
93
- ? Object.keys((viewSchema as any).style)
94
- : Object.keys(viewSchema);
95
- const textStyle =
96
- typeof (textSchema as any)?.style === 'object' && (textSchema as any)?.style
97
- ? Object.keys((textSchema as any).style)
98
- : Object.keys(textSchema);
89
+ const viewSchema = (getAttributeSchema('View') ?? {}) as Record<
90
+ string,
91
+ unknown
92
+ >;
93
+ const textSchema = (getAttributeSchema('Text') ?? {}) as Record<
94
+ string,
95
+ unknown
96
+ >;
97
+ const getNestedStyleKeys = (schema: Record<string, unknown>): string[] => {
98
+ const nested = schema.style;
99
+ return typeof nested === 'object' && nested
100
+ ? Object.keys(nested)
101
+ : Object.keys(schema);
102
+ };
103
+ const viewStyle = getNestedStyleKeys(viewSchema);
104
+ const textStyle = getNestedStyleKeys(textSchema);
99
105
  const out = new Set<string>([...viewStyle, ...textStyle]);
100
106
  for (const k of NON_STYLE_ATTRIBUTE_KEYS) out.delete(k);
101
107
  return out;
@@ -209,23 +215,18 @@ export function getAttributeMeta(
209
215
  const attributes = p?.meta?.attributes;
210
216
 
211
217
  // Some patterns store style meta under `meta.attributes.styles` (nested) instead of `meta.styles`.
218
+ const attrsRecord = attributes as Record<string, unknown> | undefined;
212
219
  const nestedStyles =
213
- attributes &&
214
- typeof attributes === 'object' &&
215
- (attributes as any).styles &&
216
- typeof (attributes as any).styles === 'object'
217
- ? ((attributes as any).styles as Record<string, AttributeMeta>)
220
+ attrsRecord && typeof attrsRecord.styles === 'object' && attrsRecord.styles
221
+ ? (attrsRecord.styles as Record<string, AttributeMeta>)
218
222
  : undefined;
219
223
 
220
224
  // When `meta.attributes.styles` exists, treat `meta.attributes` (minus `styles`) as non-style meta.
221
- const attributesWithoutNestedStyles =
222
- attributes && typeof attributes === 'object'
223
- ? Object.fromEntries(
224
- Object.entries(attributes as Record<string, unknown>).filter(
225
- ([k]) => k !== 'styles',
226
- ),
227
- )
228
- : attributes;
225
+ const attributesWithoutNestedStyles = attrsRecord
226
+ ? Object.fromEntries(
227
+ Object.entries(attrsRecord).filter(([k]) => k !== 'styles'),
228
+ )
229
+ : attributes;
229
230
 
230
231
  // schemaVersion=2 prefers `meta.styles` but some repos split UI meta into:
231
232
  // - meta.styles: style-tab fields
@@ -261,13 +262,7 @@ export function getTypeSchema(
261
262
  ): Record<string, string | string[]> | undefined {
262
263
  if (!componentType || !typeName) return undefined;
263
264
  const p = getPatternByType(componentType);
264
- // Some JSON imports may not type-check "types" so we fallback to any access
265
- const types: Record<string, Record<string, string | string[]>> | undefined = (
266
- p as unknown as {
267
- types?: Record<string, Record<string, string | string[]>>;
268
- }
269
- )?.types;
270
- return types?.[typeName];
265
+ return p?.types?.[typeName];
271
266
  }
272
267
 
273
268
  /** Utility: returns true if the type name refers to a primitive scalar */
@@ -2,13 +2,11 @@ import type { Node, NodeData } from '../types/Node';
2
2
  import { generateRandomKeyForNode } from './generateRandomKeyForNode';
3
3
 
4
4
  function isNodeDataLike(value: unknown): value is NodeData {
5
- return (
6
- typeof value === 'object' &&
7
- value !== null &&
8
- !Array.isArray(value) &&
9
- 'type' in (value as any) &&
10
- 'children' in (value as any)
11
- );
5
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
6
+ return false;
7
+ }
8
+ const record = value as Record<string, unknown>;
9
+ return 'type' in record && 'children' in record;
12
10
  }
13
11
 
14
12
  function normalizeKey(value: unknown): string | undefined {
@@ -39,10 +39,10 @@ function stripNestedIsMain(node: Node, isRoot: boolean): Node {
39
39
  if (!shouldDemote && nextChildren === prevChildren) return node;
40
40
 
41
41
  return {
42
- ...(node as any),
42
+ ...node,
43
43
  ...(shouldDemote ? { isMain: false } : null),
44
44
  children: nextChildren,
45
- } as NodeData;
45
+ };
46
46
  }
47
47
 
48
48
  export function wrapNodeInMain(node: Node): NodeData {
@@ -50,7 +50,7 @@ export function wrapNodeInMain(node: Node): NodeData {
50
50
  // Ensure no nested nodes keep `isMain: true`.
51
51
  const cleaned = stripNestedIsMain(node, true) as NodeData;
52
52
  // Keep root as main.
53
- if (cleaned.isMain !== true) return { ...(cleaned as any), isMain: true };
53
+ if (cleaned.isMain !== true) return { ...cleaned, isMain: true };
54
54
  return cleaned;
55
55
  }
56
56