@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.
- package/dist/android.svg +43 -0
- package/dist/apple.svg +16 -0
- package/dist/attributes-editor/Field.d.ts +2 -1
- package/dist/attributes-editor/SizeField.d.ts +9 -0
- package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +1 -0
- package/dist/build-components/Button/ButtonProps.generated.d.ts +1 -0
- package/dist/build-components/Carousel/CarouselProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +1 -0
- package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +1 -0
- package/dist/build-components/Image/ImageProps.generated.d.ts +1 -0
- package/dist/build-components/Onboard/OnboardProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +1 -1
- package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +2 -3
- package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +2 -1
- package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +1 -0
- package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +1 -0
- package/dist/build-components/Text/TextProps.generated.d.ts +1 -0
- package/dist/build-components/View/ViewProps.generated.d.ts +1 -0
- package/dist/build-components/patterns.generated.d.ts +194 -57
- package/dist/components/JsonTextEditor.d.ts +9 -0
- package/dist/index.cjs.js +5 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +5 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/pages/tabs/SideTool.d.ts +2 -1
- package/dist/store.d.ts +2 -0
- package/dist/styles.css +1 -1
- package/dist/utils/extractImageStyle.d.ts +2 -1
- package/dist/utils/extractViewStyle.d.ts +1 -2
- package/dist/utils/selection.d.ts +7 -0
- package/dist/utils/useMergedStyle.d.ts +2 -0
- package/package.json +2 -5
- package/src/.DS_Store +0 -0
- package/src/AttributesEditor.tsx +7 -2
- package/src/RenderPage.tsx +10 -6
- package/src/attributes-editor/Field.tsx +48 -160
- package/src/attributes-editor/SizeField.tsx +184 -0
- package/src/attributes-editor/SpecialCategorySection.tsx +10 -3
- package/src/build-components/BackgroundImage/BackgroundImage.tsx +7 -17
- package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +1 -0
- package/src/build-components/Button/Button.tsx +7 -9
- package/src/build-components/Button/ButtonProps.generated.ts +1 -0
- package/src/build-components/Carousel/Carousel.tsx +7 -9
- package/src/build-components/Carousel/CarouselProps.generated.ts +1 -0
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +1 -0
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +1 -0
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +1 -0
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +1 -0
- package/src/build-components/Image/Image.tsx +11 -18
- package/src/build-components/Image/ImageProps.generated.ts +1 -0
- package/src/build-components/Image/pattern.json +1 -9
- package/src/build-components/Onboard/OnboardProps.generated.ts +1 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +0 -3
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +1 -1
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +1 -0
- package/src/build-components/OnboardDot/OnboardDot.tsx +59 -39
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +2 -3
- package/src/build-components/OnboardDot/pattern.json +2 -18
- package/src/build-components/OnboardFooter/OnboardFooter.tsx +28 -15
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +1 -0
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +2 -1
- package/src/build-components/OnboardItem/OnboardItem.tsx +1 -11
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +1 -0
- package/src/build-components/OnboardProvider/OnboardProvider.tsx +1 -8
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +1 -0
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +1 -0
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +1 -0
- package/src/build-components/Text/Text.tsx +9 -15
- package/src/build-components/Text/TextProps.generated.ts +1 -0
- package/src/build-components/View/View.tsx +7 -9
- package/src/build-components/View/ViewProps.generated.ts +1 -0
- package/src/build-components/View/pattern.json +9 -1
- package/src/build-components/patterns.generated.ts +194 -57
- package/src/components/Builder.tsx +61 -17
- package/src/components/DeviceNavigationBar.tsx +0 -1
- package/src/components/EditorHeader.tsx +11 -1
- package/src/components/JsonTextEditor.tsx +185 -0
- package/src/mockOS/components/MockOSRouter.tsx +6 -0
- package/src/mockOS/context/MockOSContext.tsx +0 -5
- package/src/mockOS/managers/mockPermissionManager.ts +0 -4
- package/src/mockOS/managers/navigationManager.ts +1 -6
- package/src/modals/ColorModal.tsx +103 -25
- package/src/modals/LocalicationModal.tsx +4 -5
- package/src/modals/Modal.tsx +8 -1
- package/src/pages/ProjectPage.tsx +7 -1
- package/src/pages/tabs/SideTool.tsx +10 -9
- package/src/store.ts +5 -0
- package/src/styles/base/_global.scss +5 -0
- package/src/styles/components/_editor-shell.scss +4 -2
- package/src/styles/modals/_color-modal.scss +30 -1
- package/src/styles/utilities/_carousel.scss +9 -8
- package/src/utils/extractImageStyle.ts +3 -6
- package/src/utils/extractTextStyle.ts +2 -81
- package/src/utils/extractViewStyle.ts +20 -15
- package/src/utils/selection.ts +24 -0
- package/src/utils/useMergedStyle.ts +16 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
type SizeUnit = '' | 'vs' | 's' | 'f' | '%';
|
|
4
|
+
type SizeSelectUnit = SizeUnit | 'auto';
|
|
5
|
+
|
|
6
|
+
export type PreferredScale = 'vs' | 's' | 'f' | '%';
|
|
7
|
+
|
|
8
|
+
export function toPreferredScale(value: unknown): PreferredScale | undefined {
|
|
9
|
+
if (value === 'vs' || value === 's' || value === 'f' || value === '%') {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value !== 'string') return undefined;
|
|
13
|
+
const normalized = value.trim().toLowerCase();
|
|
14
|
+
return normalized === 'vs' ||
|
|
15
|
+
normalized === 's' ||
|
|
16
|
+
normalized === 'f' ||
|
|
17
|
+
normalized === '%'
|
|
18
|
+
? (normalized as PreferredScale)
|
|
19
|
+
: undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SizeFieldProps = {
|
|
23
|
+
value: unknown;
|
|
24
|
+
onChange: (val: unknown) => void;
|
|
25
|
+
preferredScale?: PreferredScale;
|
|
26
|
+
fieldName: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function parseSizeValue(value: unknown): { amount: string; unit: SizeUnit } {
|
|
30
|
+
const empty = { amount: '', unit: '' as SizeUnit };
|
|
31
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
32
|
+
return { amount: String(value), unit: '' };
|
|
33
|
+
}
|
|
34
|
+
if (typeof value !== 'string') return empty;
|
|
35
|
+
const trimmed = value.trim();
|
|
36
|
+
if (!trimmed) return empty;
|
|
37
|
+
if (trimmed.endsWith('%')) {
|
|
38
|
+
return { amount: trimmed.slice(0, -1), unit: '%' };
|
|
39
|
+
}
|
|
40
|
+
const lower = trimmed.toLowerCase();
|
|
41
|
+
if (lower.endsWith('@vs'))
|
|
42
|
+
return { amount: trimmed.slice(0, -3), unit: 'vs' };
|
|
43
|
+
if (lower.endsWith('vs')) return { amount: trimmed.slice(0, -2), unit: 'vs' };
|
|
44
|
+
if (lower.endsWith('@fs')) return { amount: trimmed.slice(0, -3), unit: 'f' };
|
|
45
|
+
if (lower.endsWith('@f')) return { amount: trimmed.slice(0, -2), unit: 'f' };
|
|
46
|
+
if (lower.endsWith('fs')) return { amount: trimmed.slice(0, -2), unit: 'f' };
|
|
47
|
+
if (lower.endsWith('f')) return { amount: trimmed.slice(0, -1), unit: 'f' };
|
|
48
|
+
if (lower.endsWith('@s')) return { amount: trimmed.slice(0, -2), unit: 's' };
|
|
49
|
+
if (lower.endsWith('s')) return { amount: trimmed.slice(0, -1), unit: 's' };
|
|
50
|
+
if (lower.endsWith('px')) return { amount: trimmed.slice(0, -2), unit: '' };
|
|
51
|
+
return { amount: trimmed, unit: '' };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function composeSizeValue(amount: string, unit: SizeUnit): string | number {
|
|
55
|
+
const trimmed = amount.trim();
|
|
56
|
+
if (unit === '%') {
|
|
57
|
+
return `${trimmed}%`;
|
|
58
|
+
}
|
|
59
|
+
if (unit === '') {
|
|
60
|
+
const numeric = Number(trimmed);
|
|
61
|
+
return Number.isFinite(numeric) ? numeric : trimmed;
|
|
62
|
+
}
|
|
63
|
+
if (unit === 'f') {
|
|
64
|
+
return `${trimmed}@fs`;
|
|
65
|
+
}
|
|
66
|
+
return `${trimmed}@${unit}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizePreferredScale(
|
|
70
|
+
preferredScale: PreferredScale | undefined,
|
|
71
|
+
fieldName: string,
|
|
72
|
+
): SizeUnit {
|
|
73
|
+
const fallbackName = fieldName.trim().toLowerCase();
|
|
74
|
+
const fallback: SizeUnit =
|
|
75
|
+
fallbackName.includes('height') ||
|
|
76
|
+
fallbackName.includes('top') ||
|
|
77
|
+
fallbackName.includes('vertical')
|
|
78
|
+
? 'vs'
|
|
79
|
+
: 's';
|
|
80
|
+
return preferredScale ?? fallback;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function SizeField({
|
|
84
|
+
value,
|
|
85
|
+
onChange,
|
|
86
|
+
preferredScale,
|
|
87
|
+
fieldName,
|
|
88
|
+
}: SizeFieldProps) {
|
|
89
|
+
const parsed = useMemo(() => parseSizeValue(value), [value]);
|
|
90
|
+
const normalizedPreferred = useMemo(
|
|
91
|
+
() => normalizePreferredScale(preferredScale, fieldName),
|
|
92
|
+
[preferredScale, fieldName],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const [amount, setAmount] = useState(parsed.amount);
|
|
96
|
+
const [unit, setUnit] = useState<SizeSelectUnit>(() => {
|
|
97
|
+
// Default to "auto" when the stored unit is already the preferred one (or empty)
|
|
98
|
+
// so that "auto" means "use preferredScale" without changing behavior.
|
|
99
|
+
return parsed.unit && parsed.unit !== normalizedPreferred
|
|
100
|
+
? parsed.unit
|
|
101
|
+
: 'auto';
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
setAmount(parsed.amount);
|
|
106
|
+
|
|
107
|
+
// Keep "auto" selected whenever value is preferred (or unscaled).
|
|
108
|
+
const nextUnit: SizeSelectUnit =
|
|
109
|
+
parsed.unit && parsed.unit !== normalizedPreferred ? parsed.unit : 'auto';
|
|
110
|
+
setUnit(nextUnit);
|
|
111
|
+
}, [parsed.amount, parsed.unit, normalizedPreferred]);
|
|
112
|
+
|
|
113
|
+
const resolveUnit = useCallback(
|
|
114
|
+
(nextUnit: SizeSelectUnit): SizeUnit =>
|
|
115
|
+
nextUnit === 'auto' ? normalizedPreferred : nextUnit,
|
|
116
|
+
[normalizedPreferred],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const emitValue = useCallback(
|
|
120
|
+
(nextAmount: string, nextUnit: SizeSelectUnit) => {
|
|
121
|
+
const trimmed = nextAmount.trim();
|
|
122
|
+
if (!trimmed) {
|
|
123
|
+
onChange(undefined);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// If "auto" is selected, persist the preferredScale.
|
|
127
|
+
onChange(composeSizeValue(trimmed, resolveUnit(nextUnit)));
|
|
128
|
+
},
|
|
129
|
+
[onChange, resolveUnit],
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
133
|
+
const nextAmount = e.target.value;
|
|
134
|
+
setAmount(nextAmount);
|
|
135
|
+
if (!nextAmount.trim()) {
|
|
136
|
+
onChange(undefined);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
emitValue(nextAmount, unit);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const handleUnitChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
143
|
+
const nextUnit = e.target.value as SizeSelectUnit;
|
|
144
|
+
setUnit(nextUnit);
|
|
145
|
+
if (!amount.trim()) return;
|
|
146
|
+
emitValue(amount, nextUnit);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const unitPriority: SizeUnit[] = ['vs', 's', 'f', '%'];
|
|
150
|
+
const orderedUnits = [
|
|
151
|
+
normalizedPreferred,
|
|
152
|
+
...unitPriority.filter((u) => u !== normalizedPreferred),
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
const unitOptions: Array<{ value: SizeSelectUnit; label: string }> = [
|
|
156
|
+
{ value: 'auto', label: 'auto' },
|
|
157
|
+
...orderedUnits.map((u) => ({
|
|
158
|
+
value: u,
|
|
159
|
+
label: u === normalizedPreferred ? `${u} (preferred)` : u,
|
|
160
|
+
})),
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className="attributes-editor__size-field">
|
|
165
|
+
<input
|
|
166
|
+
type="number"
|
|
167
|
+
className="input attributes-editor__size-field-input"
|
|
168
|
+
value={amount}
|
|
169
|
+
onChange={handleAmountChange}
|
|
170
|
+
/>
|
|
171
|
+
<select
|
|
172
|
+
className="input attributes-editor__size-field-select"
|
|
173
|
+
value={unit}
|
|
174
|
+
onChange={handleUnitChange}
|
|
175
|
+
>
|
|
176
|
+
{unitOptions.map((opt) => (
|
|
177
|
+
<option key={opt.value} value={opt.value}>
|
|
178
|
+
{opt.label}
|
|
179
|
+
</option>
|
|
180
|
+
))}
|
|
181
|
+
</select>
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
@@ -3,6 +3,7 @@ import { NodeDefaultAttribute } from '../types/Node';
|
|
|
3
3
|
import type { ProjectColors } from '../types/Project';
|
|
4
4
|
import { Field } from './Field';
|
|
5
5
|
import { FieldInfoTooltip } from './FieldInfoTooltip';
|
|
6
|
+
import { toPreferredScale } from './SizeField';
|
|
6
7
|
import {
|
|
7
8
|
AttributeMetaMap,
|
|
8
9
|
LayoutContext,
|
|
@@ -92,7 +93,9 @@ export function SpecialCategorySection({
|
|
|
92
93
|
{entries.map(({ name, type }) => {
|
|
93
94
|
const label = attributeMeta?.[name]?.label ?? name;
|
|
94
95
|
const description = attributeMeta?.[name]?.description;
|
|
95
|
-
const preferredScale =
|
|
96
|
+
const preferredScale = toPreferredScale(
|
|
97
|
+
attributeMeta?.[name]?.preferedScale,
|
|
98
|
+
);
|
|
96
99
|
const currentValue = (attributes as Record<string, unknown>)[name];
|
|
97
100
|
const isBoolean = isBooleanFieldType(type);
|
|
98
101
|
const fieldSlot = detectFieldSlot(name);
|
|
@@ -169,7 +172,9 @@ export function SpecialCategorySection({
|
|
|
169
172
|
{boxEntries.map(({ name, type }) => {
|
|
170
173
|
const label = attributeMeta?.[name]?.label ?? name;
|
|
171
174
|
const description = attributeMeta?.[name]?.description;
|
|
172
|
-
const preferredScale =
|
|
175
|
+
const preferredScale = toPreferredScale(
|
|
176
|
+
attributeMeta?.[name]?.preferedScale,
|
|
177
|
+
);
|
|
173
178
|
const currentValue = (attributes as Record<string, unknown>)[name];
|
|
174
179
|
const isBoolean = isBooleanFieldType(type);
|
|
175
180
|
const fieldSlot = detectFieldSlot(name);
|
|
@@ -212,7 +217,9 @@ export function SpecialCategorySection({
|
|
|
212
217
|
{baseEntries.map(({ name, type }) => {
|
|
213
218
|
const label = attributeMeta?.[name]?.label ?? name;
|
|
214
219
|
const description = attributeMeta?.[name]?.description;
|
|
215
|
-
const preferredScale =
|
|
220
|
+
const preferredScale = toPreferredScale(
|
|
221
|
+
attributeMeta?.[name]?.preferedScale,
|
|
222
|
+
);
|
|
216
223
|
const currentValue = (attributes as Record<string, unknown>)[name];
|
|
217
224
|
const isBoolean = isBooleanFieldType(type);
|
|
218
225
|
const wrapperClassNames = [
|
|
@@ -4,6 +4,8 @@ import useNode from '../useNode';
|
|
|
4
4
|
import { useRenderStore } from '../../store';
|
|
5
5
|
import { extractViewStyle } from '../../utils/extractViewStyle';
|
|
6
6
|
import { useLogRender } from '../../utils/useLogRender';
|
|
7
|
+
import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
8
|
+
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
7
9
|
|
|
8
10
|
function BackgroundImage({ node }: BackgroundImageComponentProps) {
|
|
9
11
|
useLogRender('BackgroundImage');
|
|
@@ -56,25 +58,13 @@ function BackgroundImage({ node }: BackgroundImageComponentProps) {
|
|
|
56
58
|
|
|
57
59
|
return style;
|
|
58
60
|
}, [node]);
|
|
59
|
-
const isSelected =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
(current as any).key === (node as any).key;
|
|
65
|
-
|
|
66
|
-
const mergedStyle = useMemo(
|
|
67
|
-
() => ({
|
|
68
|
-
...baseStyle,
|
|
69
|
-
...backgroundStyle,
|
|
70
|
-
}),
|
|
71
|
-
[baseStyle, backgroundStyle],
|
|
61
|
+
const isSelected = isNodeSelected({ previewMode, current, node });
|
|
62
|
+
const mergedStyle = useMergedStyle(baseStyle, backgroundStyle);
|
|
63
|
+
const style = useMergedStyle(
|
|
64
|
+
mergedStyle,
|
|
65
|
+
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
72
66
|
);
|
|
73
67
|
|
|
74
|
-
const style = isSelected
|
|
75
|
-
? { ...mergedStyle, outline: '2px solid #2684FF' }
|
|
76
|
-
: mergedStyle;
|
|
77
|
-
|
|
78
68
|
return (
|
|
79
69
|
<div
|
|
80
70
|
attribute-name={attributeName}
|
|
@@ -4,6 +4,8 @@ import useNode from '../useNode';
|
|
|
4
4
|
import { useRenderStore } from '../../store';
|
|
5
5
|
import { useLogRender } from '../../utils/useLogRender';
|
|
6
6
|
import { extractViewStyle } from '../../utils/extractViewStyle';
|
|
7
|
+
import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
8
|
+
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
7
9
|
|
|
8
10
|
function Button({ node }: ButtonComponentProps) {
|
|
9
11
|
useLogRender('Button');
|
|
@@ -23,15 +25,11 @@ function Button({ node }: ButtonComponentProps) {
|
|
|
23
25
|
() => extractViewStyle(node, { appConfig, projectColors }),
|
|
24
26
|
[node, appConfig, projectColors],
|
|
25
27
|
);
|
|
26
|
-
const isSelected =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
(current as any).key === (node as any).key;
|
|
32
|
-
const style = isSelected
|
|
33
|
-
? { ...baseStyle, outline: '2px solid #2684FF' }
|
|
34
|
-
: baseStyle;
|
|
28
|
+
const isSelected = isNodeSelected({ previewMode, current, node });
|
|
29
|
+
const style = useMergedStyle(
|
|
30
|
+
baseStyle,
|
|
31
|
+
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
32
|
+
);
|
|
35
33
|
|
|
36
34
|
return (
|
|
37
35
|
<div
|
|
@@ -6,6 +6,8 @@ import useNode from '../useNode';
|
|
|
6
6
|
import { useRenderStore } from '../../store';
|
|
7
7
|
import { useLogRender } from '../../utils/useLogRender';
|
|
8
8
|
import { extractViewStyle } from '../../utils/extractViewStyle';
|
|
9
|
+
import { isNodeSelected, SELECTED_OUTLINE_STYLE } from '../../utils/selection';
|
|
10
|
+
import { useMergedStyle } from '../../utils/useMergedStyle';
|
|
9
11
|
|
|
10
12
|
function Carousel({ node }: CarouselComponentProps) {
|
|
11
13
|
useLogRender('Carousel');
|
|
@@ -25,15 +27,11 @@ function Carousel({ node }: CarouselComponentProps) {
|
|
|
25
27
|
() => extractViewStyle(node, { appConfig, projectColors }),
|
|
26
28
|
[node, appConfig, projectColors],
|
|
27
29
|
);
|
|
28
|
-
const isSelected =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
(current as any).key === (node as any).key;
|
|
34
|
-
const style = isSelected
|
|
35
|
-
? { ...baseStyle, outline: '2px solid #2684FF' }
|
|
36
|
-
: baseStyle;
|
|
30
|
+
const isSelected = isNodeSelected({ previewMode, current, node });
|
|
31
|
+
const style = useMergedStyle(
|
|
32
|
+
baseStyle,
|
|
33
|
+
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
34
|
+
);
|
|
37
35
|
// Ensure children are carouselItems
|
|
38
36
|
const renderChildren = () => {
|
|
39
37
|
if (Array.isArray(node.children)) {
|
|
@@ -3,8 +3,9 @@ import type { ImageComponentProps } from './ImageProps.generated';
|
|
|
3
3
|
import useNode from '../useNode';
|
|
4
4
|
import { useRenderStore } from '../../store';
|
|
5
5
|
import { extractImageStyle } from '../../utils/extractImageStyle';
|
|
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 Image({ node }: ImageComponentProps) {
|
|
10
11
|
useLogRender('Image');
|
|
@@ -20,30 +21,22 @@ function Image({ node }: ImageComponentProps) {
|
|
|
20
21
|
projectColors: s.projectColors,
|
|
21
22
|
}),
|
|
22
23
|
);
|
|
23
|
-
const
|
|
24
|
-
() =>
|
|
24
|
+
const imageStyle = useMemo(
|
|
25
|
+
() => extractImageStyle(node, { appConfig, projectColors }),
|
|
25
26
|
[node, appConfig, projectColors],
|
|
26
27
|
);
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
(current as any).key === (node as any).key;
|
|
34
|
-
const style = {
|
|
35
|
-
...viewStyle,
|
|
36
|
-
...imageStyle,
|
|
37
|
-
...(isSelected ? { outline: '2px solid #2684FF' } : {}),
|
|
38
|
-
};
|
|
28
|
+
const isSelected = isNodeSelected({ previewMode, current, node });
|
|
29
|
+
const style = useMergedStyle(
|
|
30
|
+
imageStyle,
|
|
31
|
+
isSelected ? SELECTED_OUTLINE_STYLE : undefined,
|
|
32
|
+
);
|
|
33
|
+
|
|
39
34
|
return (
|
|
40
35
|
<img
|
|
41
|
-
key={node.key}
|
|
36
|
+
key={node.key + (node.attributes?.src ?? '-')}
|
|
42
37
|
attribute-name={attributeName}
|
|
43
38
|
attribute-key={attributeKey}
|
|
44
39
|
src={node.attributes?.src}
|
|
45
|
-
width={node.attributes?.width}
|
|
46
|
-
height={node.attributes?.height}
|
|
47
40
|
style={style}
|
|
48
41
|
alt=""
|
|
49
42
|
/>
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"src": "string",
|
|
10
10
|
"width": "size",
|
|
11
11
|
"height": "size",
|
|
12
|
-
"resizeMode": ["cover", "contain", "stretch", "center"]
|
|
13
|
-
"borderRadius": "size"
|
|
12
|
+
"resizeMode": ["cover", "contain", "stretch", "center"]
|
|
14
13
|
}
|
|
15
14
|
},
|
|
16
15
|
"meta": {
|
|
@@ -45,13 +44,6 @@
|
|
|
45
44
|
"category": "style",
|
|
46
45
|
"specialCategory": null,
|
|
47
46
|
"sort": 4
|
|
48
|
-
},
|
|
49
|
-
"borderRadius": {
|
|
50
|
-
"label": "Border Radius",
|
|
51
|
-
"description": "Corner rounding.",
|
|
52
|
-
"category": "style",
|
|
53
|
-
"specialCategory": null,
|
|
54
|
-
"sort": 5
|
|
55
47
|
}
|
|
56
48
|
}
|
|
57
49
|
}
|
|
@@ -57,7 +57,6 @@ function OnboardButton({ node }: OnboardButtonComponentProps) {
|
|
|
57
57
|
mockPermissionManager.requestPermission(permission);
|
|
58
58
|
handledEventsRef.current.push(e);
|
|
59
59
|
//TODO: cause user to click second time
|
|
60
|
-
return;
|
|
61
60
|
} else if (e.type === 'Navigate') {
|
|
62
61
|
const eventTargetIndex = e.targetIndex;
|
|
63
62
|
if (typeof eventTargetIndex === 'number') {
|
|
@@ -65,7 +64,6 @@ function OnboardButton({ node }: OnboardButtonComponentProps) {
|
|
|
65
64
|
navigateHandled = true;
|
|
66
65
|
handledEventsRef.current.push(e);
|
|
67
66
|
//TODO: cause user to click second time
|
|
68
|
-
return;
|
|
69
67
|
} else if (e.navigate_to) {
|
|
70
68
|
const eventTarget = e.navigate_to;
|
|
71
69
|
if (typeof eventTarget === 'string') {
|
|
@@ -78,7 +76,6 @@ function OnboardButton({ node }: OnboardButtonComponentProps) {
|
|
|
78
76
|
alert('Mock OS context not available for navigation.');
|
|
79
77
|
}
|
|
80
78
|
}
|
|
81
|
-
return;
|
|
82
79
|
}
|
|
83
80
|
}
|
|
84
81
|
}
|
|
@@ -58,6 +58,7 @@ export interface OnboardButtonPropsGenerated {
|
|
|
58
58
|
borderRadius?: string;
|
|
59
59
|
width?: string;
|
|
60
60
|
height?: string;
|
|
61
|
+
flex?: number;
|
|
61
62
|
position?: PositionOptionType;
|
|
62
63
|
top?: string;
|
|
63
64
|
bottom?: string;
|
|
@@ -69,7 +70,6 @@ export interface OnboardButtonPropsGenerated {
|
|
|
69
70
|
animation?: AnimationOptionType;
|
|
70
71
|
animation_color?: string;
|
|
71
72
|
button_background_color?: string;
|
|
72
|
-
flex?: number;
|
|
73
73
|
events?: EventObjectGenerated[];
|
|
74
74
|
};
|
|
75
75
|
}
|