@flung.dev/connect 0.1.2 → 0.4.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.
- package/README.md +224 -12
- package/dist/core/client.d.ts +11 -3
- package/dist/core/client.js +34 -12
- package/dist/core/controller.d.ts +232 -0
- package/dist/core/controller.js +447 -0
- package/dist/core/events.d.ts +25 -0
- package/dist/core/events.js +1 -0
- package/dist/core/index.d.ts +12 -4
- package/dist/core/index.js +7 -3
- package/dist/core/labels.d.ts +96 -0
- package/dist/core/labels.js +50 -0
- package/dist/core/platforms.d.ts +7 -1
- package/dist/core/platforms.js +11 -1
- package/dist/core/qr.d.ts +13 -0
- package/dist/core/qr.js +319 -0
- package/dist/core/types.d.ts +28 -0
- package/dist/core/types.js +1 -0
- package/dist/element/copy.d.ts +3 -39
- package/dist/element/copy.js +2 -32
- package/dist/element/dom.d.ts +29 -8
- package/dist/element/dom.js +77 -8
- package/dist/element/events.d.ts +14 -24
- package/dist/element/flung-connect.d.ts +21 -1
- package/dist/element/flung-connect.js +248 -198
- package/dist/element/marks.d.ts +7 -2
- package/dist/element/marks.js +8 -1
- package/dist/element/styles.d.ts +5 -3
- package/dist/element/styles.js +168 -42
- package/dist/element/tooltip.d.ts +26 -0
- package/dist/element/tooltip.js +135 -0
- package/dist/index.d.ts +2 -4
- package/dist/index.js +0 -1
- package/dist/react/index.d.ts +43 -3
- package/dist/react/index.js +39 -2
- package/dist/react/use-flung-connect.d.ts +13 -0
- package/dist/react/use-flung-connect.js +65 -0
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { createElement, forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef } from 'react';
|
|
1
|
+
import { createElement, forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useSyncExternalStore } from 'react';
|
|
2
|
+
import { initialConnectState } from '../core/controller.js';
|
|
2
3
|
import { defineFlungConnect, TAG_NAME } from '../element/define.js';
|
|
4
|
+
export { useFlungConnect } from './use-flung-connect.js';
|
|
3
5
|
const EVENTS = { 'flung-load': 'onLoad', 'flung-connect': 'onConnect', 'flung-disconnect': 'onDisconnect', 'flung-error': 'onError' };
|
|
4
6
|
const useClientLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
|
|
5
7
|
function FlungConnectInner(props, ref) {
|
|
@@ -36,15 +38,50 @@ function FlungConnectInner(props, ref) {
|
|
|
36
38
|
if (node.token !== props.token)
|
|
37
39
|
node.token = props.token;
|
|
38
40
|
}, [props.token, props.labels]);
|
|
41
|
+
// The element's state, only when a render prop needs it, so a panel without them renders no more often than before.
|
|
42
|
+
const custom = props.renderPlatform !== undefined || props.renderAccount !== undefined;
|
|
43
|
+
const subscribe = useCallback((notify) => {
|
|
44
|
+
const node = element.current;
|
|
45
|
+
if (!custom || node === null)
|
|
46
|
+
return () => undefined;
|
|
47
|
+
node.addEventListener('flung-change', notify);
|
|
48
|
+
return () => node.removeEventListener('flung-change', notify);
|
|
49
|
+
}, [custom]);
|
|
50
|
+
const initial = initialConnectState(props.token !== null);
|
|
51
|
+
const state = useSyncExternalStore(subscribe, () => (custom ? (element.current?.state ?? initial) : initial), () => initial);
|
|
52
|
+
const actions = useMemo(() => {
|
|
53
|
+
const controller = () => element.current?.controller ?? null;
|
|
54
|
+
return {
|
|
55
|
+
connect: (platform, options) => controller()?.connect(platform, options),
|
|
56
|
+
submitHandle: (platform, handle) => controller()?.submitHandle(platform, handle),
|
|
57
|
+
reconnect: (accountId) => controller()?.reconnect(accountId),
|
|
58
|
+
requestDisconnect: (accountId) => controller()?.requestDisconnect(accountId),
|
|
59
|
+
confirmDisconnect: (platform) => controller()?.confirmDisconnect(platform) ?? Promise.resolve(),
|
|
60
|
+
cancel: (platform) => controller()?.cancel(platform),
|
|
61
|
+
dismissNotice: () => controller()?.dismissNotice(),
|
|
62
|
+
refresh: () => controller()?.refresh() ?? Promise.resolve(),
|
|
63
|
+
};
|
|
64
|
+
}, []);
|
|
65
|
+
// Each custom row goes into the light DOM with the element's slot name for it, so your CSS reaches it directly.
|
|
66
|
+
const children = custom
|
|
67
|
+
? state.platforms.flatMap((platform) => [
|
|
68
|
+
props.renderPlatform === undefined ? null : createElement('div', { key: `platform-${platform.platform}`, slot: `platform-${platform.platform}` }, props.renderPlatform({ platform, actions, labels: state.labels })),
|
|
69
|
+
...(props.renderAccount === undefined ? [] : platform.accounts.map((account) => createElement('div', { key: `account-${account.account.id}`, slot: `account-${account.account.id}` }, props.renderAccount?.({ account, platform, actions, labels: state.labels })))),
|
|
70
|
+
])
|
|
71
|
+
: undefined;
|
|
39
72
|
return createElement(TAG_NAME, {
|
|
40
73
|
ref: element,
|
|
41
74
|
'base-url': props.baseUrl,
|
|
42
75
|
platforms: props.platforms?.join(','),
|
|
43
76
|
mode: props.mode,
|
|
44
77
|
theme: props.theme,
|
|
78
|
+
layout: props.layout,
|
|
79
|
+
variants: props.variants,
|
|
80
|
+
unstyled: props.unstyled === true ? '' : undefined,
|
|
45
81
|
branding: props.branding,
|
|
46
82
|
class: props.className,
|
|
47
83
|
style: props.style,
|
|
48
|
-
});
|
|
84
|
+
}, children);
|
|
49
85
|
}
|
|
86
|
+
/** The `<flung-connect>` element as a React component. */
|
|
50
87
|
export const FlungConnect = forwardRef(FlungConnectInner);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ConnectActions, ConnectControllerOptions, ConnectState } from '../core/controller.js';
|
|
2
|
+
/** What `useFlungConnect` takes: the controller's options. Callbacks and a token function may be new on every render. */
|
|
3
|
+
export type UseFlungConnectOptions = ConnectControllerOptions;
|
|
4
|
+
/** What `useFlungConnect` returns: the state to draw, and the actions to call from your own buttons and forms. */
|
|
5
|
+
export type UseFlungConnectResult = ConnectState & ConnectActions;
|
|
6
|
+
/**
|
|
7
|
+
* The connect panel with none of Flung's markup, for drawing every piece with your own components and CSS. It runs a
|
|
8
|
+
* `createConnectController` for as long as the component is mounted, and a new one when the token string, `baseUrl`
|
|
9
|
+
* or whether there is a `fetch` changes. A token function, `fetch` and the callbacks are read fresh on every call, so
|
|
10
|
+
* they need no `useCallback`. Call `connect`, `submitHandle` and `reconnect` straight from a click or submit handler: a
|
|
11
|
+
* browser opens a window only during one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useFlungConnect(options: UseFlungConnectOptions): UseFlungConnectResult;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
|
|
2
|
+
import { createConnectController, initialConnectState } from '../core/controller.js';
|
|
3
|
+
const noSubscribe = () => () => undefined;
|
|
4
|
+
/**
|
|
5
|
+
* The connect panel with none of Flung's markup, for drawing every piece with your own components and CSS. It runs a
|
|
6
|
+
* `createConnectController` for as long as the component is mounted, and a new one when the token string, `baseUrl`
|
|
7
|
+
* or whether there is a `fetch` changes. A token function, `fetch` and the callbacks are read fresh on every call, so
|
|
8
|
+
* they need no `useCallback`. Call `connect`, `submitHandle` and `reconnect` straight from a click or submit handler: a
|
|
9
|
+
* browser opens a window only during one.
|
|
10
|
+
*/
|
|
11
|
+
export function useFlungConnect(options) {
|
|
12
|
+
const latest = useRef(options);
|
|
13
|
+
latest.current = options;
|
|
14
|
+
const current = useRef(null);
|
|
15
|
+
const [controller, setController] = useState(null);
|
|
16
|
+
const { token, baseUrl } = options;
|
|
17
|
+
const tokenKey = token === null ? null : typeof token === 'string' ? `token:${token}` : 'function';
|
|
18
|
+
const hasFetch = options.fetch !== undefined;
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const source = latest.current.token;
|
|
21
|
+
const made = createConnectController({
|
|
22
|
+
token: typeof source === 'function'
|
|
23
|
+
? () => {
|
|
24
|
+
const now = latest.current.token;
|
|
25
|
+
return typeof now === 'function' ? now() : Promise.resolve(now ?? '');
|
|
26
|
+
}
|
|
27
|
+
: source,
|
|
28
|
+
baseUrl,
|
|
29
|
+
platforms: latest.current.platforms,
|
|
30
|
+
mode: latest.current.mode,
|
|
31
|
+
labels: latest.current.labels,
|
|
32
|
+
readRedirect: latest.current.readRedirect,
|
|
33
|
+
fetch: hasFetch ? (input, init) => (latest.current.fetch ?? fetch)(input, init) : undefined,
|
|
34
|
+
onLoad: (detail) => latest.current.onLoad?.(detail),
|
|
35
|
+
onConnect: (detail) => latest.current.onConnect?.(detail),
|
|
36
|
+
onDisconnect: (detail) => latest.current.onDisconnect?.(detail),
|
|
37
|
+
onError: (detail) => latest.current.onError?.(detail),
|
|
38
|
+
});
|
|
39
|
+
current.current = made;
|
|
40
|
+
setController(made);
|
|
41
|
+
return () => {
|
|
42
|
+
made.destroy();
|
|
43
|
+
if (current.current === made)
|
|
44
|
+
current.current = null;
|
|
45
|
+
};
|
|
46
|
+
}, [tokenKey, baseUrl, hasFetch]);
|
|
47
|
+
const platformsKey = options.platforms?.join(',') ?? '';
|
|
48
|
+
const labelsKey = JSON.stringify(options.labels ?? {});
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
controller?.configure({ platforms: latest.current.platforms ?? null, mode: latest.current.mode ?? 'popup', labels: latest.current.labels });
|
|
51
|
+
}, [controller, platformsKey, options.mode, labelsKey]);
|
|
52
|
+
const initial = initialConnectState(token !== null);
|
|
53
|
+
const state = useSyncExternalStore(controller?.subscribe ?? noSubscribe, controller?.getState ?? (() => initial), () => initial);
|
|
54
|
+
const actions = useMemo(() => ({
|
|
55
|
+
connect: (platform, options) => current.current?.connect(platform, options),
|
|
56
|
+
submitHandle: (platform, handle) => current.current?.submitHandle(platform, handle),
|
|
57
|
+
reconnect: (accountId) => current.current?.reconnect(accountId),
|
|
58
|
+
requestDisconnect: (accountId) => current.current?.requestDisconnect(accountId),
|
|
59
|
+
confirmDisconnect: (platform) => current.current?.confirmDisconnect(platform) ?? Promise.resolve(),
|
|
60
|
+
cancel: (platform) => current.current?.cancel(platform),
|
|
61
|
+
dismissNotice: () => current.current?.dismissNotice(),
|
|
62
|
+
refresh: () => current.current?.refresh() ?? Promise.resolve(),
|
|
63
|
+
}), []);
|
|
64
|
+
return { ...state, ...actions };
|
|
65
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flung.dev/connect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Let people connect and disconnect their social accounts from your page: a <flung-connect> web component and a React component for Flung, with no runtime dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|