@developer_tribe/react-builder 1.2.24 → 1.2.25

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 (137) hide show
  1. package/dist/attributes-editor/SpecialCategorySection.d.ts +2 -1
  2. package/dist/attributes-editor/attributesEditorModelTypes.d.ts +2 -0
  3. package/dist/build-components/BIcon/BIconProps.generated.d.ts +0 -2
  4. package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +0 -2
  5. package/dist/build-components/Button/ButtonProps.generated.d.ts +0 -2
  6. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +0 -2
  7. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +0 -2
  8. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +0 -2
  9. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +0 -2
  10. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +0 -2
  11. package/dist/build-components/CountDown/CountDownProps.generated.d.ts +0 -2
  12. package/dist/build-components/Counter/CounterProps.generated.d.ts +0 -2
  13. package/dist/build-components/Image/ImageProps.generated.d.ts +0 -2
  14. package/dist/build-components/Main/MainProps.generated.d.ts +0 -2
  15. package/dist/build-components/NavigationBarColor/NavigationBarColorProps.generated.d.ts +0 -2
  16. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +0 -2
  17. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +0 -2
  18. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +0 -2
  19. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +0 -2
  20. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +0 -2
  21. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +0 -2
  22. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +0 -2
  23. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +0 -2
  24. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +0 -2
  25. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +0 -2
  26. package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +0 -2
  27. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +0 -2
  28. package/dist/build-components/PaywallCounter/PaywallCounterProps.generated.d.ts +0 -2
  29. package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +0 -2
  30. package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +0 -2
  31. package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +0 -2
  32. package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +0 -2
  33. package/dist/build-components/Separator/SeparatorProps.generated.d.ts +0 -2
  34. package/dist/build-components/StatusBarColor/StatusBarColorProps.generated.d.ts +0 -2
  35. package/dist/build-components/Text/TextProps.generated.d.ts +0 -2
  36. package/dist/build-components/patterns.generated.d.ts +76 -70
  37. package/dist/index.cjs.js +1 -1
  38. package/dist/index.cjs.js.map +1 -1
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.esm.js +3 -3
  41. package/dist/index.esm.js.map +1 -1
  42. package/dist/index.web.cjs.js +4 -4
  43. package/dist/index.web.cjs.js.map +1 -1
  44. package/dist/index.web.esm.js +2 -2
  45. package/dist/index.web.esm.js.map +1 -1
  46. package/dist/pages/ProjectPage.d.ts +2 -2
  47. package/dist/pages/projectPageUtils.d.ts +7 -1
  48. package/dist/types/Project.d.ts +6 -0
  49. package/dist/utils/patterns.d.ts +2 -0
  50. package/package.json +1 -1
  51. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +11 -2
  52. package/src/AttributesEditor.tsx +15 -4
  53. package/src/assets/meta.json +1 -1
  54. package/src/assets/samples/paywall-app-delete-offer.json +0 -1
  55. package/src/assets/samples/paywall-app-open-offer.json +0 -1
  56. package/src/assets/samples/paywall-back-offer.json +0 -1
  57. package/src/assets/samples/paywall-notification-offer.json +0 -1
  58. package/src/assets/samples/simple-2.json +0 -1
  59. package/src/attributes-editor/AttributesEditorView.tsx +43 -36
  60. package/src/attributes-editor/SpecialCategorySection.tsx +5 -3
  61. package/src/attributes-editor/attributesEditorModelTypes.ts +2 -0
  62. package/src/attributes-editor/useAttributesEditorModel.ts +6 -0
  63. package/src/build-components/BIcon/BIconProps.generated.ts +0 -2
  64. package/src/build-components/BIcon/pattern.json +5 -3
  65. package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +0 -2
  66. package/src/build-components/BackgroundImage/pattern.json +12 -4
  67. package/src/build-components/Button/ButtonProps.generated.ts +0 -2
  68. package/src/build-components/Button/pattern.json +5 -3
  69. package/src/build-components/Carousel/CarouselProps.generated.ts +0 -2
  70. package/src/build-components/Carousel/pattern.json +11 -5
  71. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +0 -2
  72. package/src/build-components/CarouselButtons/pattern.json +11 -4
  73. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +0 -2
  74. package/src/build-components/CarouselDots/pattern.json +5 -3
  75. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +0 -2
  76. package/src/build-components/CarouselItem/pattern.json +6 -6
  77. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +0 -2
  78. package/src/build-components/CarouselProvider/pattern.json +6 -5
  79. package/src/build-components/CountDown/CountDownProps.generated.ts +0 -2
  80. package/src/build-components/CountDown/pattern.json +6 -3
  81. package/src/build-components/Counter/CounterProps.generated.ts +0 -2
  82. package/src/build-components/Counter/pattern.json +5 -1
  83. package/src/build-components/Image/ImageProps.generated.ts +0 -2
  84. package/src/build-components/Image/pattern.json +5 -3
  85. package/src/build-components/Main/MainProps.generated.ts +0 -2
  86. package/src/build-components/Main/pattern.json +5 -3
  87. package/src/build-components/NavigationBarColor/NavigationBarColorProps.generated.ts +0 -2
  88. package/src/build-components/NavigationBarColor/pattern.json +5 -3
  89. package/src/build-components/Onboard/OnboardProps.generated.ts +0 -2
  90. package/src/build-components/Onboard/pattern.json +9 -7
  91. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +0 -2
  92. package/src/build-components/OnboardButton/pattern.json +16 -5
  93. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +0 -2
  94. package/src/build-components/OnboardButtons/pattern.json +17 -6
  95. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +0 -2
  96. package/src/build-components/OnboardDot/pattern.json +5 -3
  97. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +0 -2
  98. package/src/build-components/OnboardFooter/pattern.json +5 -3
  99. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +0 -2
  100. package/src/build-components/OnboardImage/pattern.json +7 -3
  101. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +0 -2
  102. package/src/build-components/OnboardItem/pattern.json +13 -5
  103. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +0 -2
  104. package/src/build-components/OnboardProvider/pattern.json +10 -4
  105. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +0 -2
  106. package/src/build-components/OnboardSubtitle/pattern.json +7 -6
  107. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +0 -2
  108. package/src/build-components/OnboardTitle/pattern.json +7 -6
  109. package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +0 -2
  110. package/src/build-components/PaywallBackground/pattern.json +5 -5
  111. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +0 -2
  112. package/src/build-components/PaywallCloseButton/pattern.json +6 -6
  113. package/src/build-components/PaywallCounter/PaywallCounterProps.generated.ts +0 -2
  114. package/src/build-components/PaywallCounter/pattern.json +6 -3
  115. package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +0 -2
  116. package/src/build-components/PaywallOptions/pattern.json +6 -6
  117. package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +0 -2
  118. package/src/build-components/PaywallProvider/pattern.json +5 -3
  119. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +0 -2
  120. package/src/build-components/PaywallSubscribeButton/pattern.json +6 -6
  121. package/src/build-components/RadioButton/RadioButtonProps.generated.ts +0 -2
  122. package/src/build-components/RadioButton/pattern.json +5 -3
  123. package/src/build-components/Separator/SeparatorProps.generated.ts +0 -2
  124. package/src/build-components/Separator/pattern.json +5 -3
  125. package/src/build-components/StatusBarColor/StatusBarColorProps.generated.ts +0 -2
  126. package/src/build-components/StatusBarColor/pattern.json +5 -3
  127. package/src/build-components/Text/TextProps.generated.ts +0 -2
  128. package/src/build-components/Text/pattern.json +11 -5
  129. package/src/build-components/View/pattern.json +18 -4
  130. package/src/build-components/patterns.generated.ts +72 -70
  131. package/src/components/AttributesEditorPanel.tsx +48 -32
  132. package/src/components/Builder.tsx +4 -1
  133. package/src/index.ts +1 -1
  134. package/src/pages/ProjectPage.tsx +45 -22
  135. package/src/pages/projectPageUtils.ts +15 -1
  136. package/src/types/Project.ts +7 -0
  137. package/src/utils/patterns.ts +2 -0
@@ -1,10 +1,10 @@
1
- import type { Project, ProjectColors } from '../types/Project';
1
+ import type { Project, ProjectColors, ProjectMeta } from '../types/Project';
2
2
  import { AppConfig } from '../types/PreviewConfig';
3
3
  import type { LogLevel } from '../types/Project';
4
4
  import type { Fonts } from '../types/Fonts';
5
5
  export type ProjectPageProps = {
6
6
  project: Project;
7
- onSaveProject: (project: Project) => void;
7
+ onSaveProject: (project: ProjectMeta) => void;
8
8
  appConfig?: AppConfig;
9
9
  logLevel?: LogLevel;
10
10
  projectColors?: ProjectColors;
@@ -1,7 +1,13 @@
1
- import type { Project } from '../types/Project';
1
+ import type { Project, ProjectMeta } from '../types/Project';
2
2
  import type { Node } from '../types/Node';
3
3
  export declare function resolveProjectForSave(args: {
4
4
  project: Project;
5
5
  overrideProject?: Project | null;
6
6
  data: Node;
7
7
  }): Project;
8
+ /**
9
+ * Strips a full Project down to its essential persistence fields.
10
+ * Use before handing the project to onSaveProject so consumers only
11
+ * receive the canonical metadata (name, version, type, data).
12
+ */
13
+ export declare function toProjectMeta(project: Project): ProjectMeta;
@@ -24,6 +24,12 @@ export interface ProjectBase<T> {
24
24
  }
25
25
  export interface Project extends ProjectBase<Node> {
26
26
  }
27
+ /**
28
+ * Lightweight subset of Project containing only the essential metadata
29
+ * needed for persistence (name, version, type, data).
30
+ * Excludes runtime/editor-only fields like appConfig and projectColors.
31
+ */
32
+ export type ProjectMeta = Pick<Project, 'name' | 'version' | 'type' | 'data'>;
27
33
  export type LogLevel = 'NONE' | 'ERROR' | 'WARN' | 'INFO' | 'VERBOSE';
28
34
  export type LogSource = string;
29
35
  export interface LogEntry {
@@ -41,6 +41,8 @@ type Pattern = {
41
41
  schemaVersion: number;
42
42
  pattern: {
43
43
  type: string;
44
+ title?: string;
45
+ description?: string;
44
46
  children: unknown;
45
47
  attributes?: Record<string, string | string[]>;
46
48
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@developer_tribe/react-builder",
3
- "version": "1.2.24",
3
+ "version": "1.2.25",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "restricted": true,
@@ -120,11 +120,20 @@ async function validatePatternJson(componentDir, componentName) {
120
120
  `[${componentName}] pattern.json -> 'pattern.children' must be one of: node | string | never`
121
121
  );
122
122
  }
123
- if (typeof pattern.attributes !== 'object' || pattern.attributes == null) {
123
+ // pattern.attributes is optional components that only declare title/description
124
+ // (now at pattern level) may have no extra attributes at all.
125
+ if (
126
+ Object.prototype.hasOwnProperty.call(pattern, 'attributes') &&
127
+ (typeof pattern.attributes !== 'object' || pattern.attributes == null)
128
+ ) {
124
129
  return fail(
125
- `[${componentName}] pattern.json -> 'pattern.attributes' must be an object`
130
+ `[${componentName}] pattern.json -> 'pattern.attributes' must be an object (or omitted)`
126
131
  );
127
132
  }
133
+ // Normalise missing attributes to empty object for the rest of the validation
134
+ if (!pattern.attributes) {
135
+ pattern.attributes = {};
136
+ }
128
137
 
129
138
  // Helpers for validating custom types
130
139
  const isPrimitive = t =>
@@ -1,4 +1,4 @@
1
- import { useEffect } from 'react';
1
+ import { useEffect, useRef } from 'react';
2
2
  import type { AttributesEditorProps } from './attributes-editor/attributesEditorModelTypes';
3
3
  import { useLogRender } from './utils/useLogRender';
4
4
  import { AttributesEditorView } from './attributes-editor/AttributesEditorView';
@@ -8,11 +8,22 @@ export function AttributesEditor(props: AttributesEditorProps) {
8
8
  useLogRender('AttributesEditor');
9
9
  const model = useAttributesEditorModel(props);
10
10
  const titleValue = model.attributes?.title;
11
+ const hasTitleField = model.hasTitleField;
12
+
13
+ // Keep a stable ref so the effect doesn't re-run when the callback
14
+ // reference changes (which happens every render due to unstable onChange prop).
15
+ const handleAttributeChangeRef = useRef(model.handleAttributeChange);
16
+ handleAttributeChangeRef.current = model.handleAttributeChange;
17
+
11
18
  useEffect(() => {
12
- if (typeof titleValue === 'string' && titleValue.length > 20) {
13
- model.handleAttributeChange('title', titleValue.slice(0, 20));
19
+ if (
20
+ hasTitleField &&
21
+ typeof titleValue === 'string' &&
22
+ titleValue.length > 20
23
+ ) {
24
+ handleAttributeChangeRef.current('title', titleValue.slice(0, 20));
14
25
  }
15
- }, [titleValue, model.handleAttributeChange]);
26
+ }, [hasTitleField, titleValue]);
16
27
  return <AttributesEditorView {...model} />;
17
28
  }
18
29
 
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "supportedProjectVersion": "1.1.2",
3
- "reactBuilderVersion": "1.2.23"
3
+ "reactBuilderVersion": "1.2.24"
4
4
  }
@@ -68,7 +68,6 @@
68
68
  "type": "PaywallBackground",
69
69
  "attributes": {
70
70
  "src": "https://images.unsplash.com/photo-1496307042754-b4aa456c4a2d?auto=format&fit=crop&w=1200&q=80",
71
- "resizeMode": "cover",
72
71
  "description": "Paywall background.",
73
72
  "title": "Paywall Background"
74
73
  },
@@ -68,7 +68,6 @@
68
68
  "type": "PaywallBackground",
69
69
  "attributes": {
70
70
  "src": "https://images.unsplash.com/photo-1501785888041-af3ef285b470?auto=format&fit=crop&w=1200&q=80",
71
- "resizeMode": "cover",
72
71
  "description": "Paywall background.",
73
72
  "title": "Paywall Background"
74
73
  },
@@ -68,7 +68,6 @@
68
68
  "type": "PaywallBackground",
69
69
  "attributes": {
70
70
  "src": "https://images.unsplash.com/photo-1470770903676-69b98201ea1c?auto=format&fit=crop&w=1200&q=80",
71
- "resizeMode": "cover",
72
71
  "description": "Paywall background.",
73
72
  "title": "Paywall Background"
74
73
  },
@@ -68,7 +68,6 @@
68
68
  "type": "PaywallBackground",
69
69
  "attributes": {
70
70
  "src": "https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=1200&q=80",
71
- "resizeMode": "cover",
72
71
  "description": "Paywall background.",
73
72
  "title": "Paywall Background"
74
73
  },
@@ -104,7 +104,6 @@
104
104
  "type": "image",
105
105
  "attributes": {
106
106
  "src": "https://picsum.photos/720/320",
107
- "resizeMode": "cover",
108
107
  "description": "image element 1 in sample.",
109
108
  "title": "image 1",
110
109
  "styles": {
@@ -63,6 +63,8 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
63
63
  firstAvailableTab,
64
64
  activeEntries,
65
65
  activeSpecialSections,
66
+ hasTitleField,
67
+ hasDescriptionField,
66
68
  hasStringChildren,
67
69
  childrenValue,
68
70
  handleChildrenChange,
@@ -94,37 +96,46 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
94
96
 
95
97
  const titleValue = getAttributeValue('title');
96
98
  const descriptionValue = getAttributeValue('description');
97
- const topFieldsSection = !isInvalidNode ? (
99
+ const showTopFields =
100
+ !isInvalidNode && (hasTitleField || hasDescriptionField);
101
+ const topFieldsSection = showTopFields ? (
98
102
  <section className="attributes-editor__top-fields">
99
- <div className="attributes-editor__field-wrapper">
100
- <label className="attributes-editor__field-label" htmlFor="title">
101
- Title (max 20 characters for display purposes)
102
- </label>
103
- <input
104
- id="title"
105
- className="input"
106
- type="text"
107
- maxLength={20}
108
- value={typeof titleValue === 'string' ? titleValue : ''}
109
- onChange={(event) =>
110
- handleAttributeChange('title', event.target.value)
111
- }
112
- />
113
- </div>
114
- <div className="attributes-editor__field-wrapper">
115
- <label className="attributes-editor__field-label" htmlFor="description">
116
- Description (for display purposes)
117
- </label>
118
- <input
119
- id="description"
120
- className="input"
121
- type="text"
122
- value={typeof descriptionValue === 'string' ? descriptionValue : ''}
123
- onChange={(event) =>
124
- handleAttributeChange('description', event.target.value)
125
- }
126
- />
127
- </div>
103
+ {hasTitleField ? (
104
+ <div className="attributes-editor__field-wrapper">
105
+ <label className="attributes-editor__field-label" htmlFor="title">
106
+ Title (max 20 characters for display purposes)
107
+ </label>
108
+ <input
109
+ id="title"
110
+ className="input"
111
+ type="text"
112
+ maxLength={20}
113
+ value={typeof titleValue === 'string' ? titleValue : ''}
114
+ onChange={(event) =>
115
+ handleAttributeChange('title', event.target.value)
116
+ }
117
+ />
118
+ </div>
119
+ ) : null}
120
+ {hasDescriptionField ? (
121
+ <div className="attributes-editor__field-wrapper">
122
+ <label
123
+ className="attributes-editor__field-label"
124
+ htmlFor="description"
125
+ >
126
+ Description (for display purposes)
127
+ </label>
128
+ <input
129
+ id="description"
130
+ className="input"
131
+ type="text"
132
+ value={typeof descriptionValue === 'string' ? descriptionValue : ''}
133
+ onChange={(event) =>
134
+ handleAttributeChange('description', event.target.value)
135
+ }
136
+ />
137
+ </div>
138
+ ) : null}
128
139
  </section>
129
140
  ) : null;
130
141
 
@@ -346,18 +357,14 @@ export function AttributesEditorView(props: AttributesEditorViewProps) {
346
357
  );
347
358
  }
348
359
 
349
- const sectionAttributes =
350
- section.meta?.category === 'style'
351
- ? ((styleBag ?? {}) as unknown as NodeDefaultAttribute)
352
- : attributes;
353
-
354
360
  return (
355
361
  <SpecialCategorySection
356
362
  key={section.key}
357
363
  category={section.key}
358
364
  entries={section.entries}
359
365
  attributeMeta={attributeMeta}
360
- attributes={sectionAttributes}
366
+ attributes={attributes}
367
+ getAttributeValue={getAttributeValue}
361
368
  onAttributeChange={handleAttributeChange}
362
369
  componentType={data?.type}
363
370
  projectColors={projectColorsForPicker}
@@ -16,6 +16,7 @@ type SpecialCategorySectionProps = {
16
16
  entries: SchemaEntry[];
17
17
  attributeMeta?: AttributeMetaMap;
18
18
  attributes: NodeDefaultAttribute;
19
+ getAttributeValue: (name: string) => unknown;
19
20
  onAttributeChange: (name: string, value: unknown) => void;
20
21
  componentType?: string;
21
22
  projectColors?: ProjectColors;
@@ -41,6 +42,7 @@ export function SpecialCategorySection({
41
42
  entries,
42
43
  attributeMeta,
43
44
  attributes,
45
+ getAttributeValue,
44
46
  onAttributeChange,
45
47
  componentType,
46
48
  projectColors,
@@ -96,7 +98,7 @@ export function SpecialCategorySection({
96
98
  const preferredScale = toPreferredScale(
97
99
  attributeMeta?.[name]?.preferedScale,
98
100
  );
99
- const currentValue = (attributes as Record<string, unknown>)[name];
101
+ const currentValue = getAttributeValue(name);
100
102
  const isBoolean = isBooleanFieldType(type);
101
103
  const fieldSlot = detectFieldSlot(name);
102
104
  const wrapperClassNames = [
@@ -175,7 +177,7 @@ export function SpecialCategorySection({
175
177
  const preferredScale = toPreferredScale(
176
178
  attributeMeta?.[name]?.preferedScale,
177
179
  );
178
- const currentValue = (attributes as Record<string, unknown>)[name];
180
+ const currentValue = getAttributeValue(name);
179
181
  const isBoolean = isBooleanFieldType(type);
180
182
  const fieldSlot = detectFieldSlot(name);
181
183
  const wrapperClassNames = [
@@ -220,7 +222,7 @@ export function SpecialCategorySection({
220
222
  const preferredScale = toPreferredScale(
221
223
  attributeMeta?.[name]?.preferedScale,
222
224
  );
223
- const currentValue = (attributes as Record<string, unknown>)[name];
225
+ const currentValue = getAttributeValue(name);
224
226
  const isBoolean = isBooleanFieldType(type);
225
227
  const wrapperClassNames = [
226
228
  'attributes-editor__field-wrapper',
@@ -81,6 +81,8 @@ export type AttributesEditorModel = {
81
81
  mockableFeatureKeys: string[];
82
82
  activeMockableFeature: string | null;
83
83
  setActiveMockableFeature: (next: string | null) => void;
84
+ hasTitleField: boolean;
85
+ hasDescriptionField: boolean;
84
86
  hasStringChildren: boolean;
85
87
  childrenValue: string;
86
88
  };
@@ -217,6 +217,10 @@ export function useAttributesEditorModel({
217
217
  const componentTitle = componentMeta?.label ?? data?.type ?? 'Component';
218
218
  const componentDescription = componentMeta?.description;
219
219
 
220
+ const hasTitleField = patternForType?.pattern?.title === 'title';
221
+ const hasDescriptionField =
222
+ patternForType?.pattern?.description === 'description';
223
+
220
224
  const entries = useMemo(() => {
221
225
  return buildAttributesEditorEntries(schema, attributeMeta).filter(
222
226
  ({ type }) => (typeof type === 'string' ? type !== 'never' : true),
@@ -477,6 +481,8 @@ export function useAttributesEditorModel({
477
481
  mockableFeatureKeys,
478
482
  activeMockableFeature,
479
483
  setActiveMockableFeature,
484
+ hasTitleField,
485
+ hasDescriptionField,
480
486
  hasStringChildren,
481
487
  childrenValue,
482
488
  };
@@ -66,8 +66,6 @@ export interface BIconPropsGenerated {
66
66
  child: string;
67
67
  attributes: {
68
68
  style?: BIconStyleGenerated;
69
- title?: string;
70
- description?: string;
71
69
  adjustsFontSizeToFit?: boolean;
72
70
  showEllipsis?: boolean;
73
71
  scrollable?: boolean;
@@ -2,18 +2,20 @@
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
4
  "type": "BIcon",
5
+ "title": "title",
6
+ "description": "description",
5
7
  "children": "never",
6
8
  "extends": "Text",
7
9
  "attributes": {
8
- "title": "title",
9
- "description": "description",
10
10
  "iconType": "iconType",
11
11
  "size": "number",
12
12
  "strokeWidth": "number"
13
13
  }
14
14
  },
15
15
  "meta": {
16
- "desiredParent": ["all"],
16
+ "desiredParent": [
17
+ "all"
18
+ ],
17
19
  "label": "BIcon",
18
20
  "description": "Renders an icon from the icon set.",
19
21
  "styles": {},
@@ -62,8 +62,6 @@ export interface BackgroundImagePropsGenerated {
62
62
  attributes: {
63
63
  style?: BackgroundImageStyleGenerated;
64
64
  scrollable?: boolean;
65
- title?: string;
66
- description?: string;
67
65
  src?: string;
68
66
  resizeMode?: ResizeModeOptionType;
69
67
  };
@@ -2,13 +2,18 @@
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
4
  "type": "BackgroundImage",
5
+ "title": "title",
6
+ "description": "description",
5
7
  "children": "never",
6
8
  "extends": "View",
7
9
  "attributes": {
8
- "title": "title",
9
- "description": "description",
10
10
  "src": "string",
11
- "resizeMode": ["cover", "contain", "stretch", "center"]
11
+ "resizeMode": [
12
+ "cover",
13
+ "contain",
14
+ "stretch",
15
+ "center"
16
+ ]
12
17
  },
13
18
  "defaults": {
14
19
  "resizeMode": "cover",
@@ -24,7 +29,10 @@
24
29
  }
25
30
  },
26
31
  "meta": {
27
- "desiredParent": ["all", "background"],
32
+ "desiredParent": [
33
+ "all",
34
+ "background"
35
+ ],
28
36
  "label": "Background Image",
29
37
  "description": "Background image.",
30
38
  "styles": {
@@ -76,8 +76,6 @@ export interface ButtonPropsGenerated {
76
76
  attributes: {
77
77
  style?: ButtonStyleGenerated;
78
78
  scrollable?: boolean;
79
- title?: string;
80
- description?: string;
81
79
  };
82
80
  }
83
81
 
@@ -2,11 +2,11 @@
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
4
  "type": "Button",
5
+ "title": "title",
6
+ "description": "description",
5
7
  "children": "string",
6
8
  "extends": "View",
7
9
  "attributes": {
8
- "title": "title",
9
- "description": "description",
10
10
  "style": {
11
11
  "color": "color",
12
12
  "fontSize": "size",
@@ -27,7 +27,9 @@
27
27
  }
28
28
  },
29
29
  "meta": {
30
- "desiredParent": ["all"],
30
+ "desiredParent": [
31
+ "all"
32
+ ],
31
33
  "label": "Button",
32
34
  "description": "Simple action button.",
33
35
  "styles": {
@@ -62,8 +62,6 @@ export interface CarouselPropsGenerated {
62
62
  attributes: {
63
63
  style?: CarouselStyleGenerated;
64
64
  scrollable?: boolean;
65
- title?: string;
66
- description?: string;
67
65
  loop?: boolean;
68
66
  dragFree?: boolean;
69
67
  align?: AlignOptionType;
@@ -1,19 +1,25 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
- "extends": "View",
5
4
  "type": "Carousel",
5
+ "title": "title",
6
+ "description": "description",
7
+ "extends": "View",
6
8
  "children": "node",
7
9
  "attributes": {
8
- "title": "title",
9
- "description": "description",
10
10
  "loop": "boolean",
11
11
  "dragFree": "boolean",
12
- "align": ["start", "center", "end"]
12
+ "align": [
13
+ "start",
14
+ "center",
15
+ "end"
16
+ ]
13
17
  }
14
18
  },
15
19
  "meta": {
16
- "desiredParent": ["=CarouselProvider"],
20
+ "desiredParent": [
21
+ "=CarouselProvider"
22
+ ],
17
23
  "label": "Carousel",
18
24
  "description": "Container for carousel items.",
19
25
  "styles": {}
@@ -65,8 +65,6 @@ export interface CarouselButtonsPropsGenerated {
65
65
  attributes: {
66
66
  style?: CarouselButtonsStyleGenerated;
67
67
  scrollable?: boolean;
68
- title?: string;
69
- description?: string;
70
68
  buttonType?: ButtonTypeOptionType;
71
69
  skipNumber?: number;
72
70
  };
@@ -2,17 +2,24 @@
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
4
  "type": "CarouselButtons",
5
+ "title": "title",
6
+ "description": "description",
5
7
  "children": "never",
6
8
  "extends": "View",
7
9
  "attributes": {
8
- "title": "title",
9
- "description": "description",
10
- "buttonType": ["previous_button", "next_button", "skip_button"],
10
+ "buttonType": [
11
+ "previous_button",
12
+ "next_button",
13
+ "skip_button"
14
+ ],
11
15
  "skipNumber": "number"
12
16
  }
13
17
  },
14
18
  "meta": {
15
- "desiredParent": [">OnboardProvider", ">CarouselProvider"],
19
+ "desiredParent": [
20
+ ">OnboardProvider",
21
+ ">CarouselProvider"
22
+ ],
16
23
  "label": "Carousel Buttons",
17
24
  "description": "Renders built-in carousel buttons.",
18
25
  "styles": {},
@@ -68,8 +68,6 @@ export interface CarouselDotsPropsGenerated {
68
68
  attributes: {
69
69
  style?: CarouselDotsStyleGenerated;
70
70
  scrollable?: boolean;
71
- title?: string;
72
- description?: string;
73
71
  dotType?: DotTypeOptionType;
74
72
  };
75
73
  }
@@ -2,11 +2,11 @@
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
4
  "type": "CarouselDots",
5
+ "title": "title",
6
+ "description": "description",
5
7
  "children": "never",
6
8
  "extends": "View",
7
9
  "attributes": {
8
- "title": "title",
9
- "description": "description",
10
10
  "dotType": [
11
11
  "expanding_dot",
12
12
  "normal_dot",
@@ -18,7 +18,9 @@
18
18
  }
19
19
  },
20
20
  "meta": {
21
- "desiredParent": [">CarouselProvider"],
21
+ "desiredParent": [
22
+ ">CarouselProvider"
23
+ ],
22
24
  "label": "Carousel Dots",
23
25
  "description": "Renders page indicator dots.",
24
26
  "styles": {
@@ -61,8 +61,6 @@ export interface CarouselItemPropsGenerated {
61
61
  attributes: {
62
62
  style?: CarouselItemStyleGenerated;
63
63
  scrollable?: boolean;
64
- title?: string;
65
- description?: string;
66
64
  };
67
65
  }
68
66
 
@@ -2,15 +2,15 @@
2
2
  "schemaVersion": 2,
3
3
  "pattern": {
4
4
  "type": "CarouselItem",
5
+ "title": "title",
6
+ "description": "description",
5
7
  "children": "node",
6
- "extends": "View",
7
- "attributes": {
8
- "title": "title",
9
- "description": "description"
10
- }
8
+ "extends": "View"
11
9
  },
12
10
  "meta": {
13
- "desiredParent": ["=Carousel"],
11
+ "desiredParent": [
12
+ "=Carousel"
13
+ ],
14
14
  "label": "Carousel Item",
15
15
  "description": "Single slide inside a carousel.",
16
16
  "styles": {}
@@ -61,8 +61,6 @@ export interface CarouselProviderPropsGenerated {
61
61
  attributes: {
62
62
  style?: CarouselProviderStyleGenerated;
63
63
  scrollable?: boolean;
64
- title?: string;
65
- description?: string;
66
64
  };
67
65
  }
68
66
 
@@ -3,12 +3,10 @@
3
3
  "allowUnknownAttributes": false,
4
4
  "pattern": {
5
5
  "type": "CarouselProvider",
6
+ "title": "title",
7
+ "description": "description",
6
8
  "children": "node",
7
9
  "extends": "View",
8
- "attributes": {
9
- "title": "title",
10
- "description": "description"
11
- },
12
10
  "defaults": {
13
11
  "style": {
14
12
  "width": "100%",
@@ -17,7 +15,10 @@
17
15
  }
18
16
  },
19
17
  "meta": {
20
- "desiredParent": ["root", ">View"],
18
+ "desiredParent": [
19
+ "root",
20
+ ">View"
21
+ ],
21
22
  "label": "Carousel Provider",
22
23
  "description": "Provides carousel context to its children.",
23
24
  "attributes": {}