@teamvortexsoftware/vortex-react-native 1.0.0 → 1.0.1

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 (217) hide show
  1. package/dist/InviteFormCore-D4HkMMo0.d.mts +721 -0
  2. package/dist/InviteFormCore-D9oUCbu7.d.ts +721 -0
  3. package/dist/VortexClient.js +192 -0
  4. package/dist/VortexClient.js.map +1 -0
  5. package/dist/VortexDeferredLinks.js +127 -0
  6. package/dist/VortexDeferredLinks.js.map +1 -0
  7. package/dist/clientInfo.js +45 -0
  8. package/dist/clientInfo.js.map +1 -0
  9. package/dist/components/ContactsPickerModal.js +182 -0
  10. package/dist/components/ContactsPickerModal.js.map +1 -0
  11. package/dist/components/InviteFormCore.js +2141 -0
  12. package/dist/components/InviteFormCore.js.map +1 -0
  13. package/dist/components/InviteFormMobile.js +463 -0
  14. package/dist/components/InviteFormMobile.js.map +1 -0
  15. package/dist/components/InviteFormWeb.js +295 -0
  16. package/dist/components/InviteFormWeb.js.map +1 -0
  17. package/dist/components/PlacedItemToolbar.js +147 -0
  18. package/dist/components/PlacedItemToolbar.js.map +1 -0
  19. package/dist/components/ShareButtons.js +181 -0
  20. package/dist/components/ShareButtons.js.map +1 -0
  21. package/dist/components/VrtxContactsImport.js +234 -0
  22. package/dist/components/VrtxContactsImport.js.map +1 -0
  23. package/dist/components/VrtxEmailInvitations.js +341 -0
  24. package/dist/components/VrtxEmailInvitations.js.map +1 -0
  25. package/dist/components/VrtxFindFriends.js +400 -0
  26. package/dist/components/VrtxFindFriends.js.map +1 -0
  27. package/dist/components/VrtxHeading.js +58 -0
  28. package/dist/components/VrtxHeading.js.map +1 -0
  29. package/dist/components/VrtxIncomingInvitations.js +657 -0
  30. package/dist/components/VrtxIncomingInvitations.js.map +1 -0
  31. package/dist/components/VrtxInvitationSuggestions.js +506 -0
  32. package/dist/components/VrtxInvitationSuggestions.js.map +1 -0
  33. package/dist/components/VrtxInviteContacts.js +512 -0
  34. package/dist/components/VrtxInviteContacts.js.map +1 -0
  35. package/dist/components/VrtxOutgoingInvitations.js +572 -0
  36. package/dist/components/VrtxOutgoingInvitations.js.map +1 -0
  37. package/dist/components/VrtxSearchBox.js +487 -0
  38. package/dist/components/VrtxSearchBox.js.map +1 -0
  39. package/dist/components/VrtxSelect.js +27 -0
  40. package/dist/components/VrtxSelect.js.map +1 -0
  41. package/dist/components/VrtxShareOptions.js +435 -0
  42. package/dist/components/VrtxShareOptions.js.map +1 -0
  43. package/dist/components/VrtxSubmit.js +132 -0
  44. package/dist/components/VrtxSubmit.js.map +1 -0
  45. package/dist/components/VrtxText.js +146 -0
  46. package/dist/components/VrtxText.js.map +1 -0
  47. package/dist/constants/mockData.d.mts +7 -0
  48. package/dist/constants/mockData.d.ts +7 -0
  49. package/dist/constants/mockData.js +48 -0
  50. package/dist/constants/mockData.js.map +1 -0
  51. package/dist/constants/mockData.mjs +22 -0
  52. package/dist/constants/mockData.mjs.map +1 -0
  53. package/dist/context/VortexModulesContext.js +135 -0
  54. package/dist/context/VortexModulesContext.js.map +1 -0
  55. package/dist/hooks/useInvitationFormLogic.d.mts +2 -0
  56. package/dist/hooks/useInvitationFormLogic.d.ts +2 -0
  57. package/dist/hooks/useInvitationFormLogic.js +300 -0
  58. package/dist/hooks/useInvitationFormLogic.js.map +1 -0
  59. package/dist/hooks/useInvitationFormLogic.mjs +276 -0
  60. package/dist/hooks/useInvitationFormLogic.mjs.map +1 -0
  61. package/dist/hooks/usePrefetchWidgetConfiguration.js +117 -0
  62. package/dist/hooks/usePrefetchWidgetConfiguration.js.map +1 -0
  63. package/dist/hooks/useThemeStyles.js +41 -0
  64. package/dist/hooks/useThemeStyles.js.map +1 -0
  65. package/dist/hooks/useVortexInvite.js +732 -0
  66. package/dist/hooks/useVortexInvite.js.map +1 -0
  67. package/dist/index-web.d.mts +93 -0
  68. package/dist/index-web.d.ts +93 -0
  69. package/dist/index-web.js +7397 -0
  70. package/dist/index-web.js.map +1 -0
  71. package/dist/index-web.mjs +7445 -0
  72. package/dist/index-web.mjs.map +1 -0
  73. package/dist/index.d.mts +656 -0
  74. package/dist/index.d.ts +656 -0
  75. package/dist/index.js +10206 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/index.mjs +10244 -0
  78. package/dist/index.mjs.map +1 -0
  79. package/dist/types/VortexClient.d.ts +106 -0
  80. package/dist/types/VortexClient.d.ts.map +1 -0
  81. package/dist/types/VortexDeferredLinks.d.ts +73 -0
  82. package/dist/types/VortexDeferredLinks.d.ts.map +1 -0
  83. package/dist/types/clientInfo.d.ts +5 -0
  84. package/dist/types/clientInfo.d.ts.map +1 -0
  85. package/dist/types/components/ContactsPickerModal.d.ts +18 -0
  86. package/dist/types/components/ContactsPickerModal.d.ts.map +1 -0
  87. package/dist/types/components/InviteFormCore.d.ts +166 -0
  88. package/dist/types/components/InviteFormCore.d.ts.map +1 -0
  89. package/dist/types/components/InviteFormMobile.d.ts +42 -0
  90. package/dist/types/components/InviteFormMobile.d.ts.map +1 -0
  91. package/dist/types/components/InviteFormWeb.d.ts +87 -0
  92. package/dist/types/components/InviteFormWeb.d.ts.map +1 -0
  93. package/dist/types/components/PlacedItemToolbar.d.ts +16 -0
  94. package/dist/types/components/PlacedItemToolbar.d.ts.map +1 -0
  95. package/dist/types/components/ShareButtons.d.ts +29 -0
  96. package/dist/types/components/ShareButtons.d.ts.map +1 -0
  97. package/dist/types/components/VrtxContactsImport.d.ts +14 -0
  98. package/dist/types/components/VrtxContactsImport.d.ts.map +1 -0
  99. package/dist/types/components/VrtxEmailInvitations.d.ts +31 -0
  100. package/dist/types/components/VrtxEmailInvitations.d.ts.map +1 -0
  101. package/dist/types/components/VrtxFindFriends.d.ts +25 -0
  102. package/dist/types/components/VrtxFindFriends.d.ts.map +1 -0
  103. package/dist/types/components/VrtxHeading.d.ts +6 -0
  104. package/dist/types/components/VrtxHeading.d.ts.map +1 -0
  105. package/dist/types/components/VrtxIncomingInvitations.d.ts +27 -0
  106. package/dist/types/components/VrtxIncomingInvitations.d.ts.map +1 -0
  107. package/dist/types/components/VrtxInvitationSuggestions.d.ts +25 -0
  108. package/dist/types/components/VrtxInvitationSuggestions.d.ts.map +1 -0
  109. package/dist/types/components/VrtxInviteContacts.d.ts +24 -0
  110. package/dist/types/components/VrtxInviteContacts.d.ts.map +1 -0
  111. package/dist/types/components/VrtxOutgoingInvitations.d.ts +27 -0
  112. package/dist/types/components/VrtxOutgoingInvitations.d.ts.map +1 -0
  113. package/dist/types/components/VrtxSearchBox.d.ts +28 -0
  114. package/dist/types/components/VrtxSearchBox.d.ts.map +1 -0
  115. package/dist/types/components/VrtxSelect.d.ts +6 -0
  116. package/dist/types/components/VrtxSelect.d.ts.map +1 -0
  117. package/dist/types/components/VrtxShareOptions.d.ts +41 -0
  118. package/dist/types/components/VrtxShareOptions.d.ts.map +1 -0
  119. package/dist/types/components/VrtxSubmit.d.ts +18 -0
  120. package/dist/types/components/VrtxSubmit.d.ts.map +1 -0
  121. package/dist/types/components/VrtxText.d.ts +8 -0
  122. package/dist/types/components/VrtxText.d.ts.map +1 -0
  123. package/dist/types/constants/mockData.d.ts +4 -0
  124. package/dist/types/constants/mockData.d.ts.map +1 -0
  125. package/dist/types/context/VortexModulesContext.d.ts +238 -0
  126. package/dist/types/context/VortexModulesContext.d.ts.map +1 -0
  127. package/dist/types/findFriends.js +10 -0
  128. package/dist/types/findFriends.js.map +1 -0
  129. package/dist/types/hooks/useInvitationFormLogic.d.ts +55 -0
  130. package/dist/types/hooks/useInvitationFormLogic.d.ts.map +1 -0
  131. package/dist/types/hooks/usePrefetchWidgetConfiguration.d.ts +39 -0
  132. package/dist/types/hooks/usePrefetchWidgetConfiguration.d.ts.map +1 -0
  133. package/dist/types/hooks/useThemeStyles.d.ts +35 -0
  134. package/dist/types/hooks/useThemeStyles.d.ts.map +1 -0
  135. package/dist/types/hooks/useVortexInvite.d.ts +86 -0
  136. package/dist/types/hooks/useVortexInvite.d.ts.map +1 -0
  137. package/dist/types/index-web.d.ts +23 -0
  138. package/dist/types/index-web.d.ts.map +1 -0
  139. package/dist/types/index.d.ts +23 -0
  140. package/dist/types/index.d.ts.map +1 -0
  141. package/dist/types/invitations.js +13 -0
  142. package/dist/types/invitations.js.map +1 -0
  143. package/dist/types/inviteContacts.js +14 -0
  144. package/dist/types/inviteContacts.js.map +1 -0
  145. package/dist/types/platformOperations.js +3 -0
  146. package/dist/types/platformOperations.js.map +1 -0
  147. package/dist/types/searchBox.js +11 -0
  148. package/dist/types/searchBox.js.map +1 -0
  149. package/dist/types/types/findFriends.d.ts +101 -0
  150. package/dist/types/types/findFriends.d.ts.map +1 -0
  151. package/dist/types/types/invitations.d.ts +301 -0
  152. package/dist/types/types/invitations.d.ts.map +1 -0
  153. package/dist/types/types/inviteContacts.d.ts +86 -0
  154. package/dist/types/types/inviteContacts.d.ts.map +1 -0
  155. package/dist/types/types/platformOperations.d.ts +185 -0
  156. package/dist/types/types/platformOperations.d.ts.map +1 -0
  157. package/dist/types/types/searchBox.d.ts +69 -0
  158. package/dist/types/types/searchBox.d.ts.map +1 -0
  159. package/dist/types/types/unfurlConfig.d.ts +34 -0
  160. package/dist/types/types/unfurlConfig.d.ts.map +1 -0
  161. package/dist/types/unfurlConfig.js +21 -0
  162. package/dist/types/unfurlConfig.js.map +1 -0
  163. package/dist/types/utils/analytics.d.ts +54 -0
  164. package/dist/types/utils/analytics.d.ts.map +1 -0
  165. package/dist/types/utils/configCache.d.ts +34 -0
  166. package/dist/types/utils/configCache.d.ts.map +1 -0
  167. package/dist/types/utils/contactUtils.d.ts +9 -0
  168. package/dist/types/utils/contactUtils.d.ts.map +1 -0
  169. package/dist/types/utils/featureWarnings.d.ts +56 -0
  170. package/dist/types/utils/featureWarnings.d.ts.map +1 -0
  171. package/dist/types/utils/formUtils.d.ts +93 -0
  172. package/dist/types/utils/formUtils.d.ts.map +1 -0
  173. package/dist/types/utils/gradientUtils.d.ts +67 -0
  174. package/dist/types/utils/gradientUtils.d.ts.map +1 -0
  175. package/dist/types/utils/invitationEvents.d.ts +21 -0
  176. package/dist/types/utils/invitationEvents.d.ts.map +1 -0
  177. package/dist/types/utils/moduleLoaders.d.ts +115 -0
  178. package/dist/types/utils/moduleLoaders.d.ts.map +1 -0
  179. package/dist/types/utils/moduleLoaders.web.d.ts +73 -0
  180. package/dist/types/utils/moduleLoaders.web.d.ts.map +1 -0
  181. package/dist/types/utils/nameUtils.d.ts +15 -0
  182. package/dist/types/utils/nameUtils.d.ts.map +1 -0
  183. package/dist/types/utils/themeUtils.d.ts +38 -0
  184. package/dist/types/utils/themeUtils.d.ts.map +1 -0
  185. package/dist/types/vortexInvite.d.ts +165 -0
  186. package/dist/types/vortexInvite.d.ts.map +1 -0
  187. package/dist/useInvitationFormLogic-Ct73M19B.d.mts +242 -0
  188. package/dist/useInvitationFormLogic-Ct73M19B.d.ts +242 -0
  189. package/dist/utils/analytics.js +92 -0
  190. package/dist/utils/analytics.js.map +1 -0
  191. package/dist/utils/configCache.js +68 -0
  192. package/dist/utils/configCache.js.map +1 -0
  193. package/dist/utils/contactUtils.d.mts +12 -0
  194. package/dist/utils/contactUtils.d.ts +12 -0
  195. package/dist/utils/contactUtils.js +37 -0
  196. package/dist/utils/contactUtils.js.map +1 -0
  197. package/dist/utils/contactUtils.mjs +12 -0
  198. package/dist/utils/contactUtils.mjs.map +1 -0
  199. package/dist/utils/featureWarnings.js +214 -0
  200. package/dist/utils/featureWarnings.js.map +1 -0
  201. package/dist/utils/formUtils.js +284 -0
  202. package/dist/utils/formUtils.js.map +1 -0
  203. package/dist/utils/gradientUtils.js +120 -0
  204. package/dist/utils/gradientUtils.js.map +1 -0
  205. package/dist/utils/invitationEvents.js +45 -0
  206. package/dist/utils/invitationEvents.js.map +1 -0
  207. package/dist/utils/moduleLoaders.js +275 -0
  208. package/dist/utils/moduleLoaders.js.map +1 -0
  209. package/dist/utils/moduleLoaders.web.js +72 -0
  210. package/dist/utils/moduleLoaders.web.js.map +1 -0
  211. package/dist/utils/nameUtils.js +51 -0
  212. package/dist/utils/nameUtils.js.map +1 -0
  213. package/dist/utils/themeUtils.js +141 -0
  214. package/dist/utils/themeUtils.js.map +1 -0
  215. package/dist/vortexInvite.js +83 -0
  216. package/dist/vortexInvite.js.map +1 -0
  217. package/package.json +21 -56
@@ -0,0 +1,2141 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.InviteFormCore = InviteFormCore;
46
+ const react_1 = __importStar(require("react"));
47
+ const react_native_1 = require("react-native");
48
+ const useInvitationFormLogic_1 = require("../hooks/useInvitationFormLogic");
49
+ const contactUtils_1 = require("../utils/contactUtils");
50
+ const VrtxShareOptions_1 = require("./VrtxShareOptions");
51
+ const VrtxContactsImport_1 = require("./VrtxContactsImport");
52
+ const VrtxEmailInvitations_1 = require("./VrtxEmailInvitations");
53
+ const VrtxFindFriends_1 = require("./VrtxFindFriends");
54
+ const VrtxIncomingInvitations_1 = require("./VrtxIncomingInvitations");
55
+ const VrtxOutgoingInvitations_1 = require("./VrtxOutgoingInvitations");
56
+ const VrtxInvitationSuggestions_1 = require("./VrtxInvitationSuggestions");
57
+ const VrtxInviteContacts_1 = require("./VrtxInviteContacts");
58
+ const VrtxHeading_1 = require("./VrtxHeading");
59
+ const VrtxText_1 = require("./VrtxText");
60
+ const VrtxSelect_1 = require("./VrtxSelect");
61
+ const VrtxSubmit_1 = require("./VrtxSubmit");
62
+ const VrtxSearchBox_1 = require("./VrtxSearchBox");
63
+ const PlacedItemToolbar_1 = require("./PlacedItemToolbar");
64
+ const isWeb = react_native_1.Platform.OS === 'web';
65
+ // Parse CSS linear-gradient to extract first color for fallback
66
+ function parseGradientFirstColor(gradientString) {
67
+ if (!gradientString || !gradientString.includes('linear-gradient')) {
68
+ return null;
69
+ }
70
+ const stopsRegex = /(rgba?\([^)]+\)|#[0-9a-fA-F]{3,8}|[a-z]+)\s+(\d+)%/i;
71
+ const match = stopsRegex.exec(gradientString);
72
+ if (match) {
73
+ return match[1].trim();
74
+ }
75
+ return null;
76
+ }
77
+ const ButtonWrapper = ({ children, style, gradientString, onPress, disabled, wrapperStyle, }) => {
78
+ const styleArray = Array.isArray(style) ? style : [style];
79
+ // On web, use CSS gradients directly
80
+ if (gradientString && isWeb) {
81
+ return (<react_native_1.TouchableOpacity style={[wrapperStyle, ...styleArray, { background: gradientString }]} onPress={onPress} disabled={disabled} activeOpacity={0.7}>
82
+ {children}
83
+ </react_native_1.TouchableOpacity>);
84
+ }
85
+ // On native, use first color from gradient as solid background
86
+ const fallbackColor = gradientString ? parseGradientFirstColor(gradientString) : null;
87
+ const finalStyle = fallbackColor
88
+ ? [wrapperStyle, ...styleArray, { backgroundColor: fallbackColor }]
89
+ : [wrapperStyle, ...styleArray];
90
+ return (<react_native_1.TouchableOpacity style={finalStyle} onPress={onPress} disabled={disabled} activeOpacity={0.7}>
91
+ {children}
92
+ </react_native_1.TouchableOpacity>);
93
+ };
94
+ function InviteFormCore({ renderIcon, renderQRCode, platformOperations, fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif', containerStyle = {}, widgetConfiguration, isEditMode = false, isDragging = false, onComponentSelect, onDrop, onSetDropTarget, onClearDropTarget, onComponentDelete, getShareableInviteLink,
95
+ // Analytics callbacks (optional - no-op for preview mode)
96
+ onShareLinkClick, onEmailFieldFocus, onEmailFieldBlur, onEmailValidation, onEmailInvitationsSubmitted, onEmailValidationError, onEmailSubmitError,
97
+ // Find Friends configuration
98
+ findFriendsConfig, createUserIdInvitation,
99
+ // Incoming/Outgoing Invitations configuration
100
+ incomingInvitationsConfig, outgoingInvitationsConfig,
101
+ // Invitation Suggestions configuration
102
+ invitationSuggestionsConfig,
103
+ // Invite Contacts configuration
104
+ inviteContactsConfig,
105
+ // Search Box configuration
106
+ searchBoxConfig,
107
+ // API configuration
108
+ apiUrl, jwt, }) {
109
+ var _a, _b, _c, _d, _e, _f, _g, _h;
110
+ // Get the form structure from widget configuration
111
+ const getFormStructure = () => {
112
+ var _a, _b, _c;
113
+ try {
114
+ const formData = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.form']) === null || _c === void 0 ? void 0 : _c.value;
115
+ if (formData && typeof formData === 'object' && formData.root) {
116
+ return formData.root;
117
+ }
118
+ }
119
+ catch (err) {
120
+ console.error('[InviteFormCore] Failed to parse form structure:', err);
121
+ }
122
+ return null;
123
+ };
124
+ const formStructure = getFormStructure();
125
+ if (!formStructure) {
126
+ console.error('[InviteFormCore] No form structure found in widget configuration. ' +
127
+ 'The widget may not have a form configured, or the configuration format is unexpected. ' +
128
+ 'Expected path: configuration.props["vortex.components.form"].value.root');
129
+ }
130
+ // Extract form title from widget configuration (mobile-specific key takes priority)
131
+ const resolvedTitle = ((_c = (_b = (_a = formStructure === null || formStructure === void 0 ? void 0 : formStructure.settings) === null || _a === void 0 ? void 0 : _a.customizations) === null || _b === void 0 ? void 0 : _b['mobile.formTitle']) === null || _c === void 0 ? void 0 : _c.textContent) ||
132
+ ((_f = (_e = (_d = formStructure === null || formStructure === void 0 ? void 0 : formStructure.settings) === null || _d === void 0 ? void 0 : _d.customizations) === null || _e === void 0 ? void 0 : _e.formTitle) === null || _f === void 0 ? void 0 : _f.textContent) ||
133
+ null;
134
+ // Extract title theme styles from root theme options
135
+ const resolvedTitleStyle = (() => {
136
+ var _a;
137
+ const themeOptions = (_a = formStructure === null || formStructure === void 0 ? void 0 : formStructure.theme) === null || _a === void 0 ? void 0 : _a.options;
138
+ if (!Array.isArray(themeOptions))
139
+ return undefined;
140
+ const getVal = (key) => { var _a; return ((_a = themeOptions.find((o) => o.key === key)) === null || _a === void 0 ? void 0 : _a.value) || undefined; };
141
+ const color = getVal('--vrtx-form-title-color');
142
+ const fontSize = getVal('--vrtx-form-title-font-size');
143
+ const fontWeight = getVal('--vrtx-form-title-font-weight');
144
+ const fontFamily = getVal('--vrtx-form-title-font-family');
145
+ if (!color && !fontSize && !fontWeight && !fontFamily)
146
+ return undefined;
147
+ return Object.assign(Object.assign(Object.assign(Object.assign({}, (color && { color })), (fontSize && { fontSize: parseFloat(fontSize) || undefined })), (fontWeight && { fontWeight })), (fontFamily && { fontFamily }));
148
+ })();
149
+ // Helper function to find email invitations block in form structure
150
+ const findEmailInvitationsBlock = () => {
151
+ if (!formStructure)
152
+ return null;
153
+ const searchChildren = (children) => {
154
+ if (!Array.isArray(children))
155
+ return null;
156
+ for (const child of children) {
157
+ if (child.type === 'block' &&
158
+ child.subtype === 'vrtx-email-invitations' &&
159
+ child.hidden !== true) {
160
+ return child;
161
+ }
162
+ if (child.children) {
163
+ const found = searchChildren(child.children);
164
+ if (found)
165
+ return found;
166
+ }
167
+ }
168
+ return null;
169
+ };
170
+ if (formStructure.children) {
171
+ return searchChildren(formStructure.children);
172
+ }
173
+ return null;
174
+ };
175
+ const emailInvitationsBlock = findEmailInvitationsBlock();
176
+ // Helper function to find submit button block in form structure
177
+ const findSubmitButtonBlock = () => {
178
+ if (!formStructure)
179
+ return null;
180
+ const searchChildren = (children) => {
181
+ if (!Array.isArray(children))
182
+ return null;
183
+ for (const child of children) {
184
+ if (child.type === 'block' && child.subtype === 'vrtx-submit') {
185
+ return child;
186
+ }
187
+ if (child.children) {
188
+ const found = searchChildren(child.children);
189
+ if (found)
190
+ return found;
191
+ }
192
+ }
193
+ return null;
194
+ };
195
+ if (formStructure.children) {
196
+ return searchChildren(formStructure.children);
197
+ }
198
+ return null;
199
+ };
200
+ const submitButtonBlock = findSubmitButtonBlock();
201
+ // Helper function to find contacts-import block in form structure
202
+ const findContactsImportBlock = () => {
203
+ if (!formStructure)
204
+ return null;
205
+ const searchChildren = (children) => {
206
+ if (!Array.isArray(children))
207
+ return null;
208
+ for (const child of children) {
209
+ if (child.type === 'block' && child.subtype === 'vrtx-contacts-import') {
210
+ return child;
211
+ }
212
+ if (child.children) {
213
+ const found = searchChildren(child.children);
214
+ if (found)
215
+ return found;
216
+ }
217
+ }
218
+ return null;
219
+ };
220
+ if (formStructure.children) {
221
+ return searchChildren(formStructure.children);
222
+ }
223
+ return null;
224
+ };
225
+ const contactsImportBlock = findContactsImportBlock();
226
+ // Helper to get customization text from contacts-import block
227
+ const getContactsCustomization = (key, defaultValue) => {
228
+ var _a, _b, _c;
229
+ const textContent = (_c = (_b = (_a = contactsImportBlock === null || contactsImportBlock === void 0 ? void 0 : contactsImportBlock.settings) === null || _a === void 0 ? void 0 : _a.customizations) === null || _b === void 0 ? void 0 : _b[key]) === null || _c === void 0 ? void 0 : _c.textContent;
230
+ if (textContent === null || textContent === undefined) {
231
+ return defaultValue;
232
+ }
233
+ return textContent;
234
+ };
235
+ // Extract styles from email invitations block for "Add by Email" button
236
+ const emailInvitationsStyle = (emailInvitationsBlock === null || emailInvitationsBlock === void 0 ? void 0 : emailInvitationsBlock.style) || {};
237
+ // Extract gradient string and fallback color
238
+ // On native, 'background' is a CSS property that doesn't work — convert solid colors to 'backgroundColor'
239
+ const rawEmailBackground = emailInvitationsStyle.background || null;
240
+ const isEmailGradient = rawEmailBackground === null || rawEmailBackground === void 0 ? void 0 : rawEmailBackground.includes('gradient');
241
+ const emailInvitationsGradientString = isEmailGradient ? rawEmailBackground : null;
242
+ const emailInvitationsFallbackColor = isEmailGradient
243
+ ? parseGradientFirstColor(rawEmailBackground)
244
+ : rawEmailBackground || emailInvitationsStyle.backgroundColor;
245
+ const emailInvitationsTextColor = emailInvitationsStyle.color || '#333';
246
+ // Helper function to check if native Contacts import is enabled
247
+ const isNativeContactsEnabled = () => {
248
+ var _a, _b, _c;
249
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components']) === null || _c === void 0 ? void 0 : _c.value)) {
250
+ return false;
251
+ }
252
+ const components = widgetConfiguration.configuration.props['vortex.components'].value;
253
+ return (Array.isArray(components) &&
254
+ components.includes('vortex.components.importcontacts.providers.importcontacts'));
255
+ };
256
+ // Helper function to check if Google Contacts import is enabled
257
+ const isGoogleContactsEnabled = () => {
258
+ var _a, _b, _c;
259
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components']) === null || _c === void 0 ? void 0 : _c.value)) {
260
+ return false;
261
+ }
262
+ const components = widgetConfiguration.configuration.props['vortex.components'].value;
263
+ return (Array.isArray(components) &&
264
+ components.includes('vortex.components.importcontacts.providers.google'));
265
+ };
266
+ // Helper function to check if Copy Link is enabled
267
+ const isCopyLinkEnabled = () => {
268
+ var _a, _b, _c;
269
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
270
+ return false;
271
+ }
272
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
273
+ return Array.isArray(shareOptions) && shareOptions.includes('copyLink');
274
+ };
275
+ // Helper function to check if Share (native share sheet) is enabled
276
+ const isShareEnabled = () => {
277
+ var _a, _b, _c;
278
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
279
+ return false;
280
+ }
281
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
282
+ return Array.isArray(shareOptions) && shareOptions.includes('nativeShareSheet');
283
+ };
284
+ // Helper function to check if Email Invitations is enabled
285
+ // Check if the form structure contains a vrtx-email-invitations block
286
+ const isEmailInvitationsEnabled = () => {
287
+ var _a, _b, _c;
288
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components']) === null || _c === void 0 ? void 0 : _c.value)) {
289
+ return false;
290
+ }
291
+ const components = widgetConfiguration.configuration.props['vortex.components'].value;
292
+ return Array.isArray(components) && components.includes('vortex.components.emailinvitations');
293
+ };
294
+ // Helper function to check if Email share is enabled
295
+ const isEmailShareEnabled = () => {
296
+ var _a, _b, _c;
297
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
298
+ return false;
299
+ }
300
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
301
+ return Array.isArray(shareOptions) && shareOptions.includes('email');
302
+ };
303
+ // Helper function to check if SMS is enabled
304
+ const isSmsEnabled = () => {
305
+ var _a, _b, _c;
306
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
307
+ return false;
308
+ }
309
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
310
+ return Array.isArray(shareOptions) && shareOptions.includes('sms');
311
+ };
312
+ // Helper function to check if X/Twitter DMs is enabled
313
+ const isTwitterDmsEnabled = () => {
314
+ var _a, _b, _c;
315
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
316
+ return false;
317
+ }
318
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
319
+ return Array.isArray(shareOptions) && shareOptions.includes('twitterDms');
320
+ };
321
+ // Helper function to check if Instagram DMs is enabled
322
+ const isInstagramDmsEnabled = () => {
323
+ var _a, _b, _c;
324
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
325
+ return false;
326
+ }
327
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
328
+ return Array.isArray(shareOptions) && shareOptions.includes('instagramDms');
329
+ };
330
+ // Helper function to check if WhatsApp is enabled
331
+ const isWhatsAppEnabled = () => {
332
+ var _a, _b, _c;
333
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
334
+ return false;
335
+ }
336
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
337
+ return Array.isArray(shareOptions) && shareOptions.includes('whatsApp');
338
+ };
339
+ // Helper function to check if Line is enabled
340
+ const isLineEnabled = () => {
341
+ var _a, _b, _c;
342
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
343
+ return false;
344
+ }
345
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
346
+ return Array.isArray(shareOptions) && shareOptions.includes('line');
347
+ };
348
+ // Helper function to check if Line LIFF is enabled
349
+ const isLineLiffEnabled = () => {
350
+ var _a, _b, _c;
351
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
352
+ return false;
353
+ }
354
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
355
+ return Array.isArray(shareOptions) && shareOptions.includes('lineLiff');
356
+ };
357
+ // Helper function to check if QR Code is enabled
358
+ const isQrCodeEnabled = () => {
359
+ var _a, _b, _c;
360
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
361
+ return false;
362
+ }
363
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
364
+ return Array.isArray(shareOptions) && shareOptions.includes('qrCode');
365
+ };
366
+ // Helper function to check if Facebook Messenger is enabled
367
+ const isFacebookMessengerEnabled = () => {
368
+ var _a, _b, _c;
369
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
370
+ return false;
371
+ }
372
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
373
+ return Array.isArray(shareOptions) && shareOptions.includes('facebookMessenger');
374
+ };
375
+ // Helper function to check if Telegram is enabled
376
+ const isTelegramEnabled = () => {
377
+ var _a, _b, _c;
378
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
379
+ return false;
380
+ }
381
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
382
+ return Array.isArray(shareOptions) && shareOptions.includes('telegram');
383
+ };
384
+ // Helper function to check if Discord is enabled
385
+ const isDiscordEnabled = () => {
386
+ var _a, _b, _c;
387
+ if (!((_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value)) {
388
+ return false;
389
+ }
390
+ const shareOptions = widgetConfiguration.configuration.props['vortex.components.share.options'].value;
391
+ return Array.isArray(shareOptions) && shareOptions.includes('discord');
392
+ };
393
+ // Helper function to get share options order from configuration
394
+ const getShareOptionsOrder = () => {
395
+ var _a, _b, _c;
396
+ const shareOptions = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.components.share.options']) === null || _c === void 0 ? void 0 : _c.value;
397
+ return Array.isArray(shareOptions) ? shareOptions : [];
398
+ };
399
+ // State for fetched contacts
400
+ const [contacts, setContacts] = (0, react_1.useState)([]);
401
+ const [loadingContacts, setLoadingContacts] = (0, react_1.useState)(false);
402
+ const [contactsFetchAttempted, setContactsFetchAttempted] = (0, react_1.useState)(false);
403
+ const [contactsError, setContactsError] = (0, react_1.useState)(null);
404
+ // State for fetched Google contacts
405
+ const [googleContacts, setGoogleContacts] = (0, react_1.useState)([]);
406
+ const [loadingGoogleContacts, setLoadingGoogleContacts] = (0, react_1.useState)(false);
407
+ const [googleContactsFetchAttempted, setGoogleContactsFetchAttempted] = (0, react_1.useState)(false);
408
+ const [googleContactsError, setGoogleContactsError] = (0, react_1.useState)(null);
409
+ // State for hover tracking in edit mode
410
+ const [hoveredComponentId, setHoveredComponentId] = (0, react_1.useState)(null);
411
+ const [selectedComponentId, setSelectedComponentId] = (0, react_1.useState)(null);
412
+ const logic = (0, useInvitationFormLogic_1.useInvitationFormLogic)(platformOperations, contacts, googleContacts, getShareableInviteLink);
413
+ // Destructure for easier access
414
+ const { view, emailInput, emails, copySuccess, shareSuccess, sendSuccess, searchQuery, invitedContactIds, invitedGoogleContactIds, googleSearchQuery, setEmailInput, setSearchQuery, setGoogleSearchQuery, loadingContactIds, loadingGoogleContactIds, loadingEmailInvite, loadingCopy, loadingShare, loadingInvitationLink, lastInvalidEmail, handleClose, handleSendInvitation, handleCopyLink, handleShare, handleEmailSubmit, handleRemoveEmail, handleSelectFromGoogle, handleSelectFromContacts, handleAddByEmail, handleShowQrCode, handleBackToMain, handleInviteContact, handleInviteGoogleContact, } = logic;
415
+ // Fetch contacts on-demand when the contacts view is opened
416
+ (0, react_1.useEffect)(() => {
417
+ // Reset fetch attempt when view changes away from contacts
418
+ if (view !== 'contacts' && contactsFetchAttempted) {
419
+ setContactsFetchAttempted(false);
420
+ setContactsError(null);
421
+ }
422
+ if (view === 'contacts' && !contactsFetchAttempted && !loadingContacts) {
423
+ setLoadingContacts(true);
424
+ setContactsFetchAttempted(true);
425
+ setContactsError(null); // Clear previous errors
426
+ platformOperations
427
+ .fetchContacts()
428
+ .then((fetchedContacts) => {
429
+ setContacts(fetchedContacts);
430
+ setContactsError(null);
431
+ })
432
+ .catch((err) => {
433
+ console.error('[Vortex] Failed to fetch contacts:', err);
434
+ setContactsError(err instanceof Error ? err : new Error(String(err)));
435
+ setContacts([]); // Clear contacts on error
436
+ })
437
+ .finally(() => setLoadingContacts(false));
438
+ }
439
+ }, [view, contactsFetchAttempted, loadingContacts]);
440
+ // Fetch Google contacts on-demand when the googleContacts view is opened
441
+ (0, react_1.useEffect)(() => {
442
+ // Reset fetch attempt when view changes away from googleContacts
443
+ if (view !== 'googleContacts' && googleContactsFetchAttempted) {
444
+ setGoogleContactsFetchAttempted(false);
445
+ setGoogleContactsError(null);
446
+ }
447
+ if (view === 'googleContacts' && !googleContactsFetchAttempted && !loadingGoogleContacts) {
448
+ setLoadingGoogleContacts(true);
449
+ setGoogleContactsFetchAttempted(true);
450
+ setGoogleContactsError(null); // Clear previous errors
451
+ platformOperations
452
+ .fetchGoogleContacts()
453
+ .then((fetchedContacts) => {
454
+ setGoogleContacts(fetchedContacts);
455
+ setGoogleContactsError(null);
456
+ })
457
+ .catch((err) => {
458
+ console.error('[Vortex] Failed to fetch Google contacts:', err);
459
+ setGoogleContactsError(err instanceof Error ? err : new Error(String(err)));
460
+ setGoogleContacts([]); // Clear contacts on error
461
+ })
462
+ .finally(() => setLoadingGoogleContacts(false));
463
+ }
464
+ }, [view, googleContactsFetchAttempted, loadingGoogleContacts]);
465
+ // Filter contacts using shared utility
466
+ const filteredContacts = (0, contactUtils_1.filterContacts)(contacts, searchQuery);
467
+ const filteredGoogleContacts = (0, contactUtils_1.filterContacts)(googleContacts, googleSearchQuery);
468
+ // Wrapper functions with haptic feedback and analytics tracking
469
+ const handleCopyLinkWithHaptics = () => __awaiter(this, void 0, void 0, function* () {
470
+ var _a;
471
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
472
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('copyLink');
473
+ yield handleCopyLink();
474
+ });
475
+ const handleShareWithHaptics = () => __awaiter(this, void 0, void 0, function* () {
476
+ var _a;
477
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
478
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaNativeShare');
479
+ yield handleShare();
480
+ });
481
+ const handleSelectFromContactsWithHaptics = () => __awaiter(this, void 0, void 0, function* () {
482
+ var _a;
483
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
484
+ handleSelectFromContacts();
485
+ });
486
+ const handleSelectFromGoogleWithHaptics = () => __awaiter(this, void 0, void 0, function* () {
487
+ var _a;
488
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
489
+ handleSelectFromGoogle();
490
+ });
491
+ const handleAddByEmailWithHaptics = () => __awaiter(this, void 0, void 0, function* () {
492
+ var _a;
493
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
494
+ handleAddByEmail();
495
+ });
496
+ const handleInviteContactWithHaptics = (contactId) => __awaiter(this, void 0, void 0, function* () {
497
+ var _a;
498
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
499
+ yield handleInviteContact(contactId);
500
+ });
501
+ const handleInviteGoogleContactWithHaptics = (contactId) => __awaiter(this, void 0, void 0, function* () {
502
+ var _a;
503
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
504
+ yield handleInviteGoogleContact(contactId);
505
+ });
506
+ const handleSendInvitationWithHaptics = () => __awaiter(this, void 0, void 0, function* () {
507
+ var _a;
508
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
509
+ yield handleSendInvitation();
510
+ });
511
+ const handleRetryContacts = () => __awaiter(this, void 0, void 0, function* () {
512
+ var _a;
513
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
514
+ // Clear the error and reset fetch attempt to trigger a new fetch
515
+ setContactsError(null);
516
+ setContactsFetchAttempted(false);
517
+ });
518
+ const handleOpenSettings = () => __awaiter(this, void 0, void 0, function* () {
519
+ var _a;
520
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
521
+ try {
522
+ yield react_native_1.Linking.openSettings();
523
+ }
524
+ catch (err) {
525
+ console.warn('[Vortex] Failed to open settings:', err);
526
+ }
527
+ });
528
+ const handleEmailShare = () => __awaiter(this, void 0, void 0, function* () {
529
+ var _a, _b;
530
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
531
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaEmail');
532
+ yield ((_b = platformOperations.shareViaEmail) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
533
+ });
534
+ const handleSmsShare = () => __awaiter(this, void 0, void 0, function* () {
535
+ var _a, _b;
536
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
537
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaSMS');
538
+ yield ((_b = platformOperations.shareViaSms) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
539
+ });
540
+ const handleTwitterShare = () => __awaiter(this, void 0, void 0, function* () {
541
+ var _a, _b;
542
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
543
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaTwitter');
544
+ yield ((_b = platformOperations.shareViaTwitter) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
545
+ });
546
+ const handleInstagramShare = () => __awaiter(this, void 0, void 0, function* () {
547
+ var _a, _b;
548
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
549
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaInstagram');
550
+ yield ((_b = platformOperations.shareViaInstagram) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
551
+ });
552
+ const handleWhatsAppShare = () => __awaiter(this, void 0, void 0, function* () {
553
+ var _a, _b;
554
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
555
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaWhatsApp');
556
+ yield ((_b = platformOperations.shareViaWhatsApp) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
557
+ });
558
+ const handleLineShare = () => __awaiter(this, void 0, void 0, function* () {
559
+ var _a, _b;
560
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
561
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaLine');
562
+ yield ((_b = platformOperations.shareViaLine) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
563
+ });
564
+ const handleLineLiffShare = () => __awaiter(this, void 0, void 0, function* () {
565
+ var _a, _b;
566
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
567
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaLineLiff');
568
+ yield ((_b = platformOperations.shareViaLineLiff) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
569
+ });
570
+ const handleFacebookMessengerShare = () => __awaiter(this, void 0, void 0, function* () {
571
+ var _a, _b;
572
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
573
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaFacebookMessenger');
574
+ yield ((_b = platformOperations.shareViaFacebookMessenger) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
575
+ });
576
+ const handleTelegramShare = () => __awaiter(this, void 0, void 0, function* () {
577
+ var _a, _b;
578
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
579
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaTelegram');
580
+ yield ((_b = platformOperations.shareViaTelegram) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
581
+ });
582
+ const handleDiscordShare = () => __awaiter(this, void 0, void 0, function* () {
583
+ var _a, _b;
584
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
585
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaDiscord');
586
+ yield ((_b = platformOperations.shareViaDiscord) === null || _b === void 0 ? void 0 : _b.call(platformOperations));
587
+ });
588
+ const handleQrCode = () => __awaiter(this, void 0, void 0, function* () {
589
+ var _a;
590
+ yield ((_a = platformOperations.triggerHaptic) === null || _a === void 0 ? void 0 : _a.call(platformOperations, 'light'));
591
+ onShareLinkClick === null || onShareLinkClick === void 0 ? void 0 : onShareLinkClick('shareViaQrCode');
592
+ handleShowQrCode();
593
+ });
594
+ // Block renderer functions - render individual components based on block type
595
+ const renderShareOptionsBlock = (block) => {
596
+ return (<VrtxShareOptions_1.VrtxShareOptions block={block} renderIcon={renderIcon} isCopyLinkEnabled={isCopyLinkEnabled} isShareEnabled={isShareEnabled} isEmailShareEnabled={isEmailShareEnabled} isSmsEnabled={isSmsEnabled} isTwitterDmsEnabled={isTwitterDmsEnabled} isInstagramDmsEnabled={isInstagramDmsEnabled} isWhatsAppEnabled={isWhatsAppEnabled} isLineEnabled={isLineEnabled} isLineLiffEnabled={isLineLiffEnabled} isQrCodeEnabled={isQrCodeEnabled} isFacebookMessengerEnabled={isFacebookMessengerEnabled} isTelegramEnabled={isTelegramEnabled} isDiscordEnabled={isDiscordEnabled} handleCopyLink={handleCopyLink} handleShare={handleShare} handleEmailShare={handleEmailShare} handleSmsShare={handleSmsShare} handleTwitterShare={handleTwitterShare} handleInstagramShare={handleInstagramShare} handleWhatsAppShare={handleWhatsAppShare} handleLineShare={handleLineShare} handleLineLiffShare={handleLineLiffShare} handleQrCode={handleQrCode} handleFacebookMessengerShare={handleFacebookMessengerShare} handleTelegramShare={handleTelegramShare} handleDiscordShare={handleDiscordShare} triggerHaptic={platformOperations.triggerHaptic} loadingCopy={loadingCopy} loadingShare={loadingShare} copySuccess={copySuccess} shareSuccess={shareSuccess} isEditMode={isEditMode} shareOptionsOrder={getShareOptionsOrder()}/>);
597
+ };
598
+ const renderContactsImportBlock = (block) => {
599
+ return (<VrtxContactsImport_1.VrtxContactsImport block={block} renderIcon={renderIcon} isNativeContactsEnabled={isNativeContactsEnabled} isGoogleContactsEnabled={isGoogleContactsEnabled} handleSelectFromContacts={handleSelectFromContacts} handleSelectFromGoogle={handleSelectFromGoogle} triggerHaptic={platformOperations.triggerHaptic} isEditMode={isEditMode}/>);
600
+ };
601
+ const renderEmailInvitationsBlock = (block) => {
602
+ // Don't pass submitButtonBlock - we'll render it separately
603
+ return (<VrtxEmailInvitations_1.VrtxEmailInvitations block={block} view={view} emails={emails} emailInput={emailInput} setEmailInput={setEmailInput} handleEmailSubmit={handleEmailSubmit} handleRemoveEmail={handleRemoveEmail} submitButtonBlock={undefined} handleSendInvitation={handleSendInvitation} triggerHaptic={platformOperations.triggerHaptic} loadingEmailInvite={loadingEmailInvite} sendSuccess={sendSuccess} lastInvalidEmail={lastInvalidEmail} EditableWrapper={EditableWrapper} onEmailFieldFocus={onEmailFieldFocus} onEmailFieldBlur={onEmailFieldBlur} handleAddByEmail={handleAddByEmail} renderIcon={renderIcon} isEditMode={isEditMode}/>);
604
+ };
605
+ const renderHeadingBlock = (block) => {
606
+ return <VrtxHeading_1.VrtxHeading block={block}/>;
607
+ };
608
+ // Stable text update handler that doesn't depend on block
609
+ const handleTextUpdate = (0, react_1.useCallback)((blockId, updates) => {
610
+ // Dispatch a custom event that PageBuilderMobile can listen to
611
+ const updateEvent = new CustomEvent('vortex-update-text', {
612
+ detail: {
613
+ blockId,
614
+ textContent: updates.textContent,
615
+ },
616
+ bubbles: true,
617
+ });
618
+ // Dispatch from document if we're on web
619
+ if (isWeb && document) {
620
+ document.dispatchEvent(updateEvent);
621
+ }
622
+ }, []); // Empty deps - this handler never needs to change
623
+ const renderTextBlock = (block) => {
624
+ return <VrtxText_1.VrtxText block={block} isEditMode={isEditMode} onUpdate={handleTextUpdate}/>;
625
+ };
626
+ const renderSelectBlock = (block) => {
627
+ return <VrtxSelect_1.VrtxSelect block={block}/>;
628
+ };
629
+ const renderSubmitBlock = (block) => {
630
+ var _a;
631
+ return (<VrtxSubmit_1.VrtxSubmit block={block} view={view} handleSendInvitation={handleSendInvitation} triggerHaptic={platformOperations.triggerHaptic} loadingEmailInvite={loadingEmailInvite} sendSuccess={sendSuccess} emailCount={emails.length} emailBlockCustomizations={(_a = emailInvitationsBlock === null || emailInvitationsBlock === void 0 ? void 0 : emailInvitationsBlock.settings) === null || _a === void 0 ? void 0 : _a.customizations} emailBlockStyle={emailInvitationsBlock === null || emailInvitationsBlock === void 0 ? void 0 : emailInvitationsBlock.style}/>);
632
+ };
633
+ const renderFindFriendsBlock = (block) => {
634
+ var _a, _b, _c, _d;
635
+ // Extract theme colors from widget configuration
636
+ const themeOptions = (_d = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.theme']) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.options;
637
+ const getThemeValue = (key) => {
638
+ const option = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.find((opt) => opt.key === key);
639
+ return (option === null || option === void 0 ? void 0 : option.value) || undefined;
640
+ };
641
+ const extractBorderColor = (borderValue) => {
642
+ if (!borderValue)
643
+ return undefined;
644
+ const parts = borderValue.trim().split(/\s+/);
645
+ if (parts.length === 3)
646
+ return parts[2];
647
+ return undefined;
648
+ };
649
+ const theme = {
650
+ primaryBackground: getThemeValue('--vrtx-submit-primary-background') ||
651
+ getThemeValue('--vrtx-button-primary-background') ||
652
+ getThemeValue('--color-primary-background'),
653
+ primaryForeground: getThemeValue('--vrtx-submit-primary-color') || getThemeValue('--color-primary-foreground'),
654
+ secondaryBackground: getThemeValue('--vrtx-submit-secondary-background') ||
655
+ getThemeValue('--vrtx-button-secondary-background') ||
656
+ getThemeValue('--color-secondary-background'),
657
+ secondaryForeground: getThemeValue('--vrtx-submit-secondary-color') ||
658
+ getThemeValue('--vrtx-button-secondary-color') ||
659
+ getThemeValue('--color-secondary-foreground'),
660
+ foreground: getThemeValue('--vrtx-root-color') || getThemeValue('--color-foreground'),
661
+ border: extractBorderColor(getThemeValue('--vrtx-root-border')) ||
662
+ extractBorderColor(getThemeValue('--vrtx-input-border')) ||
663
+ getThemeValue('--color-border'),
664
+ };
665
+ return (<VrtxFindFriends_1.VrtxFindFriends block={block} findFriendsConfig={findFriendsConfig} createUserIdInvitation={createUserIdInvitation} triggerHaptic={platformOperations.triggerHaptic} theme={theme}/>);
666
+ };
667
+ const renderIncomingInvitationsBlock = (block) => {
668
+ var _a, _b, _c, _d;
669
+ // Extract theme colors from widget configuration
670
+ const themeOptions = (_d = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.theme']) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.options;
671
+ const getThemeValue = (key) => {
672
+ const option = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.find((opt) => opt.key === key);
673
+ return (option === null || option === void 0 ? void 0 : option.value) || undefined;
674
+ };
675
+ const extractBorderColor = (borderValue) => {
676
+ if (!borderValue)
677
+ return undefined;
678
+ const parts = borderValue.trim().split(/\s+/);
679
+ if (parts.length === 3)
680
+ return parts[2];
681
+ return undefined;
682
+ };
683
+ const theme = {
684
+ primaryBackground: getThemeValue('--vrtx-submit-primary-background') ||
685
+ getThemeValue('--vrtx-button-primary-background') ||
686
+ getThemeValue('--color-primary-background'),
687
+ primaryForeground: getThemeValue('--vrtx-submit-primary-color') || getThemeValue('--color-primary-foreground'),
688
+ secondaryBackground: getThemeValue('--vrtx-submit-secondary-background') ||
689
+ getThemeValue('--vrtx-button-secondary-background') ||
690
+ getThemeValue('--color-secondary-background'),
691
+ secondaryForeground: getThemeValue('--vrtx-submit-secondary-color') ||
692
+ getThemeValue('--vrtx-button-secondary-color') ||
693
+ getThemeValue('--color-secondary-foreground'),
694
+ foreground: getThemeValue('--vrtx-root-color') || getThemeValue('--color-foreground'),
695
+ border: extractBorderColor(getThemeValue('--vrtx-root-border')) ||
696
+ extractBorderColor(getThemeValue('--vrtx-input-border')) ||
697
+ getThemeValue('--color-border'),
698
+ };
699
+ return (<VrtxIncomingInvitations_1.VrtxIncomingInvitations block={block} incomingInvitationsConfig={incomingInvitationsConfig} apiUrl={apiUrl} jwt={jwt} triggerHaptic={platformOperations.triggerHaptic} theme={theme}/>);
700
+ };
701
+ const renderOutgoingInvitationsBlock = (block) => {
702
+ var _a, _b, _c, _d;
703
+ // Extract theme colors from widget configuration
704
+ const themeOptions = (_d = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.theme']) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.options;
705
+ const getThemeValue = (key) => {
706
+ const option = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.find((opt) => opt.key === key);
707
+ return (option === null || option === void 0 ? void 0 : option.value) || undefined;
708
+ };
709
+ const extractBorderColor = (borderValue) => {
710
+ if (!borderValue)
711
+ return undefined;
712
+ const parts = borderValue.trim().split(/\s+/);
713
+ if (parts.length === 3)
714
+ return parts[2];
715
+ return undefined;
716
+ };
717
+ const theme = {
718
+ primaryBackground: getThemeValue('--vrtx-submit-primary-background') ||
719
+ getThemeValue('--vrtx-button-primary-background') ||
720
+ getThemeValue('--color-primary-background'),
721
+ primaryForeground: getThemeValue('--vrtx-submit-primary-color') || getThemeValue('--color-primary-foreground'),
722
+ secondaryBackground: getThemeValue('--vrtx-submit-secondary-background') ||
723
+ getThemeValue('--vrtx-button-secondary-background') ||
724
+ getThemeValue('--color-secondary-background'),
725
+ secondaryForeground: getThemeValue('--vrtx-submit-secondary-color') ||
726
+ getThemeValue('--vrtx-button-secondary-color') ||
727
+ getThemeValue('--color-secondary-foreground'),
728
+ foreground: getThemeValue('--vrtx-root-color') || getThemeValue('--color-foreground'),
729
+ border: extractBorderColor(getThemeValue('--vrtx-root-border')) ||
730
+ extractBorderColor(getThemeValue('--vrtx-input-border')) ||
731
+ getThemeValue('--color-border'),
732
+ };
733
+ return (<VrtxOutgoingInvitations_1.VrtxOutgoingInvitations block={block} outgoingInvitationsConfig={outgoingInvitationsConfig} apiUrl={apiUrl} jwt={jwt} triggerHaptic={platformOperations.triggerHaptic} theme={theme}/>);
734
+ };
735
+ const renderSearchBoxBlock = (block) => {
736
+ var _a, _b, _c, _d;
737
+ // Extract theme colors from widget configuration
738
+ const themeOptions = (_d = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.theme']) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.options;
739
+ const getThemeValue = (key) => {
740
+ const option = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.find((opt) => opt.key === key);
741
+ return (option === null || option === void 0 ? void 0 : option.value) || undefined;
742
+ };
743
+ const theme = {
744
+ primaryBackground: getThemeValue('--color-primary-background'),
745
+ primaryForeground: getThemeValue('--color-primary-foreground'),
746
+ secondaryBackground: getThemeValue('--color-secondary-background'),
747
+ secondaryForeground: getThemeValue('--color-secondary-foreground'),
748
+ foreground: getThemeValue('--color-foreground'),
749
+ border: getThemeValue('--color-border'),
750
+ };
751
+ return (<VrtxSearchBox_1.VrtxSearchBox block={block} searchBoxConfig={searchBoxConfig} createUserIdInvitation={createUserIdInvitation} triggerHaptic={platformOperations.triggerHaptic} renderIcon={renderIcon} theme={theme}/>);
752
+ };
753
+ const renderInvitationSuggestionsBlock = (block) => {
754
+ var _a, _b, _c, _d;
755
+ // Extract theme colors from widget configuration
756
+ const themeOptions = (_d = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.theme']) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.options;
757
+ const getThemeValue = (key) => {
758
+ const option = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.find((opt) => opt.key === key);
759
+ return (option === null || option === void 0 ? void 0 : option.value) || undefined;
760
+ };
761
+ const extractBorderColor = (borderValue) => {
762
+ if (!borderValue)
763
+ return undefined;
764
+ const parts = borderValue.trim().split(/\s+/);
765
+ if (parts.length === 3)
766
+ return parts[2];
767
+ return undefined;
768
+ };
769
+ const theme = {
770
+ primaryBackground: getThemeValue('--vrtx-submit-primary-background') ||
771
+ getThemeValue('--vrtx-button-primary-background') ||
772
+ getThemeValue('--color-primary-background'),
773
+ primaryForeground: getThemeValue('--vrtx-submit-primary-color') || getThemeValue('--color-primary-foreground'),
774
+ secondaryBackground: getThemeValue('--vrtx-submit-secondary-background') ||
775
+ getThemeValue('--vrtx-button-secondary-background') ||
776
+ getThemeValue('--color-secondary-background'),
777
+ secondaryForeground: getThemeValue('--vrtx-submit-secondary-color') ||
778
+ getThemeValue('--vrtx-button-secondary-color') ||
779
+ getThemeValue('--color-secondary-foreground'),
780
+ foreground: getThemeValue('--vrtx-root-color') || getThemeValue('--color-foreground'),
781
+ border: extractBorderColor(getThemeValue('--vrtx-root-border')) ||
782
+ extractBorderColor(getThemeValue('--vrtx-input-border')) ||
783
+ getThemeValue('--color-border'),
784
+ };
785
+ return (<VrtxInvitationSuggestions_1.VrtxInvitationSuggestions block={block} invitationSuggestionsConfig={invitationSuggestionsConfig} createUserIdInvitation={createUserIdInvitation} triggerHaptic={platformOperations.triggerHaptic} theme={theme}/>);
786
+ };
787
+ const renderInviteContactsBlock = (block) => {
788
+ var _a, _b, _c, _d, _e, _f, _g;
789
+ // Extract theme colors from widget configuration
790
+ const themeOptions = (_d = (_c = (_b = (_a = widgetConfiguration === null || widgetConfiguration === void 0 ? void 0 : widgetConfiguration.configuration) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b['vortex.theme']) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.options;
791
+ const getThemeValue = (key) => {
792
+ const option = themeOptions === null || themeOptions === void 0 ? void 0 : themeOptions.find((opt) => opt.key === key);
793
+ return (option === null || option === void 0 ? void 0 : option.value) || undefined;
794
+ };
795
+ const extractBorderColor = (borderValue) => {
796
+ if (!borderValue)
797
+ return undefined;
798
+ const parts = borderValue.trim().split(/\s+/);
799
+ if (parts.length === 3)
800
+ return parts[2];
801
+ return undefined;
802
+ };
803
+ const theme = {
804
+ primaryBackground: getThemeValue('--vrtx-submit-primary-background') ||
805
+ getThemeValue('--vrtx-button-primary-background') ||
806
+ getThemeValue('--color-primary-background'),
807
+ primaryForeground: getThemeValue('--vrtx-submit-primary-color') || getThemeValue('--color-primary-foreground'),
808
+ secondaryBackground: getThemeValue('--vrtx-submit-secondary-background') ||
809
+ getThemeValue('--vrtx-button-secondary-background') ||
810
+ getThemeValue('--color-secondary-background'),
811
+ secondaryForeground: getThemeValue('--vrtx-submit-secondary-color') ||
812
+ getThemeValue('--vrtx-button-secondary-color') ||
813
+ getThemeValue('--color-secondary-foreground'),
814
+ foreground: getThemeValue('--vrtx-root-color') || getThemeValue('--color-foreground'),
815
+ border: extractBorderColor(getThemeValue('--vrtx-root-border')) ||
816
+ extractBorderColor(getThemeValue('--vrtx-input-border')) ||
817
+ getThemeValue('--color-border'),
818
+ };
819
+ // Get SMS message template from block settings
820
+ const smsMessageTemplate = (_g = (_f = (_e = block === null || block === void 0 ? void 0 : block.settings) === null || _e === void 0 ? void 0 : _e.customizations) === null || _f === void 0 ? void 0 : _f.smsMessage) === null || _g === void 0 ? void 0 : _g.textContent;
821
+ // Create SMS invitation function that calls the API
822
+ const createSmsInvitation = (phoneNumber, contactName) => __awaiter(this, void 0, void 0, function* () {
823
+ try {
824
+ if (platformOperations.createSmsInvitation) {
825
+ return yield platformOperations.createSmsInvitation(phoneNumber, contactName);
826
+ }
827
+ console.warn('[VrtxInviteContacts] No createSmsInvitation function provided');
828
+ return null;
829
+ }
830
+ catch (err) {
831
+ console.error('[VrtxInviteContacts] Failed to create SMS invitation:', err);
832
+ return null;
833
+ }
834
+ });
835
+ return (<VrtxInviteContacts_1.VrtxInviteContacts block={block} inviteContactsConfig={inviteContactsConfig} createSmsInvitation={createSmsInvitation} triggerHaptic={platformOperations.triggerHaptic} theme={theme} smsMessageTemplate={smsMessageTemplate}/>);
836
+ };
837
+ const renderBlock = (block) => {
838
+ if (!block)
839
+ return null;
840
+ // Skip rendering if block is hidden
841
+ if (block.hidden === true) {
842
+ return null;
843
+ }
844
+ const content = (() => {
845
+ switch (block.subtype) {
846
+ case 'vrtx-share-options':
847
+ return renderShareOptionsBlock(block);
848
+ case 'vrtx-contacts-import':
849
+ return renderContactsImportBlock(block);
850
+ case 'vrtx-email-invitations':
851
+ return renderEmailInvitationsBlock(block);
852
+ case 'vrtx-find-friends':
853
+ return renderFindFriendsBlock(block);
854
+ case 'vrtx-incoming-invitations':
855
+ return renderIncomingInvitationsBlock(block);
856
+ case 'vrtx-outgoing-invitations':
857
+ return renderOutgoingInvitationsBlock(block);
858
+ case 'vrtx-invitation-suggestions':
859
+ return renderInvitationSuggestionsBlock(block);
860
+ case 'vrtx-invite-contacts':
861
+ return renderInviteContactsBlock(block);
862
+ case 'vrtx-search-box':
863
+ return renderSearchBoxBlock(block);
864
+ case 'vrtx-heading':
865
+ return renderHeadingBlock(block);
866
+ case 'vrtx-text':
867
+ return renderTextBlock(block);
868
+ case 'vrtx-select':
869
+ return null; //renderSelectBlock(block);
870
+ case 'vrtx-submit':
871
+ return renderSubmitBlock(block);
872
+ default:
873
+ console.warn(`here [InvitationFormCore] Unknown block type: ${block.subtype}`);
874
+ return null;
875
+ }
876
+ })();
877
+ if (!content)
878
+ return null;
879
+ // Wrap in EditableWrapper for edit mode
880
+ return (<EditableWrapper key={block.id} componentId={block.id} componentType={block.type} node={block}>
881
+ {content}
882
+ </EditableWrapper>);
883
+ };
884
+ const renderColumn = (column, filterGroup, excludeGroups) => {
885
+ if (!column || !column.children)
886
+ return null;
887
+ // If filtering by include group, check if this column has any matching blocks
888
+ if (filterGroup) {
889
+ const hasMatchingBlocks = column.children.some((child) => {
890
+ var _a, _b, _c;
891
+ if (child.type === 'block') {
892
+ const blockGroup = (_c = (_b = (_a = child.meta) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.group) === null || _c === void 0 ? void 0 : _c.name;
893
+ return blockGroup === filterGroup;
894
+ }
895
+ return false;
896
+ });
897
+ // Skip rendering this column if it has no matching blocks
898
+ if (!hasMatchingBlocks) {
899
+ return null;
900
+ }
901
+ }
902
+ // If excluding groups, check if this column has any blocks NOT in excluded groups
903
+ if (excludeGroups && excludeGroups.length > 0) {
904
+ const hasNonExcludedBlocks = column.children.some((child) => {
905
+ var _a, _b, _c;
906
+ if (child.type === 'block') {
907
+ const blockGroup = (_c = (_b = (_a = child.meta) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.group) === null || _c === void 0 ? void 0 : _c.name;
908
+ return !excludeGroups.includes(blockGroup);
909
+ }
910
+ return false;
911
+ });
912
+ // Skip rendering this column if all its blocks are excluded
913
+ if (!hasNonExcludedBlocks) {
914
+ return null;
915
+ }
916
+ }
917
+ return (<EditableWrapper key={column.id} componentId={column.id} componentType={column.type} node={column}>
918
+ <react_native_1.View style={{ flex: 1 }}>
919
+ {column.children.map((child) => {
920
+ var _a, _b, _c, _d, _e, _f;
921
+ if (child.type === 'block') {
922
+ // Skip submit button blocks - they're rendered after email invitations
923
+ if (child.subtype === 'vrtx-submit') {
924
+ return null;
925
+ }
926
+ // If filterGroup is provided, only render blocks from that group
927
+ if (filterGroup) {
928
+ const blockGroup = (_c = (_b = (_a = child.meta) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.group) === null || _c === void 0 ? void 0 : _c.name;
929
+ if (blockGroup !== filterGroup) {
930
+ return null;
931
+ }
932
+ }
933
+ // If excludeGroups is provided, skip blocks from those groups
934
+ if (excludeGroups && excludeGroups.length > 0) {
935
+ const blockGroup = (_f = (_e = (_d = child.meta) === null || _d === void 0 ? void 0 : _d.source) === null || _e === void 0 ? void 0 : _e.group) === null || _f === void 0 ? void 0 : _f.name;
936
+ if (excludeGroups.includes(blockGroup)) {
937
+ return null;
938
+ }
939
+ }
940
+ // Special handling for email invitations block - render submit button separately
941
+ if (child.subtype === 'vrtx-email-invitations' && submitButtonBlock) {
942
+ return (<react_1.default.Fragment key={child.id}>
943
+ {renderBlock(child)}
944
+ {renderBlock(submitButtonBlock)}
945
+ </react_1.default.Fragment>);
946
+ }
947
+ return renderBlock(child);
948
+ }
949
+ return null;
950
+ })}
951
+ </react_native_1.View>
952
+ </EditableWrapper>);
953
+ };
954
+ const renderRow = (row, index, totalRows, filterGroup, excludeGroups) => {
955
+ var _a, _b, _c, _d;
956
+ if (!row)
957
+ return null;
958
+ // Check if row has any visible content (columns with blocks)
959
+ const hasVisibleContent = (_a = row.children) === null || _a === void 0 ? void 0 : _a.some((child) => {
960
+ if (child.type === 'column' && child.children) {
961
+ return child.children.some((blockChild) => blockChild.type === 'block');
962
+ }
963
+ return false;
964
+ });
965
+ // In non-edit mode, skip rows without children entirely
966
+ if (!row.children && !isEditMode)
967
+ return null;
968
+ // If filtering by include group, check if this row has any columns with matching blocks
969
+ if (filterGroup) {
970
+ const hasMatchingContent = (_b = row.children) === null || _b === void 0 ? void 0 : _b.some((child) => {
971
+ if (child.type === 'column' && child.children) {
972
+ return child.children.some((blockChild) => {
973
+ var _a, _b, _c;
974
+ if (blockChild.type === 'block') {
975
+ const blockGroup = (_c = (_b = (_a = blockChild.meta) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.group) === null || _c === void 0 ? void 0 : _c.name;
976
+ return blockGroup === filterGroup;
977
+ }
978
+ return false;
979
+ });
980
+ }
981
+ return false;
982
+ });
983
+ // Skip rendering this row if it has no matching content
984
+ if (!hasMatchingContent) {
985
+ return null;
986
+ }
987
+ }
988
+ // If excluding groups, check if this row has any columns with non-excluded blocks
989
+ if (excludeGroups && excludeGroups.length > 0) {
990
+ const hasNonExcludedContent = (_c = row.children) === null || _c === void 0 ? void 0 : _c.some((child) => {
991
+ if (child.type === 'column' && child.children) {
992
+ return child.children.some((blockChild) => {
993
+ var _a, _b, _c;
994
+ if (blockChild.type === 'block') {
995
+ const blockGroup = (_c = (_b = (_a = blockChild.meta) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.group) === null || _c === void 0 ? void 0 : _c.name;
996
+ return !excludeGroups.includes(blockGroup);
997
+ }
998
+ return false;
999
+ });
1000
+ }
1001
+ return false;
1002
+ });
1003
+ // Skip rendering this row if all its blocks are excluded
1004
+ // BUT in edit mode, allow empty rows through so they can be selected
1005
+ if (!hasNonExcludedContent && !(isEditMode && !hasVisibleContent)) {
1006
+ return null;
1007
+ }
1008
+ }
1009
+ // Determine if this is an empty row (no visible content)
1010
+ const isEmptyRow = !hasVisibleContent;
1011
+ return (<react_1.default.Fragment key={row.id}>
1012
+ {/* Drop zone before this row */}
1013
+ {isEditMode && isDragging && (<react_native_1.View
1014
+ // @ts-ignore
1015
+ data-drop-zone="between-rows" data-insertion-index={index} style={{
1016
+ height: 40,
1017
+ // borderWidth: 2,
1018
+ // borderColor: '#4CAF50',
1019
+ // borderStyle: 'dashed',
1020
+ // borderRadius: 4,
1021
+ // backgroundColor: 'rgba(76, 175, 80, 0.1)',
1022
+ marginVertical: 8,
1023
+ alignItems: 'center',
1024
+ justifyContent: 'center',
1025
+ }}>
1026
+ <react_native_1.Text style={{ color: '#4CAF50', fontSize: 12, fontWeight: '600' }}>
1027
+ {/* Drop here to insert at position {index} */}
1028
+ </react_native_1.Text>
1029
+ </react_native_1.View>)}
1030
+
1031
+ {/* The actual row */}
1032
+ <EditableWrapper componentId={row.id} componentType={row.type} node={row}>
1033
+ <react_native_1.View style={[
1034
+ styles.section,
1035
+ // In edit mode, empty rows get a minimum height so they can be selected
1036
+ isEditMode && isEmptyRow && styles.emptyRowEditMode,
1037
+ ]}>
1038
+ {(_d = row.children) === null || _d === void 0 ? void 0 : _d.map((child) => {
1039
+ if (child.type === 'column') {
1040
+ return renderColumn(child, filterGroup, excludeGroups);
1041
+ }
1042
+ return null;
1043
+ })}
1044
+ </react_native_1.View>
1045
+ </EditableWrapper>
1046
+
1047
+ {/* Drop zone after last row */}
1048
+ {isEditMode && isDragging && index === totalRows - 1 && (<react_native_1.View
1049
+ // @ts-ignore
1050
+ data-drop-zone="between-rows" data-insertion-index={totalRows} style={{
1051
+ height: 40,
1052
+ borderWidth: 2,
1053
+ borderColor: '#4CAF50',
1054
+ borderStyle: 'dashed',
1055
+ borderRadius: 4,
1056
+ backgroundColor: 'rgba(76, 175, 80, 0.1)',
1057
+ marginVertical: 8,
1058
+ alignItems: 'center',
1059
+ justifyContent: 'center',
1060
+ }}>
1061
+ <react_native_1.Text style={{ color: '#4CAF50', fontSize: 12, fontWeight: '600' }}>
1062
+ Drop here to insert at position {totalRows}
1063
+ </react_native_1.Text>
1064
+ </react_native_1.View>)}
1065
+ </react_1.default.Fragment>);
1066
+ };
1067
+ // Helper function to get component label
1068
+ const getComponentLabel = (type) => {
1069
+ const labelMap = {
1070
+ 'vrtx-share-options': 'Share Options',
1071
+ 'vrtx-contacts-import': 'Contacts Import',
1072
+ 'vrtx-email-invitations': 'Email Invitations',
1073
+ 'vrtx-find-friends': 'Find Friends',
1074
+ 'vrtx-incoming-invitations': 'Incoming Invitations',
1075
+ 'vrtx-outgoing-invitations': 'Outgoing Invitations',
1076
+ 'vrtx-invitation-suggestions': 'Invitation Suggestions',
1077
+ 'vrtx-heading': 'Heading',
1078
+ 'vrtx-text': 'Text',
1079
+ 'vrtx-select': 'Select',
1080
+ 'vrtx-submit': 'Submit',
1081
+ 'vrtx-form-label': 'Label',
1082
+ 'vrtx-row': 'Row',
1083
+ row: 'Row',
1084
+ column: 'Column',
1085
+ block: 'Block',
1086
+ };
1087
+ return labelMap[type] || type;
1088
+ };
1089
+ // EditableWrapper component for hover highlighting and drag-drop in edit mode
1090
+ // IMPORTANT: Memoized via useMemo to maintain stable component identity across re-renders.
1091
+ // Without this, every parent state change (e.g., typing in email input) would create a new
1092
+ // component type, causing React to unmount/remount all children — which blurs TextInputs.
1093
+ const EditableWrapper = react_1.default.useMemo(() => {
1094
+ const Wrapper = ({ children, componentId, componentType, node, flex, }) => {
1095
+ const wrapperRef = react_1.default.useRef(null);
1096
+ const labelRef = react_1.default.useRef(null);
1097
+ const leftMarginRef = react_1.default.useRef(null);
1098
+ const rightMarginRef = react_1.default.useRef(null);
1099
+ const outlineRef = react_1.default.useRef(null);
1100
+ // For rows on web, allow margin-based hover/selection
1101
+ const isRow = componentType === 'row';
1102
+ const isColumn = componentType === 'column';
1103
+ const isBlock = !isRow && !isColumn;
1104
+ // State for row margin hover
1105
+ const [isRowMarginHovered, setIsRowMarginHovered] = react_1.default.useState(false);
1106
+ // Determine hover and selection states
1107
+ const isHovered = isBlock
1108
+ ? hoveredComponentId === componentId
1109
+ : isRow && isWeb
1110
+ ? isRowMarginHovered
1111
+ : false;
1112
+ const isSelected = isBlock
1113
+ ? selectedComponentId === componentId
1114
+ : isRow && isWeb
1115
+ ? selectedComponentId === componentId
1116
+ : false;
1117
+ const showLabel = isEditMode && (isHovered || isSelected);
1118
+ // Create margin detection boxes for rows on web
1119
+ react_1.default.useEffect(() => {
1120
+ if (!isWeb || !isRow || !isEditMode) {
1121
+ // Clean up margin detectors if they exist
1122
+ if (leftMarginRef.current && leftMarginRef.current.parentNode) {
1123
+ leftMarginRef.current.parentNode.removeChild(leftMarginRef.current);
1124
+ leftMarginRef.current = null;
1125
+ }
1126
+ if (rightMarginRef.current && rightMarginRef.current.parentNode) {
1127
+ rightMarginRef.current.parentNode.removeChild(rightMarginRef.current);
1128
+ rightMarginRef.current = null;
1129
+ }
1130
+ if (outlineRef.current && outlineRef.current.parentNode) {
1131
+ outlineRef.current.parentNode.removeChild(outlineRef.current);
1132
+ outlineRef.current = null;
1133
+ }
1134
+ return;
1135
+ }
1136
+ if (!wrapperRef.current)
1137
+ return;
1138
+ // Find the outermost container with padding - this creates the margin areas
1139
+ // Walk up the DOM tree until we find a container that's significantly wider than the row
1140
+ let scrollContainer = wrapperRef.current.parentElement;
1141
+ const rowWidth = wrapperRef.current.getBoundingClientRect().width;
1142
+ let attempts = 0;
1143
+ while (scrollContainer && attempts < 15) {
1144
+ const containerWidth = scrollContainer.getBoundingClientRect().width;
1145
+ // If this container is significantly wider than the row (has margins/padding)
1146
+ if (containerWidth > rowWidth + 20) {
1147
+ break;
1148
+ }
1149
+ scrollContainer = scrollContainer.parentElement;
1150
+ attempts++;
1151
+ }
1152
+ // Fallback: use the widest ancestor we can find
1153
+ if (!scrollContainer || scrollContainer.getBoundingClientRect().width <= rowWidth) {
1154
+ scrollContainer = wrapperRef.current.parentElement;
1155
+ while (scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.parentElement) {
1156
+ const parent = scrollContainer.parentElement;
1157
+ if (parent.getBoundingClientRect().width > scrollContainer.getBoundingClientRect().width) {
1158
+ scrollContainer = parent;
1159
+ }
1160
+ else {
1161
+ break;
1162
+ }
1163
+ }
1164
+ }
1165
+ if (!scrollContainer)
1166
+ return;
1167
+ // Create margin detectors and outline if they don't exist
1168
+ if (!leftMarginRef.current) {
1169
+ leftMarginRef.current = document.createElement('div');
1170
+ document.body.appendChild(leftMarginRef.current);
1171
+ }
1172
+ if (!rightMarginRef.current) {
1173
+ rightMarginRef.current = document.createElement('div');
1174
+ document.body.appendChild(rightMarginRef.current);
1175
+ }
1176
+ if (!outlineRef.current) {
1177
+ outlineRef.current = document.createElement('div');
1178
+ document.body.appendChild(outlineRef.current);
1179
+ }
1180
+ const updateMarginDetectors = () => {
1181
+ if (!wrapperRef.current || !scrollContainer)
1182
+ return;
1183
+ const rowRect = wrapperRef.current.getBoundingClientRect();
1184
+ const containerRect = scrollContainer.getBoundingClientRect();
1185
+ // Update outline box (full width)
1186
+ if (outlineRef.current) {
1187
+ Object.assign(outlineRef.current.style, {
1188
+ position: 'fixed',
1189
+ top: `${rowRect.top}px`,
1190
+ left: `${containerRect.left}px`,
1191
+ width: `${containerRect.width}px`,
1192
+ height: `${rowRect.height}px`,
1193
+ outline: isRowMarginHovered || isSelected
1194
+ ? `3px solid ${isSelected ? '#1166c2' : '#72b3f3'}`
1195
+ : 'none',
1196
+ outlineOffset: '0px',
1197
+ borderRadius: '8px',
1198
+ pointerEvents: 'none',
1199
+ zIndex: '1199',
1200
+ });
1201
+ }
1202
+ // Update left margin detector
1203
+ if (leftMarginRef.current) {
1204
+ const leftWidth = rowRect.left - containerRect.left;
1205
+ Object.assign(leftMarginRef.current.style, {
1206
+ position: 'fixed',
1207
+ top: `${rowRect.top}px`,
1208
+ left: `${containerRect.left}px`,
1209
+ width: `${leftWidth}px`,
1210
+ height: `${rowRect.height}px`,
1211
+ cursor: 'pointer',
1212
+ pointerEvents: 'auto',
1213
+ zIndex: '1199',
1214
+ });
1215
+ }
1216
+ // Update right margin detector
1217
+ if (rightMarginRef.current) {
1218
+ const rightWidth = containerRect.right - rowRect.right;
1219
+ Object.assign(rightMarginRef.current.style, {
1220
+ position: 'fixed',
1221
+ top: `${rowRect.top}px`,
1222
+ left: `${rowRect.right}px`,
1223
+ width: `${rightWidth}px`,
1224
+ height: `${rowRect.height}px`,
1225
+ cursor: 'pointer',
1226
+ pointerEvents: 'auto',
1227
+ zIndex: '1199',
1228
+ });
1229
+ }
1230
+ };
1231
+ // Set up event handlers for margin detectors
1232
+ const handleMarginEnter = () => {
1233
+ setIsRowMarginHovered(true);
1234
+ };
1235
+ const handleMarginLeave = () => {
1236
+ setIsRowMarginHovered(false);
1237
+ };
1238
+ const handleMarginClick = (e) => {
1239
+ e.stopPropagation();
1240
+ setSelectedComponentId(componentId);
1241
+ if (onComponentSelect) {
1242
+ onComponentSelect({
1243
+ id: componentId,
1244
+ type: componentType,
1245
+ element: node || null,
1246
+ styles: {},
1247
+ });
1248
+ }
1249
+ };
1250
+ leftMarginRef.current.addEventListener('mouseenter', handleMarginEnter);
1251
+ leftMarginRef.current.addEventListener('mouseleave', handleMarginLeave);
1252
+ leftMarginRef.current.addEventListener('click', handleMarginClick);
1253
+ rightMarginRef.current.addEventListener('mouseenter', handleMarginEnter);
1254
+ rightMarginRef.current.addEventListener('mouseleave', handleMarginLeave);
1255
+ rightMarginRef.current.addEventListener('click', handleMarginClick);
1256
+ updateMarginDetectors();
1257
+ window.addEventListener('scroll', updateMarginDetectors, true);
1258
+ window.addEventListener('resize', updateMarginDetectors);
1259
+ return () => {
1260
+ window.removeEventListener('scroll', updateMarginDetectors, true);
1261
+ window.removeEventListener('resize', updateMarginDetectors);
1262
+ if (leftMarginRef.current) {
1263
+ leftMarginRef.current.removeEventListener('mouseenter', handleMarginEnter);
1264
+ leftMarginRef.current.removeEventListener('mouseleave', handleMarginLeave);
1265
+ leftMarginRef.current.removeEventListener('click', handleMarginClick);
1266
+ if (leftMarginRef.current.parentNode) {
1267
+ leftMarginRef.current.parentNode.removeChild(leftMarginRef.current);
1268
+ }
1269
+ leftMarginRef.current = null;
1270
+ }
1271
+ if (rightMarginRef.current) {
1272
+ rightMarginRef.current.removeEventListener('mouseenter', handleMarginEnter);
1273
+ rightMarginRef.current.removeEventListener('mouseleave', handleMarginLeave);
1274
+ rightMarginRef.current.removeEventListener('click', handleMarginClick);
1275
+ if (rightMarginRef.current.parentNode) {
1276
+ rightMarginRef.current.parentNode.removeChild(rightMarginRef.current);
1277
+ }
1278
+ rightMarginRef.current = null;
1279
+ }
1280
+ if (outlineRef.current && outlineRef.current.parentNode) {
1281
+ outlineRef.current.parentNode.removeChild(outlineRef.current);
1282
+ outlineRef.current = null;
1283
+ }
1284
+ };
1285
+ }, [
1286
+ isWeb,
1287
+ isRow,
1288
+ isEditMode,
1289
+ isRowMarginHovered,
1290
+ isSelected,
1291
+ componentId,
1292
+ componentType,
1293
+ node,
1294
+ onComponentSelect,
1295
+ ]);
1296
+ // Create and manage a portal-like label element
1297
+ react_1.default.useEffect(() => {
1298
+ if (!isWeb || !showLabel) {
1299
+ // Clean up label if it exists
1300
+ if (labelRef.current && labelRef.current.parentNode) {
1301
+ labelRef.current.parentNode.removeChild(labelRef.current);
1302
+ labelRef.current = null;
1303
+ }
1304
+ return;
1305
+ }
1306
+ if (!wrapperRef.current)
1307
+ return;
1308
+ // Find the container using the same logic as margin detectors
1309
+ let scrollContainer = null;
1310
+ if (isRow) {
1311
+ // For rows, find the outermost container with padding
1312
+ scrollContainer = wrapperRef.current.parentElement;
1313
+ const rowWidth = wrapperRef.current.getBoundingClientRect().width;
1314
+ let attempts = 0;
1315
+ while (scrollContainer && attempts < 15) {
1316
+ const containerWidth = scrollContainer.getBoundingClientRect().width;
1317
+ if (containerWidth > rowWidth + 20) {
1318
+ break;
1319
+ }
1320
+ scrollContainer = scrollContainer.parentElement;
1321
+ attempts++;
1322
+ }
1323
+ if (!scrollContainer || scrollContainer.getBoundingClientRect().width <= rowWidth) {
1324
+ scrollContainer = wrapperRef.current.parentElement;
1325
+ while (scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.parentElement) {
1326
+ const parent = scrollContainer.parentElement;
1327
+ if (parent.getBoundingClientRect().width > scrollContainer.getBoundingClientRect().width) {
1328
+ scrollContainer = parent;
1329
+ }
1330
+ else {
1331
+ break;
1332
+ }
1333
+ }
1334
+ }
1335
+ }
1336
+ // Create label element if it doesn't exist
1337
+ if (!labelRef.current) {
1338
+ labelRef.current = document.createElement('div');
1339
+ document.body.appendChild(labelRef.current);
1340
+ }
1341
+ const updateLabelPosition = () => {
1342
+ if (!wrapperRef.current || !labelRef.current)
1343
+ return;
1344
+ const rect = wrapperRef.current.getBoundingClientRect();
1345
+ const label = labelRef.current;
1346
+ // For rows on web, position at extreme left of container
1347
+ let leftPos = rect.left + 5;
1348
+ if (isRow && scrollContainer) {
1349
+ const containerRect = scrollContainer.getBoundingClientRect();
1350
+ leftPos = containerRect.left;
1351
+ }
1352
+ // Update styles
1353
+ Object.assign(label.style, {
1354
+ position: 'fixed',
1355
+ left: `${leftPos}px`,
1356
+ top: `${rect.top - 25}px`,
1357
+ height: '25px',
1358
+ display: 'flex',
1359
+ alignItems: 'center',
1360
+ backgroundColor: isSelected ? '#1166c2' : '#72b3f3',
1361
+ color: 'white',
1362
+ padding: '0 12px',
1363
+ fontSize: '11px',
1364
+ fontWeight: '600',
1365
+ borderRadius: '2px 2px 0 0',
1366
+ whiteSpace: 'nowrap',
1367
+ zIndex: '1200',
1368
+ pointerEvents: 'none',
1369
+ userSelect: 'none',
1370
+ boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.3)',
1371
+ });
1372
+ label.textContent = getComponentLabel((node === null || node === void 0 ? void 0 : node.subtype) || componentType);
1373
+ };
1374
+ updateLabelPosition();
1375
+ window.addEventListener('scroll', updateLabelPosition, true);
1376
+ window.addEventListener('resize', updateLabelPosition);
1377
+ return () => {
1378
+ window.removeEventListener('scroll', updateLabelPosition, true);
1379
+ window.removeEventListener('resize', updateLabelPosition);
1380
+ if (labelRef.current && labelRef.current.parentNode) {
1381
+ labelRef.current.parentNode.removeChild(labelRef.current);
1382
+ labelRef.current = null;
1383
+ }
1384
+ };
1385
+ }, [showLabel, isSelected, node, componentType, isWeb, isRow, isEditMode]);
1386
+ // Use the toolbar hook to manage the delete button
1387
+ (0, PlacedItemToolbar_1.usePlacedItemToolbar)({
1388
+ wrapperRef,
1389
+ isSelected,
1390
+ componentId,
1391
+ componentType,
1392
+ isRow,
1393
+ nodeSubtype: node === null || node === void 0 ? void 0 : node.subtype,
1394
+ });
1395
+ if (!isEditMode)
1396
+ return <>{children}</>;
1397
+ // Helper function to check if element is inside a contentEditable element
1398
+ const isInsideContentEditable = (target) => {
1399
+ var _a, _b;
1400
+ if (!target)
1401
+ return false;
1402
+ let el = target;
1403
+ let depth = 0;
1404
+ while (el && depth < 20) {
1405
+ if (((_a = el.getAttribute) === null || _a === void 0 ? void 0 : _a.call(el, 'data-slate-editor')) === 'true') {
1406
+ return true;
1407
+ }
1408
+ if (el.contentEditable === 'true' || ((_b = el.getAttribute) === null || _b === void 0 ? void 0 : _b.call(el, 'contenteditable')) === 'true') {
1409
+ return true;
1410
+ }
1411
+ el = el.parentElement;
1412
+ depth++;
1413
+ }
1414
+ return false;
1415
+ };
1416
+ const handleClick = (e) => {
1417
+ var _a, _b, _c, _d, _e;
1418
+ // Don't handle clicks on columns - let them pass through to child blocks
1419
+ // Rows are allowed so empty rows can be selected and deleted
1420
+ if (isColumn) {
1421
+ return;
1422
+ }
1423
+ const target = (e === null || e === void 0 ? void 0 : e.target) || ((_a = e === null || e === void 0 ? void 0 : e.nativeEvent) === null || _a === void 0 ? void 0 : _a.target);
1424
+ // Check if the click is inside a contentEditable element
1425
+ if (isInsideContentEditable(target)) {
1426
+ // If the component is already selected, allow the click to proceed for text editing
1427
+ if (isSelected) {
1428
+ console.log('[EditableWrapper] Allowing click inside contentEditable element (already selected)');
1429
+ (_b = e === null || e === void 0 ? void 0 : e.stopPropagation) === null || _b === void 0 ? void 0 : _b.call(e);
1430
+ return;
1431
+ }
1432
+ // If not selected, we'll select it first (don't return early)
1433
+ console.log('[EditableWrapper] Selecting component with contentEditable element');
1434
+ }
1435
+ if (target) {
1436
+ let el = target;
1437
+ let depth = 0;
1438
+ while (el && depth < 20) {
1439
+ // Check for circle button attribute
1440
+ if (((_c = el.getAttribute) === null || _c === void 0 ? void 0 : _c.call(el, 'data-circle-button')) === 'true') {
1441
+ console.log('[EditableWrapper] Ignoring circle button click - found data attribute');
1442
+ return;
1443
+ }
1444
+ el = el.parentElement;
1445
+ depth++;
1446
+ }
1447
+ }
1448
+ // Ignore clicks from circle button (legacy flag check)
1449
+ if ((e === null || e === void 0 ? void 0 : e._circleButtonClick) || ((_d = e === null || e === void 0 ? void 0 : e.nativeEvent) === null || _d === void 0 ? void 0 : _d._circleButtonClick)) {
1450
+ console.log('[EditableWrapper] Ignoring circle button click - found flag');
1451
+ return;
1452
+ }
1453
+ // Only handle once - prevent double firing from both capture and bubble
1454
+ if (e === null || e === void 0 ? void 0 : e._editable_handled)
1455
+ return;
1456
+ if (e)
1457
+ e._editable_handled = true;
1458
+ (_e = e === null || e === void 0 ? void 0 : e.stopPropagation) === null || _e === void 0 ? void 0 : _e.call(e);
1459
+ console.log('[EditableWrapper] Clicked:', componentId, componentType, 'onComponentSelect exists:', !!onComponentSelect);
1460
+ setSelectedComponentId(componentId);
1461
+ if (onComponentSelect) {
1462
+ console.log('[EditableWrapper] Calling onComponentSelect with:', {
1463
+ id: componentId,
1464
+ type: componentType,
1465
+ element: node || null,
1466
+ });
1467
+ onComponentSelect({
1468
+ id: componentId,
1469
+ type: componentType,
1470
+ element: node || null,
1471
+ styles: {},
1472
+ });
1473
+ }
1474
+ else {
1475
+ console.warn('[EditableWrapper] onComponentSelect is not defined!');
1476
+ }
1477
+ };
1478
+ return (<div ref={wrapperRef} data-component-id={componentId} data-component-type={componentType} style={Object.assign({ position: 'relative' }, (flex && { flex: 1 }))} onMouseEnter={isColumn
1479
+ ? undefined
1480
+ : isColumn
1481
+ ? undefined
1482
+ : (e) => {
1483
+ if (!isInsideContentEditable(e.target)) {
1484
+ setHoveredComponentId(componentId);
1485
+ }
1486
+ }} onMouseLeave={isColumn
1487
+ ? undefined
1488
+ : isColumn
1489
+ ? undefined
1490
+ : (e) => {
1491
+ if (!isInsideContentEditable(e.target)) {
1492
+ setHoveredComponentId(null);
1493
+ }
1494
+ }} onClick={handleClick}>
1495
+ {children}
1496
+ {/* Selection border - only for blocks, not rows (rows use full-width outline) */}
1497
+ {showLabel && !isRow && (<>
1498
+ <div style={{
1499
+ position: 'absolute',
1500
+ top: 0,
1501
+ left: 0,
1502
+ right: 0,
1503
+ bottom: 0,
1504
+ border: `3px solid ${isSelected ? '#1166c2' : '#72b3f3'}`,
1505
+ borderRadius: '8px',
1506
+ pointerEvents: 'none',
1507
+ zIndex: 1,
1508
+ }}/>
1509
+ </>)}
1510
+ </div>);
1511
+ };
1512
+ return Wrapper;
1513
+ }, [isEditMode, hoveredComponentId, selectedComponentId, onComponentSelect, onComponentDelete]);
1514
+ const styles = createStyles(fontFamily);
1515
+ const handleHeaderButtonPress = () => {
1516
+ if (view === 'main') {
1517
+ handleClose();
1518
+ }
1519
+ else {
1520
+ handleBackToMain();
1521
+ }
1522
+ };
1523
+ // Deselect when clicking on empty space (web only)
1524
+ react_1.default.useEffect(() => {
1525
+ if (!isEditMode || !isWeb)
1526
+ return;
1527
+ const handleDocumentClick = (e) => {
1528
+ let el = e.target;
1529
+ while (el) {
1530
+ // If the click is inside an editable element, do nothing
1531
+ if (el.getAttribute) {
1532
+ if (el.getAttribute('data-component-id') ||
1533
+ el.getAttribute('data-circle-button') === 'true') {
1534
+ return;
1535
+ }
1536
+ }
1537
+ el = el.parentElement;
1538
+ }
1539
+ // Click was on empty space, deselect
1540
+ setSelectedComponentId(null);
1541
+ };
1542
+ document.addEventListener('click', handleDocumentClick, true);
1543
+ return () => {
1544
+ document.removeEventListener('click', handleDocumentClick, true);
1545
+ };
1546
+ }, [isEditMode]);
1547
+ // Handle component deletion (web only)
1548
+ react_1.default.useEffect(() => {
1549
+ if (!isWeb || !isEditMode)
1550
+ return;
1551
+ const handleDeleteEvent = (e) => {
1552
+ const customEvent = e;
1553
+ const { id, type } = customEvent.detail;
1554
+ if (onComponentDelete) {
1555
+ onComponentDelete(id, type);
1556
+ }
1557
+ // Also deselect the component
1558
+ setSelectedComponentId(null);
1559
+ };
1560
+ document.addEventListener('vortex-delete-component', handleDeleteEvent, true);
1561
+ return () => {
1562
+ document.removeEventListener('vortex-delete-component', handleDeleteEvent, true);
1563
+ };
1564
+ }, [isEditMode, onComponentDelete]);
1565
+ // Extract root form styles from formStructure
1566
+ // Transform CSS properties to React Native equivalents (e.g., 'background' -> 'backgroundColor')
1567
+ const rawRootStyle = (formStructure === null || formStructure === void 0 ? void 0 : formStructure.style) || {};
1568
+ const rootFormStyle = {};
1569
+ for (const [key, value] of Object.entries(rawRootStyle)) {
1570
+ if (key === 'background' && typeof value === 'string' && !value.includes('gradient')) {
1571
+ // Convert CSS 'background' to RN 'backgroundColor' for solid colors
1572
+ rootFormStyle.backgroundColor = value;
1573
+ }
1574
+ else if (key !== 'background') {
1575
+ // Pass through other properties (skip gradients which need special handling)
1576
+ rootFormStyle[key] = value;
1577
+ }
1578
+ }
1579
+ return (<react_native_1.View style={Object.assign(Object.assign(Object.assign({}, styles.container), containerStyle), rootFormStyle)}>
1580
+ {/* Header with Close or Back button */}
1581
+ <react_native_1.View style={Object.assign(Object.assign({}, styles.header), rootFormStyle)}>
1582
+ <react_native_1.View style={[styles.headerButton, { minWidth: 44, minHeight: 44, justifyContent: 'center' }]} onStartShouldSetResponder={() => {
1583
+ return true;
1584
+ }} onResponderGrant={() => {
1585
+ // Handle responder grant
1586
+ }} onResponderRelease={() => {
1587
+ handleHeaderButtonPress();
1588
+ }}>
1589
+ {renderIcon({
1590
+ name: view === 'main' ? 'close' : 'arrow-back',
1591
+ size: 24,
1592
+ color: (resolvedTitleStyle === null || resolvedTitleStyle === void 0 ? void 0 : resolvedTitleStyle.color) || '#666',
1593
+ opacity: 0.75,
1594
+ })}
1595
+ </react_native_1.View>
1596
+ {resolvedTitle && (<react_native_1.Text style={[
1597
+ styles.headerTitle,
1598
+ resolvedTitleStyle && Object.assign(Object.assign(Object.assign(Object.assign({}, (resolvedTitleStyle.color && { color: resolvedTitleStyle.color })), (resolvedTitleStyle.fontSize && { fontSize: resolvedTitleStyle.fontSize })), (resolvedTitleStyle.fontWeight && { fontWeight: resolvedTitleStyle.fontWeight })), (resolvedTitleStyle.fontFamily && { fontFamily: resolvedTitleStyle.fontFamily })),
1599
+ ]}>
1600
+ {resolvedTitle}
1601
+ </react_native_1.Text>)}
1602
+ {/* Empty spacer to balance the header when title is present */}
1603
+ {resolvedTitle && <react_native_1.View style={[styles.headerButton, { minWidth: 44, minHeight: 44 }]}/>}
1604
+ </react_native_1.View>
1605
+
1606
+ <react_native_1.ScrollView style={Object.assign(Object.assign({}, styles.scrollContent), rootFormStyle)} contentContainerStyle={rootFormStyle} showsVerticalScrollIndicator={false}>
1607
+ {view === 'main' && formStructure && (<>
1608
+ {/* <EditableWrapper componentId="title-text" componentType="text">
1609
+ <Text style={styles.title}>Invite people to join your team</Text>
1610
+ </EditableWrapper> */}
1611
+
1612
+ {/* Dynamic rendering from formStructure */}
1613
+ {(_g = formStructure.children) === null || _g === void 0 ? void 0 : _g.map((child, index) => {
1614
+ if (child.type === 'row') {
1615
+ return renderRow(child, index, formStructure.children.length);
1616
+ }
1617
+ return null;
1618
+ })}
1619
+ </>)}
1620
+
1621
+ {view === 'main' && !formStructure && (<react_native_1.View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
1622
+ <react_native_1.Text style={{ fontSize: 50, marginBottom: 16 }}>⚠️</react_native_1.Text>
1623
+ <react_native_1.Text style={{ fontSize: 18, fontWeight: 'bold', color: '#d9534f', marginBottom: 8, fontFamily }}>
1624
+ Configuration Error
1625
+ </react_native_1.Text>
1626
+ <react_native_1.Text style={{ fontSize: 14, color: '#666', textAlign: 'center', fontFamily }}>
1627
+ Unable to load form structure from widget configuration. Please check your widget configuration and try again.
1628
+ </react_native_1.Text>
1629
+ </react_native_1.View>)}
1630
+
1631
+ {view === 'email' && formStructure && (<>
1632
+ <react_native_1.View style={styles.section}>
1633
+ {/* Dynamic rendering from formStructure - only email-related blocks */}
1634
+ {(_h = formStructure.children) === null || _h === void 0 ? void 0 : _h.map((child, index) => {
1635
+ if (child.type === 'row') {
1636
+ // Render all rows, but filter blocks inside to only show grp-email-invitations
1637
+ return renderRow(child, index, formStructure.children.length, 'grp-email-invitations');
1638
+ }
1639
+ return null;
1640
+ })}
1641
+ </react_native_1.View>
1642
+ </>)}
1643
+
1644
+ {view === 'email' && !formStructure && (<react_native_1.View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 }}>
1645
+ <react_native_1.Text style={{ fontSize: 50, marginBottom: 16 }}>⚠️</react_native_1.Text>
1646
+ <react_native_1.Text style={{ fontSize: 18, fontWeight: 'bold', color: '#d9534f', marginBottom: 8, fontFamily }}>
1647
+ Configuration Error
1648
+ </react_native_1.Text>
1649
+ <react_native_1.Text style={{ fontSize: 14, color: '#666', textAlign: 'center', fontFamily }}>
1650
+ Unable to load form structure from widget configuration. Please check your widget configuration and try again.
1651
+ </react_native_1.Text>
1652
+ </react_native_1.View>)}
1653
+
1654
+ {view === 'contacts' && (<>
1655
+ <react_native_1.Text style={styles.title}>{getContactsCustomization('importContacts.title', 'Add from Contacts')}</react_native_1.Text>
1656
+
1657
+ <react_native_1.View style={styles.section}>
1658
+ <react_native_1.TextInput style={styles.input} placeholder={getContactsCustomization('importContacts.searchPlaceholder', 'Search contacts...')} placeholderTextColor="#999" value={searchQuery} onChangeText={setSearchQuery} autoCapitalize="none" autoCorrect={false} returnKeyType="search"/>
1659
+
1660
+ {loadingContacts ? (<react_native_1.View style={styles.loadingContainer}>
1661
+ <react_native_1.ActivityIndicator size="large" color="#6291d5"/>
1662
+ <react_native_1.Text style={styles.loadingText}>{getContactsCustomization('importContacts.loadingText', 'Loading contacts...')}</react_native_1.Text>
1663
+ </react_native_1.View>) : contactsError ? (<react_native_1.View style={styles.errorContainer}>
1664
+ <react_native_1.Text style={styles.errorTitle}>{getContactsCustomization('importContacts.errorTitle', 'Unable to Access Contacts')}</react_native_1.Text>
1665
+ <react_native_1.Text style={styles.errorMessage}>{contactsError.message}</react_native_1.Text>
1666
+ {contactsError.message.includes('Settings') && (<>
1667
+ <react_native_1.Text style={styles.errorHint}>
1668
+ To grant access: Open Settings → Privacy & Security → Contacts → Enable for
1669
+ this app
1670
+ </react_native_1.Text>
1671
+ <react_native_1.View style={styles.errorActions}>
1672
+ <react_native_1.TouchableOpacity style={[styles.button, styles.secondaryButton, styles.halfButton]} onPress={handleOpenSettings}>
1673
+ <react_native_1.Text style={styles.secondaryButtonText}>{getContactsCustomization('importContacts.openSettingsButton', 'Open Settings')}</react_native_1.Text>
1674
+ </react_native_1.TouchableOpacity>
1675
+ <react_native_1.TouchableOpacity style={[styles.button, styles.secondaryButton, styles.halfButton]} onPress={handleRetryContacts}>
1676
+ <react_native_1.Text style={styles.secondaryButtonText}>{getContactsCustomization('importContacts.retryButton', 'Retry')}</react_native_1.Text>
1677
+ </react_native_1.TouchableOpacity>
1678
+ </react_native_1.View>
1679
+ </>)}
1680
+ {!contactsError.message.includes('Settings') && (<react_native_1.TouchableOpacity style={[styles.button, styles.secondaryButton, { marginTop: 16 }]} onPress={handleRetryContacts}>
1681
+ <react_native_1.Text style={styles.secondaryButtonText}>{getContactsCustomization('importContacts.tryAgainButton', 'Try Again')}</react_native_1.Text>
1682
+ </react_native_1.TouchableOpacity>)}
1683
+ <react_native_1.Text style={styles.errorDetails}>
1684
+ {contactsError.message || 'Unknown error occurred'}
1685
+ </react_native_1.Text>
1686
+ </react_native_1.View>) : (<react_native_1.View style={styles.contactsList}>
1687
+ {filteredContacts.length === 0 ? (<react_native_1.Text style={styles.emptyText}>
1688
+ {searchQuery
1689
+ ? getContactsCustomization('importContacts.emptySearchState', 'No contacts match your search')
1690
+ : getContactsCustomization('importContacts.emptyState', 'No contacts with email addresses found')}
1691
+ </react_native_1.Text>) : (filteredContacts.map((contact) => {
1692
+ const isInvited = invitedContactIds.has(contact.id);
1693
+ const isLoading = loadingContactIds.has(contact.id);
1694
+ const initials = contact.name
1695
+ .split(' ')
1696
+ .map((part) => part[0])
1697
+ .join('')
1698
+ .toUpperCase()
1699
+ .slice(0, 2);
1700
+ return (<react_native_1.View key={contact.id} style={styles.contactItem}>
1701
+ {contact.imageUri ? (<react_native_1.Image source={{ uri: contact.imageUri }} style={styles.contactAvatar}/>) : (<react_native_1.View style={styles.contactAvatarPlaceholder}>
1702
+ <react_native_1.Text style={styles.contactAvatarInitials}>{initials}</react_native_1.Text>
1703
+ </react_native_1.View>)}
1704
+ <react_native_1.View style={styles.contactInfo}>
1705
+ <react_native_1.Text style={styles.contactName}>{contact.name}</react_native_1.Text>
1706
+ <react_native_1.Text style={styles.contactEmail}>{contact.email}</react_native_1.Text>
1707
+ </react_native_1.View>
1708
+ {isInvited ? (<react_native_1.Text style={styles.invitedText}>{getContactsCustomization('importContacts.invitedStatus', '✓ Invited!')}</react_native_1.Text>) : (<react_native_1.TouchableOpacity style={styles.inviteButton} onPress={() => handleInviteContactWithHaptics(contact.id)} disabled={isLoading}>
1709
+ {isLoading ? (<react_native_1.ActivityIndicator size="small" color="#333"/>) : (<react_native_1.Text style={styles.inviteButtonText}>{getContactsCustomization('importContacts.inviteButton', 'Invite')}</react_native_1.Text>)}
1710
+ </react_native_1.TouchableOpacity>)}
1711
+ </react_native_1.View>);
1712
+ }))}
1713
+ </react_native_1.View>)}
1714
+ </react_native_1.View>
1715
+ </>)}
1716
+
1717
+ {view === 'googleContacts' && (<>
1718
+ <react_native_1.Text style={styles.title}>{getContactsCustomization('google.title', 'Add from Google Contacts')}</react_native_1.Text>
1719
+
1720
+ <react_native_1.View style={styles.section}>
1721
+ <react_native_1.TextInput style={styles.input} placeholder={getContactsCustomization('google.searchPlaceholder', 'Search contacts...')} placeholderTextColor="#999" value={googleSearchQuery} onChangeText={setGoogleSearchQuery} autoCapitalize="none" autoCorrect={false} returnKeyType="search"/>
1722
+
1723
+ {loadingGoogleContacts ? (<react_native_1.View style={styles.loadingContainer}>
1724
+ <react_native_1.ActivityIndicator size="large" color="#6291d5"/>
1725
+ <react_native_1.Text style={styles.loadingText}>{getContactsCustomization('google.loadingText', 'Loading Google contacts...')}</react_native_1.Text>
1726
+ </react_native_1.View>) : googleContactsError ? (<react_native_1.View style={styles.errorContainer}>
1727
+ <react_native_1.Text style={styles.errorTitle}>{getContactsCustomization('google.errorTitle', 'Unable to Access Google Contacts')}</react_native_1.Text>
1728
+ <react_native_1.Text style={styles.errorMessage}>{googleContactsError.message}</react_native_1.Text>
1729
+ <react_native_1.TouchableOpacity style={[styles.button, styles.secondaryButton, { marginTop: 16 }]} onPress={handleRetryContacts}>
1730
+ <react_native_1.Text style={styles.secondaryButtonText}>{getContactsCustomization('google.tryAgainButton', 'Try Again')}</react_native_1.Text>
1731
+ </react_native_1.TouchableOpacity>
1732
+ <react_native_1.Text style={styles.errorDetails}>
1733
+ {googleContactsError.message || 'Unknown error occurred'}
1734
+ </react_native_1.Text>
1735
+ </react_native_1.View>) : (<react_native_1.View style={styles.contactsList}>
1736
+ {filteredGoogleContacts.length === 0 ? (<react_native_1.Text style={styles.emptyText}>
1737
+ {googleSearchQuery
1738
+ ? getContactsCustomization('google.emptySearchState', 'No contacts match your search')
1739
+ : getContactsCustomization('google.emptyState', 'No Google contacts with email addresses found')}
1740
+ </react_native_1.Text>) : (filteredGoogleContacts.map((contact) => {
1741
+ const isInvited = invitedGoogleContactIds.has(contact.id);
1742
+ const isLoading = loadingGoogleContactIds.has(contact.id);
1743
+ const initials = contact.name
1744
+ .split(' ')
1745
+ .map((part) => part[0])
1746
+ .join('')
1747
+ .toUpperCase()
1748
+ .slice(0, 2);
1749
+ return (<react_native_1.View key={contact.id} style={styles.contactItem}>
1750
+ {contact.imageUri ? (<react_native_1.Image source={{ uri: contact.imageUri }} style={styles.contactAvatar}/>) : (<react_native_1.View style={styles.contactAvatarPlaceholder}>
1751
+ <react_native_1.Text style={styles.contactAvatarInitials}>{initials}</react_native_1.Text>
1752
+ </react_native_1.View>)}
1753
+ <react_native_1.View style={styles.contactInfo}>
1754
+ <react_native_1.Text style={styles.contactName}>{contact.name}</react_native_1.Text>
1755
+ <react_native_1.Text style={styles.contactEmail}>{contact.email}</react_native_1.Text>
1756
+ </react_native_1.View>
1757
+ {isInvited ? (<react_native_1.Text style={styles.invitedText}>{getContactsCustomization('google.invitedStatus', '✓ Invited!')}</react_native_1.Text>) : (<react_native_1.TouchableOpacity style={styles.inviteButton} onPress={() => handleInviteGoogleContactWithHaptics(contact.id)} disabled={isLoading}>
1758
+ {isLoading ? (<react_native_1.ActivityIndicator size="small" color="#333"/>) : (<react_native_1.Text style={styles.inviteButtonText}>{getContactsCustomization('google.inviteButton', 'Invite')}</react_native_1.Text>)}
1759
+ </react_native_1.TouchableOpacity>)}
1760
+ </react_native_1.View>);
1761
+ }))}
1762
+ </react_native_1.View>)}
1763
+ </react_native_1.View>
1764
+ </>)}
1765
+
1766
+ {view === 'qrcode' && (<react_native_1.View style={styles.section}>
1767
+ <react_native_1.View style={styles.qrCodeViewContainer}>
1768
+ {react_native_1.Platform.OS === 'web' ? (
1769
+ // In web preview mode, show placeholder QR code immediately for demo
1770
+ renderQRCode ? (renderQRCode({
1771
+ value: logic.invitationLink,
1772
+ size: 250,
1773
+ })) : (<react_native_1.Text style={styles.errorMessage}>QR Code rendering not available</react_native_1.Text>)) : loadingInvitationLink ||
1774
+ logic.invitationLink === 'https://app.vortexsoftware.com/invite/abc123' ? (
1775
+ // In native mode, show loading while fetching real link
1776
+ <react_native_1.View style={styles.loadingContainer}>
1777
+ <react_native_1.ActivityIndicator size="large" color="#6291d5"/>
1778
+ <react_native_1.Text style={styles.loadingText}>Generating QR Code...</react_native_1.Text>
1779
+ </react_native_1.View>) : renderQRCode ? (renderQRCode({
1780
+ value: logic.invitationLink,
1781
+ size: 250,
1782
+ })) : (<react_native_1.Text style={styles.errorMessage}>QR Code rendering not available</react_native_1.Text>)}
1783
+ </react_native_1.View>
1784
+ </react_native_1.View>)}
1785
+ </react_native_1.ScrollView>
1786
+ </react_native_1.View>);
1787
+ }
1788
+ const createStyles = (fontFamily) => react_native_1.StyleSheet.create({
1789
+ container: {
1790
+ flex: 1,
1791
+ paddingTop: 8,
1792
+ backgroundColor: '#fff',
1793
+ },
1794
+ handle: {
1795
+ width: 40,
1796
+ height: 4,
1797
+ backgroundColor: '#ddd',
1798
+ borderRadius: 2,
1799
+ alignSelf: 'center',
1800
+ marginBottom: 2,
1801
+ },
1802
+ header: {
1803
+ flexDirection: 'row',
1804
+ justifyContent: 'space-between',
1805
+ alignItems: 'center',
1806
+ paddingHorizontal: 16,
1807
+ paddingVertical: 4,
1808
+ zIndex: 10,
1809
+ backgroundColor: '#fff',
1810
+ },
1811
+ headerButton: {
1812
+ padding: 4,
1813
+ },
1814
+ headerTitle: {
1815
+ fontFamily,
1816
+ fontSize: 17,
1817
+ fontWeight: '600',
1818
+ color: '#1a1a1a',
1819
+ textAlign: 'center',
1820
+ flex: 1,
1821
+ },
1822
+ sendButton: {
1823
+ paddingHorizontal: 8,
1824
+ paddingVertical: 8,
1825
+ },
1826
+ sendButtonText: {
1827
+ fontFamily,
1828
+ color: '#2196F3',
1829
+ fontSize: 16,
1830
+ fontWeight: '600',
1831
+ },
1832
+ scrollContent: {
1833
+ flex: 1,
1834
+ paddingHorizontal: 20,
1835
+ // backgroundColor: 'none',
1836
+ },
1837
+ title: {
1838
+ fontFamily,
1839
+ fontSize: 18,
1840
+ fontWeight: '700',
1841
+ color: '#1a1a1a',
1842
+ marginTop: 16,
1843
+ marginBottom: 20,
1844
+ textAlign: 'center',
1845
+ },
1846
+ subtitle: {
1847
+ fontFamily,
1848
+ fontSize: 13,
1849
+ color: '#666',
1850
+ marginBottom: 20,
1851
+ lineHeight: 18,
1852
+ },
1853
+ // Sections
1854
+ section: {
1855
+ marginBottom: 10,
1856
+ },
1857
+ emptyRowEditMode: {
1858
+ minHeight: 40,
1859
+ backgroundColor: 'rgba(200, 200, 200, 0.2)',
1860
+ borderWidth: 1,
1861
+ borderColor: 'rgba(150, 150, 150, 0.3)',
1862
+ borderStyle: 'dashed',
1863
+ borderRadius: 4,
1864
+ },
1865
+ sectionTitle: {
1866
+ fontFamily,
1867
+ fontSize: 16,
1868
+ fontWeight: '700',
1869
+ color: '#1a1a1a',
1870
+ marginBottom: 12,
1871
+ },
1872
+ // Email chips
1873
+ emailChipsContainer: {
1874
+ flexDirection: 'row',
1875
+ flexWrap: 'wrap',
1876
+ gap: 8,
1877
+ marginBottom: 12,
1878
+ },
1879
+ emailChip: {
1880
+ flexDirection: 'row',
1881
+ alignItems: 'center',
1882
+ backgroundColor: '#e3f2fd',
1883
+ borderRadius: 16,
1884
+ paddingVertical: 6,
1885
+ paddingLeft: 12,
1886
+ paddingRight: 8,
1887
+ borderWidth: 1,
1888
+ borderColor: '#90caf9',
1889
+ },
1890
+ emailChipText: {
1891
+ fontFamily,
1892
+ fontSize: 13,
1893
+ color: '#1565c0',
1894
+ marginRight: 6,
1895
+ },
1896
+ emailChipRemove: {
1897
+ fontFamily,
1898
+ fontSize: 20,
1899
+ color: '#1565c0',
1900
+ fontWeight: '600',
1901
+ lineHeight: 20,
1902
+ },
1903
+ // Input
1904
+ input: {
1905
+ fontFamily,
1906
+ borderWidth: 1,
1907
+ borderColor: '#ddd',
1908
+ borderRadius: 8,
1909
+ paddingHorizontal: 14,
1910
+ paddingVertical: 10,
1911
+ fontSize: 15,
1912
+ color: '#1a1a1a',
1913
+ backgroundColor: '#fafafa',
1914
+ marginBottom: 12,
1915
+ },
1916
+ // Buttons
1917
+ button: {
1918
+ borderRadius: 8,
1919
+ paddingVertical: 12,
1920
+ paddingHorizontal: 16,
1921
+ alignItems: 'center',
1922
+ justifyContent: 'center',
1923
+ flexDirection: 'row',
1924
+ },
1925
+ secondaryButton: {
1926
+ backgroundColor: '#f5f5f5',
1927
+ borderWidth: 1,
1928
+ borderColor: '#e0e0e0',
1929
+ },
1930
+ secondaryButtonText: {
1931
+ fontFamily,
1932
+ color: '#333',
1933
+ fontSize: 14,
1934
+ fontWeight: '600',
1935
+ },
1936
+ tertiaryButton: {
1937
+ backgroundColor: '#f5f5f5',
1938
+ borderWidth: 1,
1939
+ borderColor: '#e0e0e0',
1940
+ },
1941
+ tertiaryButtonText: {
1942
+ fontFamily,
1943
+ color: '#333',
1944
+ fontSize: 11,
1945
+ fontWeight: '600',
1946
+ },
1947
+ actionButtons: {
1948
+ flexDirection: 'row',
1949
+ gap: 10,
1950
+ },
1951
+ halfButton: {
1952
+ flex: 1,
1953
+ },
1954
+ shareButtonsContainer: {
1955
+ flexDirection: 'column',
1956
+ gap: 10,
1957
+ },
1958
+ contactButtonsContainer: {
1959
+ flexDirection: 'column',
1960
+ gap: 10,
1961
+ },
1962
+ fullButton: {
1963
+ width: '100%',
1964
+ },
1965
+ buttonIconContainer: {
1966
+ marginRight: 8,
1967
+ },
1968
+ // Contacts list
1969
+ contactsList: {
1970
+ gap: 0,
1971
+ },
1972
+ contactItem: {
1973
+ flexDirection: 'row',
1974
+ alignItems: 'center',
1975
+ paddingVertical: 12,
1976
+ },
1977
+ contactAvatar: {
1978
+ width: 44,
1979
+ height: 44,
1980
+ borderRadius: 22,
1981
+ },
1982
+ contactAvatarPlaceholder: {
1983
+ width: 44,
1984
+ height: 44,
1985
+ borderRadius: 22,
1986
+ backgroundColor: '#6291d5',
1987
+ alignItems: 'center',
1988
+ justifyContent: 'center',
1989
+ },
1990
+ contactAvatarInitials: {
1991
+ fontSize: 16,
1992
+ fontWeight: '600',
1993
+ color: '#ffffff',
1994
+ },
1995
+ contactInfo: {
1996
+ flex: 1,
1997
+ marginLeft: 12,
1998
+ marginRight: 12,
1999
+ },
2000
+ contactName: {
2001
+ fontFamily,
2002
+ fontSize: 15,
2003
+ fontWeight: '600',
2004
+ color: '#1a1a1a',
2005
+ marginBottom: 4,
2006
+ },
2007
+ contactEmail: {
2008
+ fontFamily,
2009
+ fontSize: 13,
2010
+ color: '#666',
2011
+ },
2012
+ inviteButton: {
2013
+ paddingVertical: 8,
2014
+ paddingHorizontal: 16,
2015
+ backgroundColor: '#f5f5f5',
2016
+ borderWidth: 1,
2017
+ borderColor: '#e0e0e0',
2018
+ borderRadius: 6,
2019
+ minWidth: 80,
2020
+ alignItems: 'center',
2021
+ },
2022
+ inviteButtonText: {
2023
+ fontFamily,
2024
+ fontSize: 13,
2025
+ fontWeight: '600',
2026
+ color: '#333',
2027
+ },
2028
+ invitedText: {
2029
+ fontFamily,
2030
+ fontSize: 13,
2031
+ fontWeight: '600',
2032
+ color: '#666',
2033
+ },
2034
+ successMessageContainer: {
2035
+ paddingVertical: 12,
2036
+ alignItems: 'center',
2037
+ },
2038
+ // Loading state
2039
+ loadingContainer: {
2040
+ paddingVertical: 40,
2041
+ alignItems: 'center',
2042
+ justifyContent: 'center',
2043
+ },
2044
+ loadingText: {
2045
+ fontFamily,
2046
+ fontSize: 14,
2047
+ color: '#666',
2048
+ marginTop: 12,
2049
+ },
2050
+ emptyText: {
2051
+ fontFamily,
2052
+ fontSize: 14,
2053
+ color: '#999',
2054
+ textAlign: 'center',
2055
+ paddingVertical: 20,
2056
+ },
2057
+ // Error state
2058
+ errorContainer: {
2059
+ paddingVertical: 40,
2060
+ paddingHorizontal: 20,
2061
+ alignItems: 'center',
2062
+ justifyContent: 'center',
2063
+ },
2064
+ errorTitle: {
2065
+ fontFamily,
2066
+ fontSize: 16,
2067
+ fontWeight: '600',
2068
+ color: '#d9534f',
2069
+ marginBottom: 12,
2070
+ textAlign: 'center',
2071
+ },
2072
+ errorMessage: {
2073
+ fontFamily,
2074
+ fontSize: 14,
2075
+ color: '#666',
2076
+ marginBottom: 16,
2077
+ textAlign: 'center',
2078
+ lineHeight: 20,
2079
+ },
2080
+ errorHint: {
2081
+ fontFamily,
2082
+ fontSize: 13,
2083
+ color: '#666',
2084
+ marginTop: 12,
2085
+ marginBottom: 8,
2086
+ textAlign: 'center',
2087
+ lineHeight: 18,
2088
+ backgroundColor: '#f0f8ff',
2089
+ padding: 12,
2090
+ borderRadius: 6,
2091
+ borderWidth: 1,
2092
+ borderColor: '#b3d9ff',
2093
+ },
2094
+ errorActions: {
2095
+ flexDirection: 'row',
2096
+ gap: 10,
2097
+ marginTop: 16,
2098
+ marginBottom: 8,
2099
+ width: '100%',
2100
+ },
2101
+ errorDetails: {
2102
+ fontFamily,
2103
+ fontSize: 12,
2104
+ color: '#999',
2105
+ textAlign: 'center',
2106
+ fontStyle: 'italic',
2107
+ },
2108
+ // QR Code view
2109
+ qrCodeViewContainer: {
2110
+ alignItems: 'center',
2111
+ justifyContent: 'center',
2112
+ padding: 20,
2113
+ backgroundColor: '#fff',
2114
+ borderRadius: 10,
2115
+ marginVertical: 10,
2116
+ },
2117
+ // Edit mode circle button
2118
+ editModeCircleButton: {
2119
+ position: 'absolute',
2120
+ right: 8,
2121
+ top: '50%',
2122
+ transform: [{ translateY: -15 }],
2123
+ width: 30,
2124
+ height: 30,
2125
+ borderRadius: 15,
2126
+ backgroundColor: '#2196F3',
2127
+ justifyContent: 'center',
2128
+ alignItems: 'center',
2129
+ shadowColor: '#000',
2130
+ shadowOffset: { width: 0, height: 2 },
2131
+ shadowOpacity: 0.25,
2132
+ shadowRadius: 3.84,
2133
+ elevation: 5,
2134
+ },
2135
+ editModeCircleButtonText: {
2136
+ color: '#fff',
2137
+ fontSize: 16,
2138
+ fontWeight: 'bold',
2139
+ },
2140
+ });
2141
+ //# sourceMappingURL=InviteFormCore.js.map