@linktr.ee/create-link-app 2.0.0-rc.1 → 2.0.0
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.
|
@@ -35,7 +35,6 @@ const container = document.getElementById('root');
|
|
|
35
35
|
const root = (0, client_1.createRoot)(container);
|
|
36
36
|
function EmbeddedExtension() {
|
|
37
37
|
const wrapperRef = (0, react_1.useRef)(null);
|
|
38
|
-
const [extensionData, setExtensionData] = (0, react_1.useState)(extension_dev_data_1.default);
|
|
39
38
|
(0, react_1.useEffect)(() => {
|
|
40
39
|
const postReady = (height) => {
|
|
41
40
|
const ready = { type: 'extension-ready', data: { ready: true, height } };
|
|
@@ -56,15 +55,10 @@ function EmbeddedExtension() {
|
|
|
56
55
|
ro.observe(wrapperRef.current);
|
|
57
56
|
const onMessage = (event) => {
|
|
58
57
|
if (event.data?.type === 'extension-data') {
|
|
59
|
-
const data = event.data?.data || {};
|
|
60
58
|
// eslint-disable-next-line no-console
|
|
61
|
-
console.info('[Extension] received extension-data', data);
|
|
62
|
-
setExtensionData((prev) => ({ ...prev, ...data }));
|
|
59
|
+
console.info('[Extension] received extension-data', event.data?.data);
|
|
63
60
|
}
|
|
64
61
|
};
|
|
65
|
-
// forward interaction events to the parent (parity with production)
|
|
66
|
-
const onInteraction = (event) => window.parent.postMessage({ type: 'interaction-event', data: event.detail }, '*');
|
|
67
|
-
document.addEventListener('interaction-event', onInteraction);
|
|
68
62
|
window.addEventListener('message', onMessage);
|
|
69
63
|
return () => {
|
|
70
64
|
if (wrapperRef.current) {
|
|
@@ -75,12 +69,11 @@ function EmbeddedExtension() {
|
|
|
75
69
|
// ignore unobserve errors in dev simulator
|
|
76
70
|
}
|
|
77
71
|
}
|
|
78
|
-
document.removeEventListener('interaction-event', onInteraction);
|
|
79
72
|
window.removeEventListener('message', onMessage);
|
|
80
73
|
};
|
|
81
74
|
}, []);
|
|
82
75
|
return (react_1.default.createElement("div", { ref: wrapperRef, style: { display: 'block' } },
|
|
83
|
-
react_1.default.createElement(extension_1.default, { ...
|
|
76
|
+
react_1.default.createElement(extension_1.default, { ...extension_dev_data_1.default })));
|
|
84
77
|
}
|
|
85
78
|
const App = () => {
|
|
86
79
|
if (window.location.search === '?embed') {
|
|
@@ -30,22 +30,14 @@ const react_1 = __importStar(require("react"));
|
|
|
30
30
|
const styled_components_1 = __importStar(require("styled-components"));
|
|
31
31
|
const iframe_resizer_react_1 = __importDefault(require("iframe-resizer-react"));
|
|
32
32
|
const extension_dev_data_1 = __importDefault(require("@linktr.ee/extension-dev-data"));
|
|
33
|
-
function coerceExtensionData(input) {
|
|
34
|
-
if (input !== null && typeof input === 'object' && !Array.isArray(input)) {
|
|
35
|
-
return input;
|
|
36
|
-
}
|
|
37
|
-
return {};
|
|
38
|
-
}
|
|
39
33
|
const Global = (0, styled_components_1.createGlobalStyle) `
|
|
40
34
|
html, body, #root { height: 100%; }
|
|
41
35
|
body { margin: 0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji"; background: #111317; }
|
|
42
36
|
`;
|
|
43
37
|
const Page = styled_components_1.default.div `
|
|
44
38
|
min-height: 100vh;
|
|
45
|
-
display:
|
|
46
|
-
|
|
47
|
-
justify-content: center;
|
|
48
|
-
gap: 24px;
|
|
39
|
+
display: grid;
|
|
40
|
+
place-items: center;
|
|
49
41
|
padding: 24px;
|
|
50
42
|
box-sizing: border-box;
|
|
51
43
|
`;
|
|
@@ -107,16 +99,6 @@ const ScrollArea = styled_components_1.default.div `
|
|
|
107
99
|
padding: 24px 22px 28px;
|
|
108
100
|
box-sizing: border-box;
|
|
109
101
|
`;
|
|
110
|
-
const SettingsPanel = styled_components_1.default.div `
|
|
111
|
-
width: 320px;
|
|
112
|
-
max-width: calc(100% - 24px);
|
|
113
|
-
background: rgba(255, 255, 255, 0.98);
|
|
114
|
-
color: #1f1147;
|
|
115
|
-
border-radius: 14px;
|
|
116
|
-
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.25);
|
|
117
|
-
padding: 12px 14px;
|
|
118
|
-
border: 1px solid rgba(0, 0, 0, 0.05);
|
|
119
|
-
`;
|
|
120
102
|
const Profile = styled_components_1.default.div `
|
|
121
103
|
display: flex;
|
|
122
104
|
flex-direction: column;
|
|
@@ -233,54 +215,7 @@ function kebab() {
|
|
|
233
215
|
function Simulator() {
|
|
234
216
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
235
217
|
const [loadFailed, setLoadFailed] = (0, react_1.useState)(false);
|
|
236
|
-
const [settingsOpen, setSettingsOpen] = (0, react_1.useState)(false);
|
|
237
|
-
// Allow overriding default dev data via window.postMessage({ type: 'extension-data', data: {...} })
|
|
238
|
-
const [extensionData] = (0, react_1.useState)(() => coerceExtensionData(extension_dev_data_1.default));
|
|
239
|
-
const DEFAULT_THEME = {
|
|
240
|
-
textColor: '#54417e',
|
|
241
|
-
backgroundColor: '#f2c2f3',
|
|
242
|
-
borderRadius: 'var(--button-style-inner-radius)',
|
|
243
|
-
borderColor: '#e9eaeb',
|
|
244
|
-
isOutlineStyle: false,
|
|
245
|
-
contrastColor: 'black',
|
|
246
|
-
textHoverColor: '#54417e',
|
|
247
|
-
buttonColor: '#7c3aed',
|
|
248
|
-
};
|
|
249
|
-
const [theme, setTheme] = (0, react_1.useState)(() => {
|
|
250
|
-
try {
|
|
251
|
-
const raw = window.localStorage.getItem('simulator:theme');
|
|
252
|
-
if (raw)
|
|
253
|
-
return { ...DEFAULT_THEME, ...JSON.parse(raw) };
|
|
254
|
-
}
|
|
255
|
-
catch (e) {
|
|
256
|
-
void e;
|
|
257
|
-
}
|
|
258
|
-
return DEFAULT_THEME;
|
|
259
|
-
});
|
|
260
|
-
// IframeResizer's React wrapper forwards a proxy object, not the raw iframe
|
|
261
|
-
// Store a generic ref and resolve the actual iframe window via a helper
|
|
262
218
|
const iframeRef = (0, react_1.useRef)(null);
|
|
263
|
-
const getIframeWindow = (0, react_1.useCallback)(() => {
|
|
264
|
-
const node = iframeRef.current;
|
|
265
|
-
if (!node)
|
|
266
|
-
return null;
|
|
267
|
-
if (node.contentWindow)
|
|
268
|
-
return node.contentWindow;
|
|
269
|
-
const proxy = node;
|
|
270
|
-
if (typeof proxy.getIframeElement === 'function') {
|
|
271
|
-
try {
|
|
272
|
-
const el = proxy.getIframeElement();
|
|
273
|
-
return el?.contentWindow ?? null;
|
|
274
|
-
}
|
|
275
|
-
catch (e) {
|
|
276
|
-
void e;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
const maybeIframe = proxy.iframeResizer?.iframe;
|
|
280
|
-
if (maybeIframe?.contentWindow)
|
|
281
|
-
return maybeIframe.contentWindow;
|
|
282
|
-
return null;
|
|
283
|
-
}, []);
|
|
284
219
|
const loadTimeoutRef = (0, react_1.useRef)(null);
|
|
285
220
|
const APP_LOAD_TIMEOUT_MILLISECONDS = 8000;
|
|
286
221
|
const MAX_IFRAME_HEIGHT = 900;
|
|
@@ -293,32 +228,34 @@ function Simulator() {
|
|
|
293
228
|
}
|
|
294
229
|
}, []);
|
|
295
230
|
const initialiseData = (0, react_1.useCallback)(() => {
|
|
296
|
-
|
|
297
|
-
if (!cw) {
|
|
231
|
+
if (!iframeRef.current?.contentWindow)
|
|
298
232
|
return;
|
|
299
|
-
}
|
|
300
233
|
const payload = {
|
|
301
234
|
type: 'extension-data',
|
|
302
235
|
data: {
|
|
303
|
-
|
|
304
|
-
|
|
236
|
+
__environment: {
|
|
237
|
+
RECAPTCHA_SITE_KEY: 'dev-invisible',
|
|
238
|
+
GRAPH_ENDPOINT: `${window.location.origin}/graphql`,
|
|
239
|
+
GRAPHQL_CLIENT_NAME: '@linktr.ee/create-link-app',
|
|
240
|
+
GRAPHQL_CLIENT_VERSION: 'dev',
|
|
241
|
+
COUNTRY_CODE: 'US',
|
|
242
|
+
PROFILE: 'dev-user',
|
|
243
|
+
},
|
|
244
|
+
__linkUrl: extension_dev_data_1.default?.url ?? '',
|
|
245
|
+
__thumbnail: extension_dev_data_1.default?.thumbnail ?? '',
|
|
305
246
|
__linkParams: null,
|
|
306
247
|
displayType: 'accordion',
|
|
307
|
-
...
|
|
308
|
-
__theme: { ...theme, backgroundColor: theme.buttonColor }, // button color of the host is the background color of the link app
|
|
248
|
+
...extension_dev_data_1.default,
|
|
309
249
|
},
|
|
310
250
|
};
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}, [targetOrigin, theme, extensionData, getIframeWindow]);
|
|
251
|
+
iframeRef.current.contentWindow.postMessage(payload, targetOrigin);
|
|
252
|
+
}, [targetOrigin]);
|
|
314
253
|
(0, react_1.useEffect)(() => {
|
|
315
254
|
const handler = (event) => {
|
|
316
|
-
const
|
|
317
|
-
const type = msg.type || '';
|
|
255
|
+
const type = (event?.data && event.data.type) || '';
|
|
318
256
|
if (!type)
|
|
319
257
|
return;
|
|
320
|
-
|
|
321
|
-
if (cw && event.source !== cw)
|
|
258
|
+
if (iframeRef.current?.contentWindow && event.source !== iframeRef.current.contentWindow)
|
|
322
259
|
return;
|
|
323
260
|
switch (type) {
|
|
324
261
|
case 'extension-loaded': {
|
|
@@ -327,21 +264,11 @@ function Simulator() {
|
|
|
327
264
|
}
|
|
328
265
|
case 'extension-ready': {
|
|
329
266
|
setLoading(false);
|
|
330
|
-
// Ensure data is sent if not already
|
|
331
267
|
try {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
catch (e) {
|
|
335
|
-
void e;
|
|
336
|
-
}
|
|
337
|
-
try {
|
|
338
|
-
const el = document.getElementById('extension-iframe-sim');
|
|
339
|
-
const cw = el?.contentWindow || getIframeWindow();
|
|
340
|
-
cw?.focus();
|
|
341
|
-
}
|
|
342
|
-
catch (e) {
|
|
343
|
-
void e;
|
|
268
|
+
const node = document.getElementById('extension-iframe-sim');
|
|
269
|
+
(node || iframeRef.current)?.contentWindow?.focus();
|
|
344
270
|
}
|
|
271
|
+
catch { }
|
|
345
272
|
break;
|
|
346
273
|
}
|
|
347
274
|
case 'extension-error': {
|
|
@@ -349,6 +276,11 @@ function Simulator() {
|
|
|
349
276
|
setLoadFailed(true);
|
|
350
277
|
break;
|
|
351
278
|
}
|
|
279
|
+
case 'interaction-event': {
|
|
280
|
+
// eslint-disable-next-line no-console
|
|
281
|
+
console.info('[Simulator] interaction-event', event.data?.data);
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
352
284
|
default:
|
|
353
285
|
break;
|
|
354
286
|
}
|
|
@@ -369,43 +301,14 @@ function Simulator() {
|
|
|
369
301
|
window.clearTimeout(loadTimeoutRef.current);
|
|
370
302
|
};
|
|
371
303
|
}, [loading]);
|
|
372
|
-
// persist theme and re-post data when changed
|
|
373
|
-
(0, react_1.useEffect)(() => {
|
|
374
|
-
try {
|
|
375
|
-
window.localStorage.setItem('simulator:theme', JSON.stringify(theme));
|
|
376
|
-
}
|
|
377
|
-
catch (e) {
|
|
378
|
-
void e;
|
|
379
|
-
}
|
|
380
|
-
if (getIframeWindow())
|
|
381
|
-
initialiseData();
|
|
382
|
-
}, [theme, initialiseData, getIframeWindow]);
|
|
383
|
-
// Re-post data when external extension-data overrides change
|
|
384
|
-
(0, react_1.useEffect)(() => {
|
|
385
|
-
if (getIframeWindow())
|
|
386
|
-
initialiseData();
|
|
387
|
-
}, [extensionData, initialiseData, getIframeWindow]);
|
|
388
304
|
const iframeSrc = (0, react_1.useMemo)(() => `${window.location}?embed`, []);
|
|
389
|
-
const cardStyle = (0, react_1.useMemo)(() => {
|
|
390
|
-
const bg = theme.isOutlineStyle ? 'transparent' : theme.backgroundColor;
|
|
391
|
-
const border = `1px solid ${theme.borderColor}`;
|
|
392
|
-
const color = theme.textColor;
|
|
393
|
-
const radius = theme.borderRadius;
|
|
394
|
-
const style = {
|
|
395
|
-
background: bg,
|
|
396
|
-
color,
|
|
397
|
-
border,
|
|
398
|
-
borderRadius: radius,
|
|
399
|
-
};
|
|
400
|
-
return style;
|
|
401
|
-
}, [theme]);
|
|
402
305
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
403
306
|
react_1.default.createElement(Global, null),
|
|
404
307
|
react_1.default.createElement(Page, null,
|
|
405
|
-
react_1.default.createElement(Phone,
|
|
308
|
+
react_1.default.createElement(Phone, null,
|
|
406
309
|
react_1.default.createElement(Notch, null),
|
|
407
310
|
react_1.default.createElement(HeaderChrome, null,
|
|
408
|
-
react_1.default.createElement(RoundIcon, { title: "Settings"
|
|
311
|
+
react_1.default.createElement(RoundIcon, { title: "Settings" }, "\u2699\uFE0F"),
|
|
409
312
|
react_1.default.createElement(RoundIcon, { title: "Notifications" }, "\uD83D\uDD14")),
|
|
410
313
|
react_1.default.createElement(ScrollArea, null,
|
|
411
314
|
react_1.default.createElement(Profile, null,
|
|
@@ -414,7 +317,7 @@ function Simulator() {
|
|
|
414
317
|
"Sample Creator ",
|
|
415
318
|
react_1.default.createElement(Badge, { title: "Verified" }, "\u2713")),
|
|
416
319
|
react_1.default.createElement(Bio, null, "Digital creator")),
|
|
417
|
-
react_1.default.createElement(ExtensionCard,
|
|
320
|
+
react_1.default.createElement(ExtensionCard, null,
|
|
418
321
|
loadFailed && (react_1.default.createElement("div", { style: {
|
|
419
322
|
position: 'absolute',
|
|
420
323
|
inset: 0,
|
|
@@ -444,28 +347,19 @@ function Simulator() {
|
|
|
444
347
|
'allow-forms',
|
|
445
348
|
].join(' '), forwardRef: (node) => {
|
|
446
349
|
iframeRef.current = node;
|
|
447
|
-
const cw = getIframeWindow();
|
|
448
|
-
if (cw) {
|
|
449
|
-
try {
|
|
450
|
-
setTimeout(() => initialiseData(), 0);
|
|
451
|
-
}
|
|
452
|
-
catch (e) {
|
|
453
|
-
void e;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
350
|
} })),
|
|
457
|
-
react_1.default.createElement(Card,
|
|
351
|
+
react_1.default.createElement(Card, null,
|
|
458
352
|
react_1.default.createElement(CardIcon, null, "\uD83D\uDCBB"),
|
|
459
353
|
react_1.default.createElement("div", null,
|
|
460
354
|
react_1.default.createElement(CardTitle, null, "Featured link"),
|
|
461
355
|
react_1.default.createElement(CardSub, null, "example.com")),
|
|
462
356
|
react_1.default.createElement(Kebab, null, kebab())),
|
|
463
|
-
react_1.default.createElement(Card,
|
|
357
|
+
react_1.default.createElement(Card, null,
|
|
464
358
|
react_1.default.createElement(CardIcon, null, "\uD83D\uDCAC"),
|
|
465
359
|
react_1.default.createElement("div", null,
|
|
466
360
|
react_1.default.createElement(CardTitle, null, "Follow me")),
|
|
467
361
|
react_1.default.createElement(Kebab, null, kebab())),
|
|
468
|
-
react_1.default.createElement(Card,
|
|
362
|
+
react_1.default.createElement(Card, null,
|
|
469
363
|
react_1.default.createElement(CardIcon, null, "\u2709\uFE0F"),
|
|
470
364
|
react_1.default.createElement("div", null,
|
|
471
365
|
react_1.default.createElement(CardTitle, null, "Contact")),
|
|
@@ -474,36 +368,6 @@ function Simulator() {
|
|
|
474
368
|
react_1.default.createElement("span", { title: "Social A" }, "in"),
|
|
475
369
|
react_1.default.createElement("span", { title: "Social B" }, "\uD835\uDD4F"),
|
|
476
370
|
react_1.default.createElement("span", { title: "Social C" }, "\uD83D\uDC7B")),
|
|
477
|
-
react_1.default.createElement(Footer, null, "Report \u00B7 Privacy")))
|
|
478
|
-
settingsOpen && (react_1.default.createElement(SettingsPanel, null,
|
|
479
|
-
react_1.default.createElement("div", { style: { fontWeight: 800, fontSize: 14, marginBottom: 8 } }, "Theme"),
|
|
480
|
-
[
|
|
481
|
-
['Text color', 'textColor'],
|
|
482
|
-
['Background', 'backgroundColor'],
|
|
483
|
-
['Border color', 'borderColor'],
|
|
484
|
-
['Hover text', 'textHoverColor'],
|
|
485
|
-
['Contrast color', 'contrastColor'],
|
|
486
|
-
['Button color', 'buttonColor'],
|
|
487
|
-
].map(([label, key]) => (react_1.default.createElement("label", { key: key, style: {
|
|
488
|
-
display: 'grid',
|
|
489
|
-
gridTemplateColumns: '1fr 120px',
|
|
490
|
-
alignItems: 'center',
|
|
491
|
-
gap: 10,
|
|
492
|
-
fontSize: 12,
|
|
493
|
-
margin: '8px 0',
|
|
494
|
-
} },
|
|
495
|
-
react_1.default.createElement("span", null, label),
|
|
496
|
-
react_1.default.createElement("input", { type: "color", value: theme[key], onChange: (e) => setTheme({ ...theme, [key]: e.target.value }), style: { width: 120, height: 28, borderRadius: 8, border: '1px solid #d1d5db', background: '#fff' } })))),
|
|
497
|
-
react_1.default.createElement("label", { style: {
|
|
498
|
-
display: 'grid',
|
|
499
|
-
gridTemplateColumns: '1fr 120px',
|
|
500
|
-
alignItems: 'center',
|
|
501
|
-
gap: 10,
|
|
502
|
-
fontSize: 12,
|
|
503
|
-
margin: '8px 0',
|
|
504
|
-
} },
|
|
505
|
-
react_1.default.createElement("span", null, "Outline style"),
|
|
506
|
-
react_1.default.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end' } },
|
|
507
|
-
react_1.default.createElement("input", { type: "checkbox", checked: theme.isOutlineStyle, onChange: (e) => setTheme({ ...theme, isOutlineStyle: e.target.checked }) }))))))));
|
|
371
|
+
react_1.default.createElement(Footer, null, "Report \u00B7 Privacy"))))));
|
|
508
372
|
}
|
|
509
373
|
exports.default = Simulator;
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
"@linktr.ee/create-link-app": "latest",
|
|
14
14
|
"@linktr.ee/ui-link-kit": "latest",
|
|
15
15
|
"@types/react": "^18.2.8",
|
|
16
|
-
"@types/react-dom": "^18.2.4"
|
|
17
|
-
"iframe-resizer-react": "^1.1.1"
|
|
16
|
+
"@types/react-dom": "^18.2.4"
|
|
18
17
|
},
|
|
19
18
|
"main": "lib/commonjs/index.js",
|
|
20
19
|
"react-native": "src/index.ts",
|