@proulr/sdui-components 0.1.15 → 0.1.17
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/package.json +1 -1
- package/src/bdc/components/discover.tsx +1 -0
- package/src/bdc/components/inbox.tsx +68 -0
- package/src/bdc/components/native-blocks.tsx +1 -0
- package/src/bdc/index.ts +10 -0
- package/src/renderer/blocks/SduiDiscoverBlocks.tsx +24 -6
- package/src/renderer/blocks/SduiInboxBlocks.tsx +292 -0
- package/src/renderer/blocks/SduiNativeDomainBlocks.tsx +5 -0
- package/src/renderer/sdui-component-registry.tsx +18 -0
- package/src/renderer/sdui-hybrid-renderer-context.tsx +30 -0
package/package.json
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { BdcComponent, BdcElement } from '../jsx-runtime';
|
|
2
|
+
|
|
3
|
+
type LayoutProps = {
|
|
4
|
+
id?: string;
|
|
5
|
+
gap?: number | string;
|
|
6
|
+
padding?: number | string;
|
|
7
|
+
style?: Record<string, unknown>;
|
|
8
|
+
children?: BdcElement[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function layoutBlock(type: string, props: LayoutProps): BdcElement {
|
|
12
|
+
return { type, props: { ...props }, children: props.children ?? [] };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type SegmentedTabsProps = LayoutProps & {
|
|
16
|
+
segmentsRef?: string;
|
|
17
|
+
activeRef?: string;
|
|
18
|
+
actionPrefix?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const SegmentedTabs: BdcComponent = (props) =>
|
|
22
|
+
layoutBlock('segmented_tabs', props as SegmentedTabsProps);
|
|
23
|
+
|
|
24
|
+
type EmptyStateProps = LayoutProps & {
|
|
25
|
+
title?: string;
|
|
26
|
+
titleRef?: string;
|
|
27
|
+
hint?: string;
|
|
28
|
+
hintRef?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const EmptyState: BdcComponent = (props) => layoutBlock('empty_state', props as EmptyStateProps);
|
|
32
|
+
|
|
33
|
+
type InboxPersonRowProps = LayoutProps & {
|
|
34
|
+
variant: 'visit' | 'flash' | 'chat';
|
|
35
|
+
rowRef: string;
|
|
36
|
+
actionId?: string;
|
|
37
|
+
actionParams?: Record<string, string>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const InboxPersonRow: BdcComponent = (props) =>
|
|
41
|
+
layoutBlock('inbox_person_row', props as InboxPersonRowProps);
|
|
42
|
+
|
|
43
|
+
type InboxSearchFieldProps = LayoutProps & {
|
|
44
|
+
placeholder?: string;
|
|
45
|
+
layout?: 'wide_only' | 'always';
|
|
46
|
+
segment?: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const InboxSearchField: BdcComponent = (props) =>
|
|
50
|
+
layoutBlock('inbox_search_field', props as InboxSearchFieldProps);
|
|
51
|
+
|
|
52
|
+
type InboxCapabilitiesProps = {
|
|
53
|
+
id?: string;
|
|
54
|
+
dataRef?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function capabilityBlock(type: string, props: InboxCapabilitiesProps): BdcElement {
|
|
58
|
+
return { type, props: { ...props }, children: [] };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const ChatInboxCapabilities: BdcComponent = (props) =>
|
|
62
|
+
capabilityBlock('chat_inbox_capabilities', props as InboxCapabilitiesProps);
|
|
63
|
+
|
|
64
|
+
export const FlashInboxCapabilities: BdcComponent = (props) =>
|
|
65
|
+
capabilityBlock('flash_inbox_capabilities', props as InboxCapabilitiesProps);
|
|
66
|
+
|
|
67
|
+
export const ProfileVisitsCapabilities: BdcComponent = (props) =>
|
|
68
|
+
capabilityBlock('profile_visits_capabilities', props as InboxCapabilitiesProps);
|
|
@@ -18,6 +18,7 @@ function nativeBlock(type: string, props: NativeBlockProps): BdcElement {
|
|
|
18
18
|
|
|
19
19
|
export const FlashInboxList: BdcComponent = (props) => nativeBlock('flash_inbox_list', props);
|
|
20
20
|
export const ChatInboxList: BdcComponent = (props) => nativeBlock('chat_inbox_list', props);
|
|
21
|
+
export const ProfileVisitsList: BdcComponent = (props) => nativeBlock('profile_visits_list', props);
|
|
21
22
|
export const ChatThread: BdcComponent = (props) => nativeBlock('chat_thread', props);
|
|
22
23
|
export const SocialPostFeed: BdcComponent = (props) => nativeBlock('social_post_feed', props);
|
|
23
24
|
export const ThoughtFeed: BdcComponent = (props) => nativeBlock('thought_feed', props);
|
package/src/bdc/index.ts
CHANGED
|
@@ -16,6 +16,15 @@ export {
|
|
|
16
16
|
screenProps,
|
|
17
17
|
} from './components/ui';
|
|
18
18
|
export { Chip, ChipRow, DiscoverGrid, DiscoverMap, DiscoverProfileCard } from './components/discover';
|
|
19
|
+
export {
|
|
20
|
+
ChatInboxCapabilities,
|
|
21
|
+
EmptyState,
|
|
22
|
+
FlashInboxCapabilities,
|
|
23
|
+
InboxPersonRow,
|
|
24
|
+
InboxSearchField,
|
|
25
|
+
ProfileVisitsCapabilities,
|
|
26
|
+
SegmentedTabs,
|
|
27
|
+
} from './components/inbox';
|
|
19
28
|
export { TextField } from './components/forms';
|
|
20
29
|
export { ProfileCompletionBanner, StoryRail } from './components/social';
|
|
21
30
|
export {
|
|
@@ -24,6 +33,7 @@ export {
|
|
|
24
33
|
ChatInboxList,
|
|
25
34
|
ChatThread,
|
|
26
35
|
FlashInboxList,
|
|
36
|
+
ProfileVisitsList,
|
|
27
37
|
NewPostComposer,
|
|
28
38
|
NewStoryComposer,
|
|
29
39
|
PostComments,
|
|
@@ -263,6 +263,7 @@ export function SduiDiscoverGridBlock({ block, data, onAction }: SduiBlockRender
|
|
|
263
263
|
|
|
264
264
|
export function SduiChipBlock({ block, onAction }: SduiBlockRenderProps) {
|
|
265
265
|
const label = readStringProp(block, 'label') ?? '';
|
|
266
|
+
const glyph = readStringProp(block, 'glyph');
|
|
266
267
|
const actionId = readStringProp(block, 'action_id');
|
|
267
268
|
const actionParams = readStringRecordProp(block, 'action_params');
|
|
268
269
|
const active = readBooleanProp(block, 'active');
|
|
@@ -275,6 +276,11 @@ export function SduiChipBlock({ block, onAction }: SduiBlockRenderProps) {
|
|
|
275
276
|
onPress={() => actionId && onAction(actionId, actionParams)}
|
|
276
277
|
disabled={!actionId}
|
|
277
278
|
>
|
|
279
|
+
{glyph ? (
|
|
280
|
+
<Text style={[styles.chipLabel, active && styles.chipLabelActive]} accessibilityElementsHidden>
|
|
281
|
+
{glyph}{' '}
|
|
282
|
+
</Text>
|
|
283
|
+
) : null}
|
|
278
284
|
<Text style={[styles.chipLabel, active && styles.chipLabelActive]}>{label}</Text>
|
|
279
285
|
</Pressable>
|
|
280
286
|
);
|
|
@@ -289,7 +295,9 @@ export function SduiChipRowBlock({ block, children }: SduiBlockRenderProps) {
|
|
|
289
295
|
<ScrollView
|
|
290
296
|
horizontal
|
|
291
297
|
showsHorizontalScrollIndicator={false}
|
|
298
|
+
style={styles.chipRowScroll}
|
|
292
299
|
contentContainerStyle={[styles.chipRow, isHeader && styles.chipRowOnHeader]}
|
|
300
|
+
keyboardShouldPersistTaps="handled"
|
|
293
301
|
>
|
|
294
302
|
{children}
|
|
295
303
|
</ScrollView>
|
|
@@ -433,17 +441,27 @@ const styles = StyleSheet.create({
|
|
|
433
441
|
fontWeight: '600',
|
|
434
442
|
fontFamily: fonts.semibold,
|
|
435
443
|
},
|
|
444
|
+
chipRowScroll: {
|
|
445
|
+
flexGrow: 0,
|
|
446
|
+
flexShrink: 0,
|
|
447
|
+
alignSelf: 'stretch',
|
|
448
|
+
},
|
|
436
449
|
chipRow: {
|
|
437
450
|
flexDirection: 'row',
|
|
438
|
-
|
|
451
|
+
alignItems: 'center',
|
|
452
|
+
gap: spacing.xs,
|
|
439
453
|
paddingHorizontal: spacing.sm,
|
|
454
|
+
paddingVertical: 0,
|
|
440
455
|
},
|
|
441
456
|
chipRowOnHeader: {
|
|
442
|
-
paddingHorizontal:
|
|
457
|
+
paddingHorizontal: spacing.sm,
|
|
443
458
|
},
|
|
444
459
|
chip: {
|
|
445
|
-
|
|
446
|
-
|
|
460
|
+
flexDirection: 'row',
|
|
461
|
+
alignItems: 'center',
|
|
462
|
+
alignSelf: 'center',
|
|
463
|
+
paddingHorizontal: spacing.sm + 2,
|
|
464
|
+
paddingVertical: spacing.xs,
|
|
447
465
|
borderRadius: m3Shape.cornerFull,
|
|
448
466
|
backgroundColor: m3Colors.surfaceContainerHigh,
|
|
449
467
|
borderWidth: 1,
|
|
@@ -459,8 +477,8 @@ const styles = StyleSheet.create({
|
|
|
459
477
|
},
|
|
460
478
|
chipLabel: {
|
|
461
479
|
color: m3Colors.onSurface,
|
|
462
|
-
fontSize:
|
|
463
|
-
fontFamily: fonts.
|
|
480
|
+
fontSize: 12,
|
|
481
|
+
fontFamily: fonts.semibold,
|
|
464
482
|
},
|
|
465
483
|
chipLabelActive: {
|
|
466
484
|
color: m3Colors.onPrimaryContainer,
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
import type { SduiBlock } from '@proulr/sdui-contract';
|
|
4
|
+
import { Card } from '../ui/Card';
|
|
5
|
+
import { fonts, m3Colors, m3Shape, spacing } from '../theme/proulr-theme';
|
|
6
|
+
import { resolveDataRef, resolveDataRefString } from '../lib/resolve-data-ref';
|
|
7
|
+
import { useSduiHybridRenderer } from '../sdui-hybrid-renderer-context';
|
|
8
|
+
import type { SduiBlockRenderProps } from './SduiPrimitiveBlocks';
|
|
9
|
+
|
|
10
|
+
function readStringProp(block: SduiBlock, key: string): string | undefined {
|
|
11
|
+
const value = block.props[key];
|
|
12
|
+
return typeof value === 'string' ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function readStringRecordProp(block: SduiBlock, key: string): Record<string, string> | undefined {
|
|
16
|
+
const value = block.props[key];
|
|
17
|
+
if (!value || typeof value !== 'object') return undefined;
|
|
18
|
+
const entries = Object.entries(value as Record<string, unknown>).filter(
|
|
19
|
+
(entry): entry is [string, string] => typeof entry[1] === 'string',
|
|
20
|
+
);
|
|
21
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type HubSegmentWire = { id: string; label: string; glyph?: string };
|
|
25
|
+
|
|
26
|
+
function readHubSegments(data: Record<string, unknown>, ref?: string): HubSegmentWire[] {
|
|
27
|
+
const hub = resolveDataRef(data, ref?.split('.')[0] ?? 'hub');
|
|
28
|
+
if (!hub || typeof hub !== 'object') return [];
|
|
29
|
+
const segments = (hub as Record<string, unknown>).segments;
|
|
30
|
+
if (!Array.isArray(segments)) return [];
|
|
31
|
+
return segments.filter(
|
|
32
|
+
(item): item is HubSegmentWire =>
|
|
33
|
+
Boolean(item && typeof item === 'object' && typeof (item as HubSegmentWire).id === 'string'),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function readActiveSegment(data: Record<string, unknown>, ref?: string): string {
|
|
38
|
+
const value = resolveDataRefString(data, ref ?? 'hub.active_segment');
|
|
39
|
+
return value || 'chats';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function SduiSegmentedTabsBlock({ block, data, onAction }: SduiBlockRenderProps) {
|
|
43
|
+
const hybrid = useSduiHybridRenderer();
|
|
44
|
+
if (hybrid.renderSegmentedTabs) {
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
{hybrid.renderSegmentedTabs({
|
|
48
|
+
block,
|
|
49
|
+
data,
|
|
50
|
+
onAction,
|
|
51
|
+
segmentsRef: readStringProp(block, 'segments_ref'),
|
|
52
|
+
activeRef: readStringProp(block, 'active_ref'),
|
|
53
|
+
actionPrefix: readStringProp(block, 'action_prefix') ?? 'select_segment_',
|
|
54
|
+
})}
|
|
55
|
+
</>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const segmentsRef = readStringProp(block, 'segments_ref') ?? 'hub.segments';
|
|
60
|
+
const activeRef = readStringProp(block, 'active_ref') ?? 'hub.active_segment';
|
|
61
|
+
const actionPrefix = readStringProp(block, 'action_prefix') ?? 'select_segment_';
|
|
62
|
+
const segments = readHubSegments(data, segmentsRef);
|
|
63
|
+
const active = readActiveSegment(data, activeRef);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<View style={styles.segmentTrack} accessibilityRole="tablist">
|
|
67
|
+
{segments.map((segment) => {
|
|
68
|
+
const selected = segment.id === active;
|
|
69
|
+
return (
|
|
70
|
+
<Pressable
|
|
71
|
+
key={segment.id}
|
|
72
|
+
style={[styles.segment, selected && styles.segmentActive]}
|
|
73
|
+
onPress={() => onAction(`${actionPrefix}${segment.id}`)}
|
|
74
|
+
accessibilityRole="tab"
|
|
75
|
+
accessibilityState={{ selected }}
|
|
76
|
+
>
|
|
77
|
+
{segment.glyph ? <Text style={styles.segmentGlyph}>{segment.glyph}</Text> : null}
|
|
78
|
+
<Text style={[styles.segmentLabel, selected && styles.segmentLabelActive]}>
|
|
79
|
+
{segment.label}
|
|
80
|
+
</Text>
|
|
81
|
+
</Pressable>
|
|
82
|
+
);
|
|
83
|
+
})}
|
|
84
|
+
</View>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function SduiEmptyStateBlock({ block, data }: SduiBlockRenderProps) {
|
|
89
|
+
const hybrid = useSduiHybridRenderer();
|
|
90
|
+
const title =
|
|
91
|
+
readStringProp(block, 'title') || resolveDataRefString(data, readStringProp(block, 'title_ref'));
|
|
92
|
+
const hint =
|
|
93
|
+
readStringProp(block, 'hint') || resolveDataRefString(data, readStringProp(block, 'hint_ref'));
|
|
94
|
+
|
|
95
|
+
if (hybrid.renderEmptyState) {
|
|
96
|
+
return <>{hybrid.renderEmptyState({ title, hint })}</>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Card style={styles.emptyCard}>
|
|
101
|
+
<Text style={styles.emptyTitle}>{title}</Text>
|
|
102
|
+
{hint ? <Text style={styles.emptyHint}>{hint}</Text> : null}
|
|
103
|
+
</Card>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function SduiInboxPersonRowBlock({ block, data, onAction }: SduiBlockRenderProps) {
|
|
108
|
+
const hybrid = useSduiHybridRenderer();
|
|
109
|
+
const variant = readStringProp(block, 'variant');
|
|
110
|
+
const rowRef = readStringProp(block, 'row_ref');
|
|
111
|
+
const actionId = readStringProp(block, 'action_id');
|
|
112
|
+
const actionParams = readStringRecordProp(block, 'action_params');
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
hybrid.renderInboxPersonRow &&
|
|
116
|
+
variant &&
|
|
117
|
+
rowRef &&
|
|
118
|
+
(variant === 'visit' || variant === 'flash' || variant === 'chat')
|
|
119
|
+
) {
|
|
120
|
+
return (
|
|
121
|
+
<>
|
|
122
|
+
{hybrid.renderInboxPersonRow({
|
|
123
|
+
block,
|
|
124
|
+
data,
|
|
125
|
+
onAction,
|
|
126
|
+
variant,
|
|
127
|
+
rowRef,
|
|
128
|
+
actionId,
|
|
129
|
+
actionParams,
|
|
130
|
+
})}
|
|
131
|
+
</>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const row = rowRef ? resolveDataRef(data, rowRef) : null;
|
|
136
|
+
if (!row || typeof row !== 'object') return null;
|
|
137
|
+
const record = row as Record<string, unknown>;
|
|
138
|
+
const title =
|
|
139
|
+
resolveDataRefString(data, `${rowRef}.viewer_name`) ||
|
|
140
|
+
resolveDataRefString(data, `${rowRef}.sender_name`) ||
|
|
141
|
+
resolveDataRefString(data, `${rowRef}.peer_display_name`) ||
|
|
142
|
+
'Alguém';
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<Pressable
|
|
146
|
+
onPress={() => actionId && onAction(actionId, actionParams)}
|
|
147
|
+
disabled={!actionId}
|
|
148
|
+
>
|
|
149
|
+
<Card style={styles.rowCard}>
|
|
150
|
+
<Text style={styles.rowTitle}>{title}</Text>
|
|
151
|
+
{typeof record.viewed_at === 'string' ? (
|
|
152
|
+
<Text style={styles.rowMeta}>Visualizou seu perfil</Text>
|
|
153
|
+
) : null}
|
|
154
|
+
</Card>
|
|
155
|
+
</Pressable>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function SduiInboxSearchFieldBlock({ block, data, onAction }: SduiBlockRenderProps) {
|
|
160
|
+
const hybrid = useSduiHybridRenderer();
|
|
161
|
+
const placeholder = readStringProp(block, 'placeholder') ?? 'Buscar…';
|
|
162
|
+
const layout = readStringProp(block, 'layout') ?? 'wide_only';
|
|
163
|
+
const segment = readStringProp(block, 'segment') ?? 'chats';
|
|
164
|
+
const activeSegment = readActiveSegment(data, 'hub.active_segment');
|
|
165
|
+
|
|
166
|
+
if (segment && activeSegment !== segment) return null;
|
|
167
|
+
|
|
168
|
+
if (hybrid.renderInboxSearchField) {
|
|
169
|
+
return (
|
|
170
|
+
<>
|
|
171
|
+
{hybrid.renderInboxSearchField({
|
|
172
|
+
block,
|
|
173
|
+
data,
|
|
174
|
+
onAction,
|
|
175
|
+
placeholder,
|
|
176
|
+
layout,
|
|
177
|
+
segment,
|
|
178
|
+
})}
|
|
179
|
+
</>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function CapabilitiesShell({
|
|
187
|
+
block,
|
|
188
|
+
data,
|
|
189
|
+
onAction,
|
|
190
|
+
rendererKey,
|
|
191
|
+
}: SduiBlockRenderProps & {
|
|
192
|
+
rendererKey:
|
|
193
|
+
| 'renderChatInboxCapabilities'
|
|
194
|
+
| 'renderFlashInboxCapabilities'
|
|
195
|
+
| 'renderProfileVisitsCapabilities';
|
|
196
|
+
}) {
|
|
197
|
+
const hybrid = useSduiHybridRenderer();
|
|
198
|
+
const renderer = hybrid[rendererKey];
|
|
199
|
+
if (typeof renderer !== 'function') return null;
|
|
200
|
+
return (
|
|
201
|
+
<>
|
|
202
|
+
{renderer({
|
|
203
|
+
block,
|
|
204
|
+
data,
|
|
205
|
+
onAction,
|
|
206
|
+
dataRef: readStringProp(block, 'data_ref'),
|
|
207
|
+
})}
|
|
208
|
+
</>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function SduiChatInboxCapabilitiesBlock(props: SduiBlockRenderProps) {
|
|
213
|
+
return <CapabilitiesShell {...props} rendererKey="renderChatInboxCapabilities" />;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function SduiFlashInboxCapabilitiesBlock(props: SduiBlockRenderProps) {
|
|
217
|
+
return <CapabilitiesShell {...props} rendererKey="renderFlashInboxCapabilities" />;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function SduiProfileVisitsCapabilitiesBlock(props: SduiBlockRenderProps) {
|
|
221
|
+
return <CapabilitiesShell {...props} rendererKey="renderProfileVisitsCapabilities" />;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const styles = StyleSheet.create({
|
|
225
|
+
segmentTrack: {
|
|
226
|
+
flexDirection: 'row',
|
|
227
|
+
flexGrow: 0,
|
|
228
|
+
flexShrink: 0,
|
|
229
|
+
alignSelf: 'stretch',
|
|
230
|
+
gap: spacing.sm,
|
|
231
|
+
backgroundColor: m3Colors.surfaceContainerHigh,
|
|
232
|
+
borderRadius: m3Shape.cornerFull,
|
|
233
|
+
padding: spacing.xs,
|
|
234
|
+
marginHorizontal: spacing.sm,
|
|
235
|
+
},
|
|
236
|
+
segment: {
|
|
237
|
+
flex: 1,
|
|
238
|
+
flexDirection: 'row',
|
|
239
|
+
alignItems: 'center',
|
|
240
|
+
justifyContent: 'center',
|
|
241
|
+
gap: spacing.xs,
|
|
242
|
+
paddingVertical: spacing.sm,
|
|
243
|
+
paddingHorizontal: spacing.sm,
|
|
244
|
+
borderRadius: m3Shape.cornerFull,
|
|
245
|
+
minHeight: 40,
|
|
246
|
+
},
|
|
247
|
+
segmentActive: {
|
|
248
|
+
backgroundColor: m3Colors.primaryContainer,
|
|
249
|
+
},
|
|
250
|
+
segmentGlyph: {
|
|
251
|
+
fontSize: 14,
|
|
252
|
+
},
|
|
253
|
+
segmentLabel: {
|
|
254
|
+
color: m3Colors.onSurfaceVariant,
|
|
255
|
+
fontFamily: fonts.semibold,
|
|
256
|
+
fontSize: 14,
|
|
257
|
+
},
|
|
258
|
+
segmentLabelActive: {
|
|
259
|
+
color: m3Colors.onPrimaryContainer,
|
|
260
|
+
},
|
|
261
|
+
emptyCard: {
|
|
262
|
+
alignItems: 'center',
|
|
263
|
+
gap: spacing.sm,
|
|
264
|
+
paddingVertical: spacing.xxl,
|
|
265
|
+
marginHorizontal: spacing.sm,
|
|
266
|
+
},
|
|
267
|
+
emptyTitle: {
|
|
268
|
+
color: m3Colors.onSurfaceVariant,
|
|
269
|
+
fontSize: 15,
|
|
270
|
+
fontFamily: fonts.medium,
|
|
271
|
+
textAlign: 'center',
|
|
272
|
+
},
|
|
273
|
+
emptyHint: {
|
|
274
|
+
color: m3Colors.onSurfaceVariant,
|
|
275
|
+
fontSize: 13,
|
|
276
|
+
textAlign: 'center',
|
|
277
|
+
},
|
|
278
|
+
rowCard: {
|
|
279
|
+
padding: spacing.md,
|
|
280
|
+
marginHorizontal: spacing.sm,
|
|
281
|
+
},
|
|
282
|
+
rowTitle: {
|
|
283
|
+
color: m3Colors.onSurface,
|
|
284
|
+
fontSize: 16,
|
|
285
|
+
fontFamily: fonts.semibold,
|
|
286
|
+
},
|
|
287
|
+
rowMeta: {
|
|
288
|
+
color: m3Colors.onSurfaceVariant,
|
|
289
|
+
fontSize: 12,
|
|
290
|
+
marginTop: spacing.xs,
|
|
291
|
+
},
|
|
292
|
+
});
|
|
@@ -20,6 +20,7 @@ function NativeBlockShell({
|
|
|
20
20
|
rendererKey:
|
|
21
21
|
| 'renderFlashInboxList'
|
|
22
22
|
| 'renderChatInboxList'
|
|
23
|
+
| 'renderProfileVisitsList'
|
|
23
24
|
| 'renderChatThread'
|
|
24
25
|
| 'renderSocialPostFeed'
|
|
25
26
|
| 'renderThoughtFeed'
|
|
@@ -75,6 +76,10 @@ export function SduiChatInboxListBlock(props: SduiBlockRenderProps) {
|
|
|
75
76
|
return <NativeBlockShell {...props} rendererKey="renderChatInboxList" fallbackLabel="Chat" />;
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
export function SduiProfileVisitsListBlock(props: SduiBlockRenderProps) {
|
|
80
|
+
return <NativeBlockShell {...props} rendererKey="renderProfileVisitsList" fallbackLabel="Visitas" />;
|
|
81
|
+
}
|
|
82
|
+
|
|
78
83
|
export function SduiChatThreadBlock(props: SduiBlockRenderProps) {
|
|
79
84
|
return <NativeBlockShell {...props} rendererKey="renderChatThread" fallbackLabel="Conversa" />;
|
|
80
85
|
}
|
|
@@ -29,6 +29,15 @@ import {
|
|
|
29
29
|
SduiProfileCompletionBannerBlock,
|
|
30
30
|
SduiStoryRailBlock,
|
|
31
31
|
} from './blocks/SduiSocialBlocks';
|
|
32
|
+
import {
|
|
33
|
+
SduiChatInboxCapabilitiesBlock,
|
|
34
|
+
SduiEmptyStateBlock,
|
|
35
|
+
SduiFlashInboxCapabilitiesBlock,
|
|
36
|
+
SduiInboxPersonRowBlock,
|
|
37
|
+
SduiInboxSearchFieldBlock,
|
|
38
|
+
SduiProfileVisitsCapabilitiesBlock,
|
|
39
|
+
SduiSegmentedTabsBlock,
|
|
40
|
+
} from './blocks/SduiInboxBlocks';
|
|
32
41
|
import { SduiNativeAdBlock } from './blocks/SduiNativeAdBlock';
|
|
33
42
|
import {
|
|
34
43
|
SduiAlbumDetailBlock,
|
|
@@ -36,6 +45,7 @@ import {
|
|
|
36
45
|
SduiChatInboxListBlock,
|
|
37
46
|
SduiChatThreadBlock,
|
|
38
47
|
SduiFlashInboxListBlock,
|
|
48
|
+
SduiProfileVisitsListBlock,
|
|
39
49
|
SduiNewPostComposerBlock,
|
|
40
50
|
SduiNewStoryComposerBlock,
|
|
41
51
|
SduiPostCommentsBlock,
|
|
@@ -70,6 +80,13 @@ const REGISTRY: Record<string, SduiBlockComponent> = {
|
|
|
70
80
|
toggle_row: SduiToggleRowBlock,
|
|
71
81
|
chip: SduiChipBlock,
|
|
72
82
|
chip_row: SduiChipRowBlock,
|
|
83
|
+
segmented_tabs: SduiSegmentedTabsBlock,
|
|
84
|
+
empty_state: SduiEmptyStateBlock,
|
|
85
|
+
inbox_person_row: SduiInboxPersonRowBlock,
|
|
86
|
+
inbox_search_field: SduiInboxSearchFieldBlock,
|
|
87
|
+
chat_inbox_capabilities: SduiChatInboxCapabilitiesBlock,
|
|
88
|
+
flash_inbox_capabilities: SduiFlashInboxCapabilitiesBlock,
|
|
89
|
+
profile_visits_capabilities: SduiProfileVisitsCapabilitiesBlock,
|
|
73
90
|
discover_grid: SduiDiscoverGridBlock,
|
|
74
91
|
discover_profile_card: SduiDiscoverProfileCardBlock,
|
|
75
92
|
discover_map: SduiDiscoverMapBlock,
|
|
@@ -78,6 +95,7 @@ const REGISTRY: Record<string, SduiBlockComponent> = {
|
|
|
78
95
|
profile_completion_banner: SduiProfileCompletionBannerBlock,
|
|
79
96
|
flash_inbox_list: SduiFlashInboxListBlock,
|
|
80
97
|
chat_inbox_list: SduiChatInboxListBlock,
|
|
98
|
+
profile_visits_list: SduiProfileVisitsListBlock,
|
|
81
99
|
chat_thread: SduiChatThreadBlock,
|
|
82
100
|
social_post_feed: SduiSocialPostFeedBlock,
|
|
83
101
|
thought_feed: SduiThoughtFeedBlock,
|
|
@@ -56,6 +56,7 @@ export type SduiHybridRenderers = {
|
|
|
56
56
|
onDiscoverMapCenterChange?: (coords: { lat: number; lng: number }) => void;
|
|
57
57
|
renderFlashInboxList?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
58
58
|
renderChatInboxList?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
59
|
+
renderProfileVisitsList?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
59
60
|
renderChatThread?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
60
61
|
renderSocialPostFeed?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
61
62
|
renderThoughtFeed?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
@@ -72,6 +73,35 @@ export type SduiHybridRenderers = {
|
|
|
72
73
|
renderSocialProfile?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
73
74
|
renderSettingsHome?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
74
75
|
renderDiscoverBrowseLocation?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
76
|
+
renderSegmentedTabs?: (props: {
|
|
77
|
+
block: SduiBlock;
|
|
78
|
+
data: Record<string, unknown>;
|
|
79
|
+
onAction: (actionId: string, vars?: Record<string, string>) => void;
|
|
80
|
+
segmentsRef?: string;
|
|
81
|
+
activeRef?: string;
|
|
82
|
+
actionPrefix?: string;
|
|
83
|
+
}) => ReactNode;
|
|
84
|
+
renderEmptyState?: (props: { title: string; hint?: string }) => ReactNode;
|
|
85
|
+
renderInboxPersonRow?: (props: {
|
|
86
|
+
block: SduiBlock;
|
|
87
|
+
data: Record<string, unknown>;
|
|
88
|
+
onAction: (actionId: string, vars?: Record<string, string>) => void;
|
|
89
|
+
variant: 'visit' | 'flash' | 'chat';
|
|
90
|
+
rowRef: string;
|
|
91
|
+
actionId?: string;
|
|
92
|
+
actionParams?: Record<string, string>;
|
|
93
|
+
}) => ReactNode;
|
|
94
|
+
renderInboxSearchField?: (props: {
|
|
95
|
+
block: SduiBlock;
|
|
96
|
+
data: Record<string, unknown>;
|
|
97
|
+
onAction: (actionId: string, vars?: Record<string, string>) => void;
|
|
98
|
+
placeholder: string;
|
|
99
|
+
layout: string;
|
|
100
|
+
segment: string;
|
|
101
|
+
}) => ReactNode;
|
|
102
|
+
renderChatInboxCapabilities?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
103
|
+
renderFlashInboxCapabilities?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
104
|
+
renderProfileVisitsCapabilities?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
75
105
|
};
|
|
76
106
|
|
|
77
107
|
const SduiHybridRendererContext = createContext<SduiHybridRenderers>({});
|