@proulr/sdui-components 0.1.17 → 0.1.19
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 +3 -2
- package/src/bdc/components/inbox.tsx +35 -4
- package/src/bdc/index.ts +2 -0
- package/src/catalog/app-icon-names.ts +84 -0
- package/src/catalog/chat-emoji-catalog.ts +115 -0
- package/src/catalog/flash-reaction-catalog.ts +46 -0
- package/src/catalog/index.ts +5 -0
- package/src/renderer/SduiScreenRenderer.tsx +15 -1
- package/src/renderer/blocks/SduiInboxBlocks.tsx +6 -0
- package/src/renderer/blocks/SduiLayoutBlocks.tsx +2 -2
- package/src/renderer/sdui-component-registry.tsx +2 -0
- package/src/renderer/sdui-hybrid-renderer-context.tsx +1 -0
- package/src/renderer/sdui-layout-debug.tsx +3 -1
- package/src/renderer/ui/AuthStepShell.tsx +2 -7
- package/src/renderer/ui/InfoBanner.tsx +5 -3
- package/src/renderer/ui/ListItem.tsx +2 -2
- package/src/renderer/ui/SelectRow.tsx +4 -4
- package/src/renderer/ui/app-glyphs.tsx +537 -0
- package/src/renderer/ui/app-icon.tsx +49 -57
- package/src/renderer/ui/compose-audience-pill.tsx +2 -6
- package/src/renderer/ui/compose-media-carousel.tsx +2 -6
- package/src/renderer/ui/compose-reply-audience-sheet.tsx +2 -6
- package/src/renderer/ui/floating-create-menu.tsx +6 -6
- package/src/renderer/ui/index.ts +30 -3
- package/src/renderer/ui/story-glyphs.tsx +3 -10
- package/src/renderer/ui/story-surface-picker.tsx +7 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proulr/sdui-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"main": "./src/renderer/index.ts",
|
|
5
5
|
"types": "./src/renderer/index.ts",
|
|
6
6
|
"exports": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"./renderer": "./src/renderer/index.ts",
|
|
10
10
|
"./ui": "./src/renderer/ui/index.ts",
|
|
11
11
|
"./primitives": "./src/renderer/ui/primitives.ts",
|
|
12
|
-
"./theme": "./src/renderer/theme/index.ts"
|
|
12
|
+
"./theme": "./src/renderer/theme/index.ts",
|
|
13
|
+
"./catalog": "./src/catalog/index.ts"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
15
16
|
"src"
|
|
@@ -54,15 +54,46 @@ type InboxCapabilitiesProps = {
|
|
|
54
54
|
dataRef?: string;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
function
|
|
57
|
+
function leafBlock(type: string, props: Record<string, unknown>): BdcElement {
|
|
58
58
|
return { type, props: { ...props }, children: [] };
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
export const ChatInboxCapabilities: BdcComponent = (props) =>
|
|
62
|
-
|
|
62
|
+
leafBlock('chat_inbox_capabilities', props as InboxCapabilitiesProps);
|
|
63
63
|
|
|
64
64
|
export const FlashInboxCapabilities: BdcComponent = (props) =>
|
|
65
|
-
|
|
65
|
+
leafBlock('flash_inbox_capabilities', props as InboxCapabilitiesProps);
|
|
66
66
|
|
|
67
67
|
export const ProfileVisitsCapabilities: BdcComponent = (props) =>
|
|
68
|
-
|
|
68
|
+
leafBlock('profile_visits_capabilities', props as InboxCapabilitiesProps);
|
|
69
|
+
|
|
70
|
+
export type FloatingCreateMenuActionProps = {
|
|
71
|
+
id: string;
|
|
72
|
+
label: string;
|
|
73
|
+
tone?: 'primary' | 'surface';
|
|
74
|
+
icon?: string;
|
|
75
|
+
actionId: string;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
type FloatingCreateMenuProps = {
|
|
79
|
+
id?: string;
|
|
80
|
+
closedLabel?: string;
|
|
81
|
+
actions: FloatingCreateMenuActionProps[];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/** Overlay FAB “+” (sibling do Scroll) — ações via action_id do wire. */
|
|
85
|
+
export const FloatingCreateMenu: BdcComponent = (props) => {
|
|
86
|
+
const menu = props as FloatingCreateMenuProps;
|
|
87
|
+
return leafBlock('floating_create_menu', {
|
|
88
|
+
...(menu.id ? { id: menu.id } : {}),
|
|
89
|
+
closedLabel: menu.closedLabel,
|
|
90
|
+
// Nested objects não passam por camelToSnake — normaliza action_id aqui.
|
|
91
|
+
actions: (menu.actions ?? []).map((action) => ({
|
|
92
|
+
id: action.id,
|
|
93
|
+
label: action.label,
|
|
94
|
+
tone: action.tone,
|
|
95
|
+
icon: action.icon,
|
|
96
|
+
action_id: action.actionId,
|
|
97
|
+
})),
|
|
98
|
+
});
|
|
99
|
+
};
|
package/src/bdc/index.ts
CHANGED
|
@@ -20,11 +20,13 @@ export {
|
|
|
20
20
|
ChatInboxCapabilities,
|
|
21
21
|
EmptyState,
|
|
22
22
|
FlashInboxCapabilities,
|
|
23
|
+
FloatingCreateMenu,
|
|
23
24
|
InboxPersonRow,
|
|
24
25
|
InboxSearchField,
|
|
25
26
|
ProfileVisitsCapabilities,
|
|
26
27
|
SegmentedTabs,
|
|
27
28
|
} from './components/inbox';
|
|
29
|
+
export type { FloatingCreateMenuActionProps } from './components/inbox';
|
|
28
30
|
export { TextField } from './components/forms';
|
|
29
31
|
export { ProfileCompletionBanner, StoryRail } from './components/social';
|
|
30
32
|
export {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** AppIconName tokens — fonte sem React Native (BFF + app + registry). */
|
|
2
|
+
export const APP_ICON_NAMES = [
|
|
3
|
+
'search',
|
|
4
|
+
'hunt',
|
|
5
|
+
'back',
|
|
6
|
+
'overflow',
|
|
7
|
+
'location',
|
|
8
|
+
'mic',
|
|
9
|
+
'send',
|
|
10
|
+
'chat',
|
|
11
|
+
'close',
|
|
12
|
+
'chevron-down',
|
|
13
|
+
'chevron-right',
|
|
14
|
+
'flip-camera',
|
|
15
|
+
'flash',
|
|
16
|
+
'gallery',
|
|
17
|
+
'video',
|
|
18
|
+
'camera',
|
|
19
|
+
'trash',
|
|
20
|
+
'globe',
|
|
21
|
+
'tab-discover',
|
|
22
|
+
'tab-vibes',
|
|
23
|
+
'tab-flash',
|
|
24
|
+
'tab-chat',
|
|
25
|
+
'boost',
|
|
26
|
+
'fire',
|
|
27
|
+
'settings',
|
|
28
|
+
'edit',
|
|
29
|
+
'incognito',
|
|
30
|
+
'events',
|
|
31
|
+
'shield',
|
|
32
|
+
'profile',
|
|
33
|
+
'bookmark',
|
|
34
|
+
'list',
|
|
35
|
+
'communities',
|
|
36
|
+
'star',
|
|
37
|
+
'sign-out',
|
|
38
|
+
'publish',
|
|
39
|
+
'story',
|
|
40
|
+
'story-music',
|
|
41
|
+
'story-sticker',
|
|
42
|
+
'story-text',
|
|
43
|
+
'story-effects',
|
|
44
|
+
'story-mention',
|
|
45
|
+
'repost',
|
|
46
|
+
'heart',
|
|
47
|
+
'heart-filled',
|
|
48
|
+
'thumbs-up',
|
|
49
|
+
'thumbs-up-filled',
|
|
50
|
+
'play',
|
|
51
|
+
'pause',
|
|
52
|
+
'plus',
|
|
53
|
+
'followers',
|
|
54
|
+
'mention',
|
|
55
|
+
'visibility',
|
|
56
|
+
'visibility-off',
|
|
57
|
+
'check',
|
|
58
|
+
'arrow-right',
|
|
59
|
+
'arrow-up-right',
|
|
60
|
+
'arrow-down-right',
|
|
61
|
+
'reply',
|
|
62
|
+
'pending',
|
|
63
|
+
'download',
|
|
64
|
+
'radio-unchecked',
|
|
65
|
+
'copy',
|
|
66
|
+
'attachment',
|
|
67
|
+
'poll',
|
|
68
|
+
'lock',
|
|
69
|
+
'volume-on',
|
|
70
|
+
'volume-off',
|
|
71
|
+
'info',
|
|
72
|
+
'warning',
|
|
73
|
+
'signal',
|
|
74
|
+
'hourglass',
|
|
75
|
+
'bell',
|
|
76
|
+
] as const;
|
|
77
|
+
|
|
78
|
+
export type AppIconName = (typeof APP_ICON_NAMES)[number];
|
|
79
|
+
|
|
80
|
+
const APP_ICON_NAME_SET: ReadonlySet<string> = new Set(APP_ICON_NAMES);
|
|
81
|
+
|
|
82
|
+
export function isAppIconName(value: string): value is AppIconName {
|
|
83
|
+
return APP_ICON_NAME_SET.has(value);
|
|
84
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export type EmojiCategoryId = 'spicy' | 'smileys' | 'gestures' | 'hearts' | 'animals' | 'food' | 'objects' | 'symbols';
|
|
2
|
+
|
|
3
|
+
export type EmojiCategory = {
|
|
4
|
+
id: EmojiCategoryId;
|
|
5
|
+
label: string;
|
|
6
|
+
tab: string;
|
|
7
|
+
emojis: readonly string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/** Pilula padrao quando ainda nao ha historico de uso. */
|
|
11
|
+
export const DEFAULT_QUICK_REACTIONS = ['👍', '🔥', '🍆', '💦', '❤️', '😂'] as const;
|
|
12
|
+
|
|
13
|
+
export const QUICK_REACTION_SLOTS = 6;
|
|
14
|
+
|
|
15
|
+
export const CHAT_EMOJI_CATEGORIES: EmojiCategory[] = [
|
|
16
|
+
{
|
|
17
|
+
id: 'spicy',
|
|
18
|
+
label: 'Safadinhos',
|
|
19
|
+
tab: '😈',
|
|
20
|
+
emojis: [
|
|
21
|
+
'👍', '🔥', '🍆', '💦', '👅', '🤤', '🍑', '😈', '💋', '🫦', '🥵', '😏',
|
|
22
|
+
'🛏️', '🫣', '👀', '💪', '🤭', '😘', '🥰', '😍', '🫠', '😮💨', '🍒', '🌶️',
|
|
23
|
+
'🥒', '🍌', '🧴', '🛁', '🚿', '🔞', '🫦', '😜', '😝', '🤫', '😳',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'smileys',
|
|
28
|
+
label: 'Rostos',
|
|
29
|
+
tab: '😀',
|
|
30
|
+
emojis: [
|
|
31
|
+
'😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂', '🙂', '🙃', '😉', '😊',
|
|
32
|
+
'😇', '🥰', '😍', '🤩', '😘', '😗', '😚', '😙', '🥲', '😋', '😛', '😜',
|
|
33
|
+
'🤪', '😝', '🤑', '🤗', '🤭', '🤫', '🤔', '🤐', '🤨', '😐', '😑', '😶',
|
|
34
|
+
'😏', '😒', '🙄', '😬', '🤥', '😌', '😔', '😪', '🤤', '😴', '😷', '🤒',
|
|
35
|
+
'🤕', '🤢', '🤮', '🤧', '🥵', '🥶', '🥴', '😵', '🤯', '🤠', '🥳', '🥸',
|
|
36
|
+
'😎', '🤓', '🧐', '😕', '😟', '🙁', '☹️', '😮', '😯', '😲', '😳', '🥺',
|
|
37
|
+
'😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱', '😖', '😣', '😞', '😓',
|
|
38
|
+
'😩', '😫', '🥱', '😤', '😡', '😠', '🤬',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'gestures',
|
|
43
|
+
label: 'Gestos',
|
|
44
|
+
tab: '👋',
|
|
45
|
+
emojis: [
|
|
46
|
+
'👍', '👎', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✌️', '🤞', '🤟', '🤘',
|
|
47
|
+
'🤙', '👈', '👉', '👆', '👇', '☝️', '✋', '🤚', '🖐', '🖖', '👋', '🤏',
|
|
48
|
+
'✊', '👊', '🤛', '🤜', '💪', '🦾', '🖕', '✍️', '🤳', '💅',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'hearts',
|
|
53
|
+
label: 'Amor',
|
|
54
|
+
tab: '❤️',
|
|
55
|
+
emojis: [
|
|
56
|
+
'❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💔', '❤️🔥', '❤️🩹',
|
|
57
|
+
'💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '💌', '💑', '💏', '🌹',
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'animals',
|
|
62
|
+
label: 'Animais',
|
|
63
|
+
tab: '🐶',
|
|
64
|
+
emojis: [
|
|
65
|
+
'🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮',
|
|
66
|
+
'🐷', '🐸', '🐵', '🐔', '🐧', '🐦', '🐤', '🦄', '🐝', '🦋', '🐢', '🐍',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'food',
|
|
71
|
+
label: 'Comida',
|
|
72
|
+
tab: '🍕',
|
|
73
|
+
emojis: [
|
|
74
|
+
'🍕', '🍔', '🍟', '🌭', '🍿', '🧁', '🍰', '🎂', '🍩', '🍪', '🍫', '🍬',
|
|
75
|
+
'🍭', '🍦', '🍧', '🍨', '🍎', '🍊', '🍋', '🍉', '🍇', '🍓', '🍑', '🍒',
|
|
76
|
+
'🥑', '🌮', '🍣', '🍺', '🍷', '🥂', '🍾', '☕', '🧃',
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'objects',
|
|
81
|
+
label: 'Coisas',
|
|
82
|
+
tab: '💡',
|
|
83
|
+
emojis: [
|
|
84
|
+
'⌚', '📱', '💻', '📷', '🎮', '🎧', '🎬', '🎤', '🎵', '🎶', '🎁', '🎈',
|
|
85
|
+
'🎉', '🎊', '🏆', '🥇', '🥈', '🥉', '⚽', '🏀', '🎾', '🚗', '✈️', '🚀',
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'symbols',
|
|
90
|
+
label: 'Símbolos',
|
|
91
|
+
tab: '✨',
|
|
92
|
+
emojis: [
|
|
93
|
+
'🔥', '✨', '💫', '⭐', '🌟', '💥', '💯', '💢', '💦', '💨', '🕳️', '💣',
|
|
94
|
+
'✅', '❌', '❓', '❗', '‼️', '⁉️', '🔴', '🟠', '🟡', '🟢', '🔵', '🟣',
|
|
95
|
+
'⚫', '⚪', '🟤', '🔶', '🔷', '🔸', '🔹',
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
export function getEmojiCategory(id: EmojiCategoryId): EmojiCategory {
|
|
101
|
+
return CHAT_EMOJI_CATEGORIES.find((category) => category.id === id) ?? CHAT_EMOJI_CATEGORIES[0];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function allCatalogEmojis(): string[] {
|
|
105
|
+
const seen = new Set<string>();
|
|
106
|
+
const result: string[] = [];
|
|
107
|
+
for (const category of CHAT_EMOJI_CATEGORIES) {
|
|
108
|
+
for (const emoji of category.emojis) {
|
|
109
|
+
if (seen.has(emoji)) continue;
|
|
110
|
+
seen.add(emoji);
|
|
111
|
+
result.push(emoji);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const FLASH_REACTION_IDS = ['flash', 'fire', 'heart', 'eyes', 'wave', 'chat'] as const;
|
|
2
|
+
|
|
3
|
+
export type FlashReactionId = (typeof FLASH_REACTION_IDS)[number];
|
|
4
|
+
|
|
5
|
+
export type FlashReaction = {
|
|
6
|
+
id: FlashReactionId;
|
|
7
|
+
emoji: string;
|
|
8
|
+
label: string;
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const FLASH_REACTIONS: FlashReaction[] = [
|
|
13
|
+
{ id: 'flash', emoji: '\u26a1', label: 'Flash', message: 'te enviou um Flash' },
|
|
14
|
+
{ id: 'fire', emoji: '\u{1F525}', label: 'Quente', message: 'achou você quente' },
|
|
15
|
+
{ id: 'heart', emoji: '\u{1F9E1}', label: 'Curti', message: 'curtiu você' },
|
|
16
|
+
{ id: 'eyes', emoji: '\u{1F440}', label: 'Interesse', message: 'está de olho em você' },
|
|
17
|
+
{ id: 'wave', emoji: '\u{1F44B}', label: 'Oi', message: 'mandou um oi' },
|
|
18
|
+
{ id: 'chat', emoji: '\u{1F4AC}', label: 'Conversar', message: 'quer conversar' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export const FLASH_FILTER_ALL_ACTION_ID = 'flash_filter_all';
|
|
22
|
+
|
|
23
|
+
const reactionById = Object.fromEntries(FLASH_REACTIONS.map((reaction) => [reaction.id, reaction])) as Record<
|
|
24
|
+
FlashReactionId,
|
|
25
|
+
FlashReaction
|
|
26
|
+
>;
|
|
27
|
+
|
|
28
|
+
export function getFlashReaction(id?: string | null): FlashReaction {
|
|
29
|
+
if (id && id in reactionById) return reactionById[id as FlashReactionId];
|
|
30
|
+
return reactionById.flash;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function flashFilterActionId(reactionId: FlashReactionId): string {
|
|
34
|
+
return `flash_filter_${reactionId}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function parseFlashInboxFilter(value: string | undefined): 'all' | FlashReactionId {
|
|
38
|
+
if (value && FLASH_REACTION_IDS.includes(value as FlashReactionId)) {
|
|
39
|
+
return value as FlashReactionId;
|
|
40
|
+
}
|
|
41
|
+
return 'all';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isFlashReactionId(value: string): value is FlashReactionId {
|
|
45
|
+
return FLASH_REACTION_IDS.includes(value as FlashReactionId);
|
|
46
|
+
}
|
|
@@ -10,11 +10,20 @@ type Props = {
|
|
|
10
10
|
onAction: (actionId: string, vars?: Record<string, string>) => void;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
/** Blocos overlay (FAB etc.) — não competem por flex com o Scroll. */
|
|
14
|
+
const OVERLAY_BLOCK_TYPES = new Set(['floating_create_menu']);
|
|
15
|
+
|
|
13
16
|
export function SduiScreenRenderer({ screen, onAction }: Props) {
|
|
14
17
|
return (
|
|
15
18
|
<SduiLayoutDebugFrame layer="renderer" style={styles.screen}>
|
|
16
19
|
{screen.blocks.map((block) => (
|
|
17
|
-
<SduiLayoutDebugFrame
|
|
20
|
+
<SduiLayoutDebugFrame
|
|
21
|
+
key={block.id}
|
|
22
|
+
layer="block"
|
|
23
|
+
extra={block.type}
|
|
24
|
+
style={OVERLAY_BLOCK_TYPES.has(block.type) ? styles.overlayBlock : styles.block}
|
|
25
|
+
pointerEvents={OVERLAY_BLOCK_TYPES.has(block.type) ? 'box-none' : undefined}
|
|
26
|
+
>
|
|
18
27
|
{renderBlockTree(block, screen.data, onAction)}
|
|
19
28
|
</SduiLayoutDebugFrame>
|
|
20
29
|
))}
|
|
@@ -25,4 +34,9 @@ export function SduiScreenRenderer({ screen, onAction }: Props) {
|
|
|
25
34
|
const styles = StyleSheet.create({
|
|
26
35
|
screen: { flex: 1, minHeight: 0, backgroundColor: colors.bg },
|
|
27
36
|
block: { flex: 1, minHeight: 0 },
|
|
37
|
+
overlayBlock: {
|
|
38
|
+
...StyleSheet.absoluteFill,
|
|
39
|
+
zIndex: 20,
|
|
40
|
+
elevation: 20,
|
|
41
|
+
},
|
|
28
42
|
});
|
|
@@ -221,6 +221,12 @@ export function SduiProfileVisitsCapabilitiesBlock(props: SduiBlockRenderProps)
|
|
|
221
221
|
return <CapabilitiesShell {...props} rendererKey="renderProfileVisitsCapabilities" />;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
export function SduiFloatingCreateMenuBlock(props: SduiBlockRenderProps) {
|
|
225
|
+
const hybrid = useSduiHybridRenderer();
|
|
226
|
+
if (typeof hybrid.renderFloatingCreateMenu !== 'function') return null;
|
|
227
|
+
return <>{hybrid.renderFloatingCreateMenu(props)}</>;
|
|
228
|
+
}
|
|
229
|
+
|
|
224
230
|
const styles = StyleSheet.create({
|
|
225
231
|
segmentTrack: {
|
|
226
232
|
flexDirection: 'row',
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { Pressable, StyleSheet, Switch, Text, View } from 'react-native';
|
|
3
3
|
import type { SduiBlock } from '@proulr/sdui-contract';
|
|
4
4
|
import { Card } from '../ui/Card';
|
|
5
|
+
import { AppIcon } from '../ui/app-icon';
|
|
5
6
|
import { colors, fonts, m3Colors, m3Type, spacing } from '../theme/proulr-theme';
|
|
6
7
|
import {
|
|
7
8
|
resolveDataRefBoolean,
|
|
@@ -69,7 +70,7 @@ export function SduiListItemBlock({ block, data, onAction }: SduiBlockRenderProp
|
|
|
69
70
|
</Text>
|
|
70
71
|
) : null}
|
|
71
72
|
</View>
|
|
72
|
-
{navChevron ? <
|
|
73
|
+
{navChevron ? <AppIcon name="chevron-right" size={22} color={m3Colors.onSurfaceVariant} /> : null}
|
|
73
74
|
{trailingText ? <Text style={styles.trailingText}>{trailingText}</Text> : null}
|
|
74
75
|
</>
|
|
75
76
|
);
|
|
@@ -152,7 +153,6 @@ const styles = StyleSheet.create({
|
|
|
152
153
|
listTitle: { color: colors.textPrimary, fontSize: 15, fontFamily: fonts.semibold },
|
|
153
154
|
listSubtitle: { color: colors.textSecondary, fontSize: 13, marginTop: 2 },
|
|
154
155
|
trailingText: { ...m3Type.bodySmall, color: colors.textSecondary },
|
|
155
|
-
chevron: { color: m3Colors.onSurfaceVariant, fontSize: 22 },
|
|
156
156
|
toggleRow: {
|
|
157
157
|
flexDirection: 'row',
|
|
158
158
|
alignItems: 'center',
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
SduiInboxPersonRowBlock,
|
|
37
37
|
SduiInboxSearchFieldBlock,
|
|
38
38
|
SduiProfileVisitsCapabilitiesBlock,
|
|
39
|
+
SduiFloatingCreateMenuBlock,
|
|
39
40
|
SduiSegmentedTabsBlock,
|
|
40
41
|
} from './blocks/SduiInboxBlocks';
|
|
41
42
|
import { SduiNativeAdBlock } from './blocks/SduiNativeAdBlock';
|
|
@@ -87,6 +88,7 @@ const REGISTRY: Record<string, SduiBlockComponent> = {
|
|
|
87
88
|
chat_inbox_capabilities: SduiChatInboxCapabilitiesBlock,
|
|
88
89
|
flash_inbox_capabilities: SduiFlashInboxCapabilitiesBlock,
|
|
89
90
|
profile_visits_capabilities: SduiProfileVisitsCapabilitiesBlock,
|
|
91
|
+
floating_create_menu: SduiFloatingCreateMenuBlock,
|
|
90
92
|
discover_grid: SduiDiscoverGridBlock,
|
|
91
93
|
discover_profile_card: SduiDiscoverProfileCardBlock,
|
|
92
94
|
discover_map: SduiDiscoverMapBlock,
|
|
@@ -102,6 +102,7 @@ export type SduiHybridRenderers = {
|
|
|
102
102
|
renderChatInboxCapabilities?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
103
103
|
renderFlashInboxCapabilities?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
104
104
|
renderProfileVisitsCapabilities?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
105
|
+
renderFloatingCreateMenu?: (props: SduiNativeBlockRenderProps) => ReactNode;
|
|
105
106
|
};
|
|
106
107
|
|
|
107
108
|
const SduiHybridRendererContext = createContext<SduiHybridRenderers>({});
|
|
@@ -73,15 +73,17 @@ export function SduiLayoutDebugFrame({
|
|
|
73
73
|
layer,
|
|
74
74
|
extra,
|
|
75
75
|
style,
|
|
76
|
+
pointerEvents,
|
|
76
77
|
children,
|
|
77
78
|
}: {
|
|
78
79
|
layer: SduiLayoutDebugLayer;
|
|
79
80
|
extra?: string;
|
|
80
81
|
style?: StyleProp<ViewStyle>;
|
|
82
|
+
pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only';
|
|
81
83
|
children: ReactNode;
|
|
82
84
|
}) {
|
|
83
85
|
return (
|
|
84
|
-
<View style={[sduiDebugViewStyle(layer), style]}>
|
|
86
|
+
<View style={[sduiDebugViewStyle(layer), style]} pointerEvents={pointerEvents}>
|
|
85
87
|
<SduiLayoutDebugLabel layer={layer} extra={extra} />
|
|
86
88
|
{children}
|
|
87
89
|
</View>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type ViewStyle,
|
|
11
11
|
} from 'react-native';
|
|
12
12
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
13
|
+
import { AppIcon } from './app-icon';
|
|
13
14
|
import { colors, fonts, m3Colors, m3Type, spacing } from '../theme/proulr-theme';
|
|
14
15
|
|
|
15
16
|
type AuthStepShellProps = {
|
|
@@ -46,7 +47,7 @@ export function AuthStepShell({
|
|
|
46
47
|
onPress={onBack}
|
|
47
48
|
style={({ pressed }) => [styles.backBtn, pressed && styles.pressed]}
|
|
48
49
|
>
|
|
49
|
-
<
|
|
50
|
+
<AppIcon name="back" size={24} color={m3Colors.onSurface} />
|
|
50
51
|
<Text style={styles.backLabel}>{backLabel}</Text>
|
|
51
52
|
</Pressable>
|
|
52
53
|
) : null}
|
|
@@ -90,12 +91,6 @@ const styles = StyleSheet.create({
|
|
|
90
91
|
marginBottom: spacing.md,
|
|
91
92
|
paddingVertical: spacing.xs,
|
|
92
93
|
},
|
|
93
|
-
backGlyph: {
|
|
94
|
-
color: m3Colors.onSurface,
|
|
95
|
-
fontSize: 24,
|
|
96
|
-
fontFamily: fonts.bold,
|
|
97
|
-
marginTop: -2,
|
|
98
|
-
},
|
|
99
94
|
backLabel: {
|
|
100
95
|
color: colors.textMuted,
|
|
101
96
|
fontSize: 14,
|
|
@@ -4,7 +4,7 @@ import { colors, fonts, radius, spacing } from '../theme/proulr-theme';
|
|
|
4
4
|
|
|
5
5
|
export function InfoBanner({
|
|
6
6
|
message,
|
|
7
|
-
icon
|
|
7
|
+
icon,
|
|
8
8
|
appIcon,
|
|
9
9
|
onDismiss,
|
|
10
10
|
}: {
|
|
@@ -13,11 +13,13 @@ export function InfoBanner({
|
|
|
13
13
|
appIcon?: AppIconName;
|
|
14
14
|
onDismiss?: () => void;
|
|
15
15
|
}) {
|
|
16
|
+
const resolvedAppIcon: AppIconName | undefined = appIcon ?? (icon ? undefined : 'info');
|
|
17
|
+
|
|
16
18
|
return (
|
|
17
19
|
<View style={styles.infoBanner}>
|
|
18
20
|
<View style={styles.infoIconWrap}>
|
|
19
|
-
{
|
|
20
|
-
<AppIcon name={
|
|
21
|
+
{resolvedAppIcon ? (
|
|
22
|
+
<AppIcon name={resolvedAppIcon} size={APP_ICON_SIZE.banner} color={colors.accentText} />
|
|
21
23
|
) : (
|
|
22
24
|
<Text style={styles.infoIcon}>{icon}</Text>
|
|
23
25
|
)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
import { AppIcon } from './app-icon';
|
|
3
4
|
import { colors, fonts, m3Colors, spacing } from '../theme/proulr-theme';
|
|
4
5
|
|
|
5
6
|
export function ListItem({
|
|
@@ -34,7 +35,7 @@ export function ListItem({
|
|
|
34
35
|
</Text>
|
|
35
36
|
) : null}
|
|
36
37
|
</View>
|
|
37
|
-
{navChevron ? <
|
|
38
|
+
{navChevron ? <AppIcon name="chevron-right" size={22} color={m3Colors.onSurfaceVariant} /> : null}
|
|
38
39
|
{trailing ? <View style={styles.listTrailing}>{trailing}</View> : null}
|
|
39
40
|
</>
|
|
40
41
|
);
|
|
@@ -65,5 +66,4 @@ const styles = StyleSheet.create({
|
|
|
65
66
|
listTitle: { color: colors.textPrimary, fontSize: 15, fontFamily: fonts.semibold },
|
|
66
67
|
listSubtitle: { color: colors.textSecondary, fontSize: 13, marginTop: 2 },
|
|
67
68
|
listTrailing: { alignItems: 'flex-end' },
|
|
68
|
-
chevron: { color: m3Colors.onSurfaceVariant, fontSize: 22 },
|
|
69
69
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { Modal, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
|
|
3
3
|
import { AppButton } from './AppButton';
|
|
4
|
+
import { AppIcon } from './app-icon';
|
|
4
5
|
import { colors, fonts, radius, spacing } from '../theme/proulr-theme';
|
|
5
6
|
|
|
6
7
|
function OptionModal({
|
|
@@ -31,7 +32,7 @@ function OptionModal({
|
|
|
31
32
|
return (
|
|
32
33
|
<Pressable key={opt} style={styles.optionRow} onPress={() => onSelect(opt)}>
|
|
33
34
|
<Text style={{ color: isSel ? colors.accentText : colors.white, fontSize: 16 }}>{opt}</Text>
|
|
34
|
-
{isSel ? <
|
|
35
|
+
{isSel ? <AppIcon name="check" size={16} color={colors.accent} /> : null}
|
|
35
36
|
</Pressable>
|
|
36
37
|
);
|
|
37
38
|
})}
|
|
@@ -66,7 +67,7 @@ export function SelectRow({
|
|
|
66
67
|
<Text style={styles.selectValue} numberOfLines={1}>
|
|
67
68
|
{value || 'Selecionar'}
|
|
68
69
|
</Text>
|
|
69
|
-
<
|
|
70
|
+
<AppIcon name="chevron-right" size={18} color={colors.textSecondary} />
|
|
70
71
|
</Pressable>
|
|
71
72
|
<OptionModal
|
|
72
73
|
title={label}
|
|
@@ -102,7 +103,7 @@ export function MultiSelectRow({
|
|
|
102
103
|
<Text style={styles.selectValue} numberOfLines={1}>
|
|
103
104
|
{values.length ? values.join(', ') : 'Selecionar'}
|
|
104
105
|
</Text>
|
|
105
|
-
<
|
|
106
|
+
<AppIcon name="chevron-right" size={18} color={colors.textSecondary} />
|
|
106
107
|
</Pressable>
|
|
107
108
|
<OptionModal
|
|
108
109
|
title={label}
|
|
@@ -134,7 +135,6 @@ const styles = StyleSheet.create({
|
|
|
134
135
|
},
|
|
135
136
|
selectLabel: { flex: 1, color: colors.white, fontSize: 15, fontFamily: fonts.medium },
|
|
136
137
|
selectValue: { color: colors.textSecondary, fontSize: 14, maxWidth: 160 },
|
|
137
|
-
chevron: { color: colors.textSecondary, fontSize: 18 },
|
|
138
138
|
modalBackdrop: { flex: 1, backgroundColor: colors.overlay, justifyContent: 'flex-end' },
|
|
139
139
|
modalSheet: {
|
|
140
140
|
backgroundColor: colors.surface,
|