@proulr/sdui-components 0.1.59 → 0.1.62
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/native-blocks.tsx +2 -0
- package/src/bdc/index.ts +2 -0
- package/src/catalog/app-icon-names.ts +1 -0
- package/src/renderer/blocks/SduiDiscoverBlocks.tsx +55 -1
- package/src/renderer/blocks/SduiNativeDomainBlocks.tsx +13 -1
- package/src/renderer/lib/discover-profile-formatters.ts +2 -0
- package/src/renderer/sdui-component-registry.tsx +4 -0
- package/src/renderer/sdui-hybrid-renderer-context.tsx +13 -0
- package/src/renderer/ui/app-glyphs.tsx +43 -0
- package/src/renderer/ui/app-icon.tsx +2 -0
- package/src/renderer/ui/index.ts +1 -0
package/package.json
CHANGED
|
@@ -41,3 +41,5 @@ export const ChatGroupAddMembers: BdcComponent = (props) =>
|
|
|
41
41
|
nativeBlock('chat_group_add_members', props);
|
|
42
42
|
export const ChatGroupInvite: BdcComponent = (props) => nativeBlock('chat_group_invite', props);
|
|
43
43
|
export const DiscoverBrowseLocation: BdcComponent = (props) => nativeBlock('discover_browse_location', props);
|
|
44
|
+
export const RightNowFeed: BdcComponent = (props) => nativeBlock('right_now_feed', props);
|
|
45
|
+
export const RightNowCompose: BdcComponent = (props) => nativeBlock('right_now_compose', props);
|
package/src/bdc/index.ts
CHANGED
|
@@ -134,6 +134,16 @@ export function SduiDiscoverProfileCardBlock({ block, data, onAction }: SduiBloc
|
|
|
134
134
|
<Text style={styles.travelBadgeText}>Viajando</Text>
|
|
135
135
|
</View>
|
|
136
136
|
) : null}
|
|
137
|
+
{person.is_right_now ? (
|
|
138
|
+
<View
|
|
139
|
+
style={[
|
|
140
|
+
styles.rightNowBadge,
|
|
141
|
+
person.has_new_media || person.traveling ? styles.rightNowBadgeOffset : null,
|
|
142
|
+
]}
|
|
143
|
+
>
|
|
144
|
+
<AppIcon name="right-now" size={12} color={m3Colors.primary} />
|
|
145
|
+
</View>
|
|
146
|
+
) : null}
|
|
137
147
|
<View style={styles.profileInfo}>
|
|
138
148
|
<Text style={styles.profileName} numberOfLines={1}>
|
|
139
149
|
{person.display_name ?? 'Alguém'}
|
|
@@ -329,10 +339,34 @@ export function SduiTextFieldBlock({ block, data, onAction }: SduiBlockRenderPro
|
|
|
329
339
|
);
|
|
330
340
|
}
|
|
331
341
|
|
|
332
|
-
|
|
342
|
+
function readMapPins(data: Record<string, unknown>, ref: string) {
|
|
343
|
+
const raw = resolveDataRef(data, ref);
|
|
344
|
+
if (!Array.isArray(raw)) return [];
|
|
345
|
+
return raw
|
|
346
|
+
.map((item) => {
|
|
347
|
+
if (!item || typeof item !== 'object') return null;
|
|
348
|
+
const row = item as Record<string, unknown>;
|
|
349
|
+
const id = typeof row.id === 'string' ? row.id : null;
|
|
350
|
+
const lat = typeof row.lat === 'number' ? row.lat : Number(row.lat);
|
|
351
|
+
const lng = typeof row.lng === 'number' ? row.lng : Number(row.lng);
|
|
352
|
+
if (!id || !Number.isFinite(lat) || !Number.isFinite(lng)) return null;
|
|
353
|
+
return {
|
|
354
|
+
id,
|
|
355
|
+
lat,
|
|
356
|
+
lng,
|
|
357
|
+
display_name: typeof row.display_name === 'string' ? row.display_name : null,
|
|
358
|
+
primary_photo_path:
|
|
359
|
+
typeof row.primary_photo_path === 'string' ? row.primary_photo_path : null,
|
|
360
|
+
};
|
|
361
|
+
})
|
|
362
|
+
.filter((pin): pin is NonNullable<typeof pin> => Boolean(pin));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function SduiDiscoverMapBlock({ block, data, onAction }: SduiBlockRenderProps) {
|
|
333
366
|
const hybrid = useSduiHybridRenderer();
|
|
334
367
|
const centerRefProp = readStringProp(block, 'center_ref') ?? 'browse_center';
|
|
335
368
|
const labelRef = readStringProp(block, 'label_ref') ?? 'map_label';
|
|
369
|
+
const pinsRef = readStringProp(block, 'pins_ref');
|
|
336
370
|
const height = readNumberProp(block, 'height', 340);
|
|
337
371
|
const regionLabel = resolveDataRefString(data, labelRef) || 'Região selecionada';
|
|
338
372
|
const centerValue = resolveDataRef(data, centerRefProp);
|
|
@@ -345,6 +379,7 @@ export function SduiDiscoverMapBlock({ block, data }: SduiBlockRenderProps) {
|
|
|
345
379
|
: { lat: -23.5505, lng: -46.6333 };
|
|
346
380
|
const centerMoveToken =
|
|
347
381
|
typeof data.map_center_move_token === 'number' ? data.map_center_move_token : 0;
|
|
382
|
+
const pins = pinsRef ? readMapPins(data, pinsRef) : [];
|
|
348
383
|
|
|
349
384
|
if (hybrid.renderDiscoverMap) {
|
|
350
385
|
return (
|
|
@@ -353,8 +388,11 @@ export function SduiDiscoverMapBlock({ block, data }: SduiBlockRenderProps) {
|
|
|
353
388
|
center,
|
|
354
389
|
label: regionLabel,
|
|
355
390
|
height,
|
|
391
|
+
pins,
|
|
392
|
+
interactive: pins.length === 0,
|
|
356
393
|
centerMoveToken,
|
|
357
394
|
onCenterChange: hybrid.onDiscoverMapCenterChange ?? (() => {}),
|
|
395
|
+
onPinPress: (profileId) => onAction('open_profile', { profile_id: profileId }),
|
|
358
396
|
})}
|
|
359
397
|
</>
|
|
360
398
|
);
|
|
@@ -408,6 +446,22 @@ const styles = StyleSheet.create({
|
|
|
408
446
|
top: spacing.sm + 24,
|
|
409
447
|
},
|
|
410
448
|
travelBadgeText: { color: m3Colors.onSecondaryContainer, fontSize: 11, fontWeight: '700' },
|
|
449
|
+
rightNowBadge: {
|
|
450
|
+
position: 'absolute',
|
|
451
|
+
top: spacing.sm,
|
|
452
|
+
left: spacing.sm,
|
|
453
|
+
width: 26,
|
|
454
|
+
height: 26,
|
|
455
|
+
borderRadius: 13,
|
|
456
|
+
alignItems: 'center',
|
|
457
|
+
justifyContent: 'center',
|
|
458
|
+
backgroundColor: m3Colors.surfaceContainerHighest,
|
|
459
|
+
borderWidth: 1,
|
|
460
|
+
borderColor: m3Colors.primary,
|
|
461
|
+
},
|
|
462
|
+
rightNowBadgeOffset: {
|
|
463
|
+
left: spacing.sm + 52,
|
|
464
|
+
},
|
|
411
465
|
profileInfo: { position: 'absolute', left: spacing.sm, bottom: spacing.sm, right: spacing.sm },
|
|
412
466
|
profileName: { color: colors.white, fontSize: 13, fontWeight: '700' },
|
|
413
467
|
distRow: { flexDirection: 'row', alignItems: 'center', gap: 6, marginTop: 2 },
|
|
@@ -39,7 +39,9 @@ function NativeBlockShell({
|
|
|
39
39
|
| 'renderChatGroupInfo'
|
|
40
40
|
| 'renderChatGroupAddMembers'
|
|
41
41
|
| 'renderChatGroupInvite'
|
|
42
|
-
| 'renderDiscoverBrowseLocation'
|
|
42
|
+
| 'renderDiscoverBrowseLocation'
|
|
43
|
+
| 'renderRightNowFeed'
|
|
44
|
+
| 'renderRightNowCompose';
|
|
43
45
|
fallbackLabel: string;
|
|
44
46
|
}) {
|
|
45
47
|
const hybrid = useSduiHybridRenderer();
|
|
@@ -172,3 +174,13 @@ export function SduiDiscoverBrowseLocationBlock(props: SduiBlockRenderProps) {
|
|
|
172
174
|
/>
|
|
173
175
|
);
|
|
174
176
|
}
|
|
177
|
+
|
|
178
|
+
export function SduiRightNowFeedBlock(props: SduiBlockRenderProps) {
|
|
179
|
+
return <NativeBlockShell {...props} rendererKey="renderRightNowFeed" fallbackLabel="Right Now feed" />;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function SduiRightNowComposeBlock(props: SduiBlockRenderProps) {
|
|
183
|
+
return (
|
|
184
|
+
<NativeBlockShell {...props} rendererKey="renderRightNowCompose" fallbackLabel="Right Now compose" />
|
|
185
|
+
);
|
|
186
|
+
}
|
|
@@ -10,6 +10,8 @@ export type DiscoverNearbyProfileWire = {
|
|
|
10
10
|
is_creator?: boolean | null;
|
|
11
11
|
has_new_media?: boolean | null;
|
|
12
12
|
traveling?: boolean | null;
|
|
13
|
+
right_now_until?: string | null;
|
|
14
|
+
is_right_now?: boolean | null;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
export type DiscoverGridProfileItemWire = {
|
|
@@ -66,6 +66,8 @@ import {
|
|
|
66
66
|
SduiChatGroupAddMembersBlock,
|
|
67
67
|
SduiChatGroupInviteBlock,
|
|
68
68
|
SduiDiscoverBrowseLocationBlock,
|
|
69
|
+
SduiRightNowComposeBlock,
|
|
70
|
+
SduiRightNowFeedBlock,
|
|
69
71
|
SduiThoughtFeedBlock,
|
|
70
72
|
} from './blocks/SduiNativeDomainBlocks';
|
|
71
73
|
|
|
@@ -128,6 +130,8 @@ const REGISTRY: Record<string, SduiBlockComponent> = {
|
|
|
128
130
|
chat_group_add_members: SduiChatGroupAddMembersBlock,
|
|
129
131
|
chat_group_invite: SduiChatGroupInviteBlock,
|
|
130
132
|
discover_browse_location: SduiDiscoverBrowseLocationBlock,
|
|
133
|
+
right_now_feed: SduiRightNowFeedBlock,
|
|
134
|
+
right_now_compose: SduiRightNowComposeBlock,
|
|
131
135
|
};
|
|
132
136
|
|
|
133
137
|
export function resolveSduiBlockComponent(type: string): SduiBlockComponent {
|
|
@@ -12,12 +12,23 @@ export type SduiHybridProfileCompletionBannerProps = {
|
|
|
12
12
|
onComplete: () => void;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export type SduiHybridDiscoverMapPin = {
|
|
16
|
+
id: string;
|
|
17
|
+
lat: number;
|
|
18
|
+
lng: number;
|
|
19
|
+
display_name?: string | null;
|
|
20
|
+
primary_photo_path?: string | null;
|
|
21
|
+
};
|
|
22
|
+
|
|
15
23
|
export type SduiHybridDiscoverMapProps = {
|
|
16
24
|
center: { lat: number; lng: number };
|
|
17
25
|
label: string;
|
|
18
26
|
height: number;
|
|
27
|
+
pins?: SduiHybridDiscoverMapPin[];
|
|
19
28
|
onCenterChange: (coords: { lat: number; lng: number }) => void;
|
|
29
|
+
onPinPress?: (profileId: string) => void;
|
|
20
30
|
centerMoveToken: number;
|
|
31
|
+
interactive?: boolean;
|
|
21
32
|
};
|
|
22
33
|
|
|
23
34
|
export type SduiHybridDiscoverProfileCardProps = {
|
|
@@ -76,6 +87,8 @@ export type SduiHybridRenderers = {
|
|
|
76
87
|
renderChatGroupAddMembers?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
77
88
|
renderChatGroupInvite?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
78
89
|
renderDiscoverBrowseLocation?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
90
|
+
renderRightNowFeed?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
91
|
+
renderRightNowCompose?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
79
92
|
renderSegmentedTabs?: (props: {
|
|
80
93
|
block: SduiBlock;
|
|
81
94
|
data: Record<string, unknown>;
|
|
@@ -593,6 +593,49 @@ export function AppChromeFireGlyph({ color = m3Colors.primary, size = 24 }: AppC
|
|
|
593
593
|
);
|
|
594
594
|
}
|
|
595
595
|
|
|
596
|
+
/**
|
|
597
|
+
* Right Now — flame (🔥). Source SVG: assets/icons/right-now.svg
|
|
598
|
+
* Outline teardrop + solid inner tongue (reads at 12–24px chrome sizes).
|
|
599
|
+
*/
|
|
600
|
+
export function AppChromeRightNowGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
|
|
601
|
+
const stroke = strokeFor(size);
|
|
602
|
+
const outerW = size * 0.5;
|
|
603
|
+
const outerH = size * 0.74;
|
|
604
|
+
const innerW = outerW * 0.4;
|
|
605
|
+
const innerH = outerH * 0.42;
|
|
606
|
+
return (
|
|
607
|
+
<View style={{ width: size, height: size, alignItems: 'center', justifyContent: 'center' }}>
|
|
608
|
+
<View
|
|
609
|
+
style={{
|
|
610
|
+
width: outerW,
|
|
611
|
+
height: outerH,
|
|
612
|
+
borderTopLeftRadius: outerW * 0.58,
|
|
613
|
+
borderTopRightRadius: outerW * 0.58,
|
|
614
|
+
borderBottomLeftRadius: outerW * 0.46,
|
|
615
|
+
borderBottomRightRadius: outerW * 0.46,
|
|
616
|
+
borderWidth: stroke,
|
|
617
|
+
borderColor: color,
|
|
618
|
+
alignItems: 'center',
|
|
619
|
+
justifyContent: 'flex-end',
|
|
620
|
+
paddingBottom: size * 0.11,
|
|
621
|
+
}}
|
|
622
|
+
>
|
|
623
|
+
<View
|
|
624
|
+
style={{
|
|
625
|
+
width: innerW,
|
|
626
|
+
height: innerH,
|
|
627
|
+
backgroundColor: color,
|
|
628
|
+
borderTopLeftRadius: innerW * 0.55,
|
|
629
|
+
borderTopRightRadius: innerW * 0.55,
|
|
630
|
+
borderBottomLeftRadius: innerW * 0.42,
|
|
631
|
+
borderBottomRightRadius: innerW * 0.42,
|
|
632
|
+
}}
|
|
633
|
+
/>
|
|
634
|
+
</View>
|
|
635
|
+
</View>
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
|
|
596
639
|
/** Editar perfil — só lápis (corpo + ponta). */
|
|
597
640
|
export function AppChromeEditGlyph({ color = m3Colors.primary, size = 24 }: AppChromeGlyphProps) {
|
|
598
641
|
const bodyW = Math.max(3, size * 0.17);
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
AppChromeCropGlyph,
|
|
23
23
|
AppChromeEventsGlyph,
|
|
24
24
|
AppChromeFireGlyph,
|
|
25
|
+
AppChromeRightNowGlyph,
|
|
25
26
|
AppChromeFlashGlyph,
|
|
26
27
|
AppChromeFlipCameraGlyph,
|
|
27
28
|
AppChromeHeartFilledGlyph,
|
|
@@ -115,6 +116,7 @@ const ICON_REGISTRY: Record<AppIconName, ComponentType<AppChromeGlyphProps>> = {
|
|
|
115
116
|
'tab-random': AppChromeTabRandomGlyph,
|
|
116
117
|
boost: AppChromeBoostGlyph,
|
|
117
118
|
fire: AppChromeFireGlyph,
|
|
119
|
+
'right-now': AppChromeRightNowGlyph,
|
|
118
120
|
settings: AppChromeSettingsGlyph,
|
|
119
121
|
edit: AppChromeEditGlyph,
|
|
120
122
|
crop: AppChromeCropGlyph,
|