@tamagui/portal 1.0.1-beta.21 → 1.0.1-beta.211

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 (43) hide show
  1. package/dist/cjs/GorhomPortal.js +266 -0
  2. package/dist/cjs/GorhomPortal.js.map +7 -0
  3. package/dist/cjs/Portal.js +19 -31
  4. package/dist/cjs/Portal.js.map +2 -2
  5. package/dist/cjs/Portal.native.js +66 -0
  6. package/dist/cjs/Portal.native.js.map +7 -0
  7. package/dist/cjs/PortalProps.js +17 -0
  8. package/dist/cjs/PortalProps.js.map +7 -0
  9. package/dist/cjs/index.js +2 -0
  10. package/dist/cjs/index.js.map +2 -2
  11. package/dist/esm/GorhomPortal.js +237 -0
  12. package/dist/esm/GorhomPortal.js.map +7 -0
  13. package/dist/esm/Portal.js +11 -15
  14. package/dist/esm/Portal.js.map +2 -2
  15. package/dist/esm/Portal.native.js +36 -0
  16. package/dist/esm/Portal.native.js.map +7 -0
  17. package/dist/esm/PortalProps.js +1 -0
  18. package/dist/esm/PortalProps.js.map +7 -0
  19. package/dist/esm/index.js +1 -0
  20. package/dist/esm/index.js.map +2 -2
  21. package/dist/jsx/GorhomPortal.js +223 -0
  22. package/dist/jsx/GorhomPortal.js.map +7 -0
  23. package/dist/jsx/Portal.js +6 -12
  24. package/dist/jsx/Portal.js.map +7 -0
  25. package/dist/jsx/Portal.native.js +21 -0
  26. package/dist/jsx/Portal.native.js.map +7 -0
  27. package/dist/jsx/PortalProps.js +1 -0
  28. package/dist/jsx/PortalProps.js.map +7 -0
  29. package/dist/jsx/index.js +2 -0
  30. package/dist/jsx/index.js.map +7 -0
  31. package/package.json +9 -7
  32. package/src/GorhomPortal.tsx +402 -0
  33. package/src/Portal.native.tsx +40 -0
  34. package/src/Portal.tsx +37 -0
  35. package/src/PortalProps.tsx +6 -0
  36. package/src/index.tsx +2 -0
  37. package/types/GorhomPortal.d.ts +106 -0
  38. package/types/Portal.d.ts +3 -3
  39. package/types/Portal.native.d.ts +3 -0
  40. package/types/PortalProps.d.ts +6 -0
  41. package/types/index.d.ts +1 -0
  42. package/types/Portal.d.ts.map +0 -1
  43. package/types/index.d.ts.map +0 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/GorhomPortal.tsx"],
4
+ "sourcesContent": ["// from https://github.com/gorhom/react-native-portal\n// MIT License Copyright (c) 2020 Mo Gorhom\n// fixing SSR issue\n\nimport { startTransition, useDidFinishSSR } from '@tamagui/core'\nimport { ReactNode, useMemo, useRef } from 'react'\nimport React, { createContext, memo, useCallback, useContext, useEffect, useReducer } from 'react'\n\ninterface PortalType {\n name: string\n node: ReactNode\n}\n\nenum ACTIONS {\n REGISTER_HOST,\n DEREGISTER_HOST,\n ADD_UPDATE_PORTAL,\n REMOVE_PORTAL,\n}\n\nconst INITIAL_STATE = {}\n\nexport { ACTIONS, INITIAL_STATE }\n\nexport interface AddUpdatePortalAction {\n type: ACTIONS\n hostName: string\n portalName: string\n node: ReactNode\n}\n\nexport interface RemovePortalAction {\n type: ACTIONS\n hostName: string\n portalName: string\n}\n\nexport interface RegisterHostAction {\n type: ACTIONS\n hostName: string\n}\n\nexport interface UnregisterHostAction {\n type: ACTIONS\n hostName: string\n}\n\nexport type ActionTypes =\n | AddUpdatePortalAction\n | RemovePortalAction\n | RegisterHostAction\n | UnregisterHostAction\n\nconst registerHost = (state: Record<string, Array<PortalType>>, hostName: string) => {\n if (!(hostName in state)) {\n state[hostName] = []\n }\n return state\n}\n\nconst deregisterHost = (state: Record<string, Array<PortalType>>, hostName: string) => {\n delete state[hostName]\n return state\n}\n\nconst addUpdatePortal = (\n state: Record<string, Array<PortalType>>,\n hostName: string,\n portalName: string,\n node: any\n) => {\n if (!(hostName in state)) {\n state = registerHost(state, hostName)\n }\n\n /**\n * updated portal, if it was already added.\n */\n const index = state[hostName].findIndex((item) => item.name === portalName)\n if (index !== -1) {\n state[hostName][index].node = node\n } else {\n state[hostName].push({\n name: portalName,\n node,\n })\n }\n return state\n}\n\nconst removePortal = (\n state: Record<string, Array<PortalType>>,\n hostName: string,\n portalName: string\n) => {\n if (!(hostName in state)) {\n console.log(`Failed to remove portal '${portalName}', '${hostName}' was not registered!`)\n return state\n }\n\n const index = state[hostName].findIndex((item) => item.name === portalName)\n if (index !== -1) state[hostName].splice(index, 1)\n return state\n}\n\nconst reducer = (state: Record<string, Array<PortalType>>, action: ActionTypes) => {\n const { type } = action\n switch (type) {\n case ACTIONS.REGISTER_HOST:\n return registerHost({ ...state }, action.hostName)\n case ACTIONS.DEREGISTER_HOST:\n return deregisterHost({ ...state }, action.hostName)\n case ACTIONS.ADD_UPDATE_PORTAL:\n return addUpdatePortal(\n { ...state },\n action.hostName,\n (action as AddUpdatePortalAction).portalName,\n (action as AddUpdatePortalAction).node\n )\n case ACTIONS.REMOVE_PORTAL:\n return removePortal({ ...state }, action.hostName, (action as RemovePortalAction).portalName)\n default:\n return state\n }\n}\n\nconst PortalStateContext = createContext<Record<string, Array<PortalType>> | null>(null)\nconst PortalDispatchContext = createContext<React.Dispatch<ActionTypes> | null>(null)\n\nconst usePortalState = (hostName: string) => {\n const state = useContext(PortalStateContext)\n\n if (state === null) {\n throw new Error(\n \"'PortalStateContext' cannot be null, please add 'PortalProvider' to the root component.\"\n )\n }\n\n return state[hostName] || []\n}\n\nexport const usePortal = (hostName = 'root') => {\n const dispatch = useContext(PortalDispatchContext)\n\n if (dispatch === null) {\n throw new Error(\n \"'PortalDispatchContext' cannot be null, please add 'PortalProvider' to the root component.\"\n )\n }\n\n //#region methods\n const registerHost = useCallback(() => {\n dispatch({\n type: ACTIONS.REGISTER_HOST,\n hostName: hostName,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const deregisterHost = useCallback(() => {\n dispatch({\n type: ACTIONS.DEREGISTER_HOST,\n hostName: hostName,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const addUpdatePortal = useCallback((name: string, node: ReactNode) => {\n dispatch({\n type: ACTIONS.ADD_UPDATE_PORTAL,\n hostName,\n portalName: name,\n node,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const removePortal = useCallback((name: string) => {\n dispatch({\n type: ACTIONS.REMOVE_PORTAL,\n hostName,\n portalName: name,\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n //#endregion\n\n return {\n registerHost,\n deregisterHost,\n addPortal: addUpdatePortal,\n updatePortal: addUpdatePortal,\n removePortal,\n }\n}\n\nexport interface PortalProviderProps {\n /**\n * Defines whether to add a default root host or not.\n *\n * @default true\n * @type boolean\n */\n shouldAddRootHost?: boolean\n\n /**\n * Defines the root portal host name.\n *\n * @default \"root\"\n * @type string\n */\n rootHostName?: string\n\n children: ReactNode | ReactNode[]\n}\n\nconst PortalProviderComponent = ({\n rootHostName = 'root',\n shouldAddRootHost = true,\n children,\n}: PortalProviderProps) => {\n const [state, dispatch] = useReducer(reducer, INITIAL_STATE)\n const transitionDispatch = useMemo(() => {\n const next = (value: any) => {\n startTransition(() => {\n dispatch(value)\n })\n }\n return next as typeof dispatch\n }, [dispatch])\n return (\n <PortalDispatchContext.Provider value={transitionDispatch}>\n <PortalStateContext.Provider value={state}>\n {children}\n {shouldAddRootHost && <PortalHost name={rootHostName} />}\n </PortalStateContext.Provider>\n </PortalDispatchContext.Provider>\n )\n}\n\nexport const PortalProvider = memo(PortalProviderComponent)\nPortalProvider.displayName = 'PortalProvider'\n\nexport interface PortalHostProps {\n /**\n * Host's key or name to be used as an identifier.\n * @type string\n */\n name: string\n}\n\nconst PortalHostComponent = ({ name }: PortalHostProps) => {\n //#region hooks\n const isServer = !useDidFinishSSR()\n const state = usePortalState(name)\n const { registerHost, deregisterHost } = usePortal(name)\n //#endregion\n\n //#region effects\n useEffect(() => {\n if (isServer) return\n registerHost()\n return () => {\n deregisterHost()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isServer])\n //#endregion\n\n //#region render\n return <>{state.map((item) => item.node)}</>\n //#endregion\n}\n\nexport const PortalHost = memo(PortalHostComponent)\nPortalHost.displayName = 'PortalHost'\n\nexport interface PortalItemProps {\n /**\n * Portal's key or name to be used as an identifier.\n * @type string\n * @default nanoid generated unique key.\n */\n name?: string\n /**\n * Host's name to teleport the portal content to.\n * @type string\n * @default 'root'\n */\n hostName?: string\n /**\n * Override internal mounting functionality, this is useful\n * if you want to trigger any action before mounting the portal content.\n * @type (mount?: () => void) => void\n * @default undefined\n */\n handleOnMount?: (mount: () => void) => void\n /**\n * Override internal un-mounting functionality, this is useful\n * if you want to trigger any action before un-mounting the portal content.\n * @type (unmount?: () => void) => void\n * @default undefined\n */\n handleOnUnmount?: (unmount: () => void) => void\n /**\n * Override internal updating functionality, this is useful\n * if you want to trigger any action before updating the portal content.\n * @type (update?: () => void) => void\n * @default undefined\n */\n handleOnUpdate?: (update: () => void) => void\n /**\n * Portal's content.\n * @type ReactNode\n * @default undefined\n */\n children?: ReactNode | ReactNode[]\n}\n\nconst PortalComponent = ({\n name: _providedName,\n hostName,\n handleOnMount: _providedHandleOnMount,\n handleOnUnmount: _providedHandleOnUnmount,\n handleOnUpdate: _providedHandleOnUpdate,\n children,\n}: PortalItemProps) => {\n //#region hooks\n const { addPortal: addUpdatePortal, removePortal } = usePortal(hostName)\n //#endregion\n\n let id = 0\n const nanoid = () => {\n id = (id + 1) % Number.MAX_SAFE_INTEGER\n return `${id}`\n }\n\n //#region variables\n const name = useMemo(() => _providedName || nanoid(), [_providedName])\n //#endregion\n\n //#region refs\n const handleOnMountRef = useRef<Function>()\n const handleOnUnmountRef = useRef<Function>()\n const handleOnUpdateRef = useRef<Function>()\n //#endregion\n\n //#region callbacks\n const handleOnMount = useCallback(() => {\n if (_providedHandleOnMount) {\n _providedHandleOnMount(() => addUpdatePortal(name, children))\n } else {\n addUpdatePortal(name, children)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [_providedHandleOnMount, addUpdatePortal])\n handleOnMountRef.current = handleOnMount\n\n const handleOnUnmount = useCallback(() => {\n if (_providedHandleOnUnmount) {\n _providedHandleOnUnmount(() => removePortal(name))\n } else {\n removePortal(name)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [_providedHandleOnUnmount, removePortal])\n handleOnUnmountRef.current = handleOnUnmount\n\n const handleOnUpdate = useCallback(() => {\n if (_providedHandleOnUpdate) {\n _providedHandleOnUpdate(() => addUpdatePortal(name, children))\n } else {\n addUpdatePortal(name, children)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [_providedHandleOnUpdate, addUpdatePortal, children])\n handleOnUpdateRef.current = handleOnUpdate\n //#endregion\n\n //#region effects\n useEffect(() => {\n handleOnMountRef.current?.()\n return () => {\n handleOnUnmountRef.current?.()\n\n // remove callbacks refs\n handleOnMountRef.current = undefined\n handleOnUnmountRef.current = undefined\n handleOnUpdateRef.current = undefined\n }\n }, [])\n useEffect(() => {\n handleOnUpdateRef.current?.()\n }, [children])\n //#endregion\n\n return null\n}\n\nexport const PortalItem = memo(PortalComponent)\nPortalItem.displayName = 'Portal'\n"],
5
+ "mappings": "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",
6
+ "names": ["ACTIONS", "registerHost", "deregisterHost", "addUpdatePortal", "removePortal"]
7
+ }
@@ -1,26 +1,20 @@
1
- var __defProp = Object.defineProperty;
2
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
1
  import "@tamagui/polyfill-dev";
4
2
  import { isWeb, useIsomorphicLayoutEffect } from "@tamagui/core";
5
3
  import { YStack } from "@tamagui/stacks";
6
4
  import * as React from "react";
7
5
  import { createPortal } from "react-dom";
8
- import { Modal } from "react-native";
9
- const Portal = /* @__PURE__ */ __name((props) => {
10
- const contents = <YStack pointerEvents="none" fullscreen {...props} />;
11
- if (!isWeb) {
12
- return <Modal visible>{contents}</Modal>;
13
- }
6
+ const Portal = ({ host = globalThis.document?.body, ...props }) => {
7
+ const contents = <YStack pointerEvents="box-none" contain="strict" fullscreen position={isWeb ? "fixed" : "absolute"} maxWidth={isWeb ? "100vw" : "100%"} maxHeight={isWeb ? "100vh" : "100%"} {...props} />;
14
8
  const [hostElement, setHostElement] = React.useState(null);
15
9
  useIsomorphicLayoutEffect(() => {
16
- var _a;
17
- setHostElement((_a = globalThis.document) == null ? void 0 : _a.body);
18
- }, []);
10
+ setHostElement(host);
11
+ }, [host]);
19
12
  if (hostElement) {
20
13
  return createPortal(contents, hostElement);
21
14
  }
22
15
  return null;
23
- }, "Portal");
16
+ };
24
17
  export {
25
18
  Portal
26
19
  };
20
+ //# sourceMappingURL=Portal.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/Portal.tsx"],
4
+ "sourcesContent": ["/* eslint-disable react-hooks/rules-of-hooks */\nimport '@tamagui/polyfill-dev'\n\nimport { isWeb, useIsomorphicLayoutEffect } from '@tamagui/core'\nimport { YStack } from '@tamagui/stacks'\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { PortalProps } from './PortalProps'\n\nexport const Portal = ({ host = globalThis.document?.body, ...props }: PortalProps) => {\n const contents = (\n <YStack\n pointerEvents=\"box-none\"\n contain=\"strict\"\n fullscreen\n // @ts-expect-error ok on web\n position={isWeb ? 'fixed' : 'absolute'}\n maxWidth={isWeb ? '100vw' : '100%'}\n maxHeight={isWeb ? '100vh' : '100%'}\n {...props}\n />\n )\n\n const [hostElement, setHostElement] = React.useState<any>(null)\n\n useIsomorphicLayoutEffect(() => {\n setHostElement(host)\n }, [host])\n\n if (hostElement) {\n return createPortal(contents, hostElement)\n }\n\n // ssr return null\n return null\n}\n"],
5
+ "mappings": "AACA,OAAO;AAEP,SAAS,OAAO,iCAAiC;AACjD,SAAS,cAAc;AACvB,YAAY,WAAW;AACvB,SAAS,oBAAoB;AAItB,MAAM,SAAS,CAAC,EAAE,OAAO,WAAW,UAAU,SAAS,MAAM,MAAmB;AACrF,QAAM,WACJ,CAAC,OACC,cAAc,WACd,QAAQ,SACR,WAEA,UAAU,QAAQ,UAAU,YAC5B,UAAU,QAAQ,UAAU,QAC5B,WAAW,QAAQ,UAAU,YACzB,OACN;AAGF,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAc,IAAI;AAE9D,4BAA0B,MAAM;AAC9B,mBAAe,IAAI;AAAA,EACrB,GAAG,CAAC,IAAI,CAAC;AAET,MAAI,aAAa;AACf,WAAO,aAAa,UAAU,WAAW;AAAA,EAC3C;AAGA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,21 @@
1
+ import { YStack } from "@tamagui/stacks";
2
+ import * as React from "react";
3
+ import { RootTagContext } from "react-native";
4
+ import { createPortal } from "react-native/Libraries/Renderer/shims/ReactNative";
5
+ const Portal = (props) => {
6
+ const rootTag = React.useContext(RootTagContext);
7
+ const contents = <YStack pointerEvents="box-none" fullscreen position="absolute" maxWidth="100%" zIndex={1e5} {...props} />;
8
+ if (rootTag) {
9
+ return createPortal(contents, rootTag);
10
+ }
11
+ if (process.env.NODE_ENV === "development") {
12
+ console.warn(
13
+ `Missing rootTag, this is a bug - you may need a different React Native version, or to avoid using "modal" on native.`
14
+ );
15
+ }
16
+ return null;
17
+ };
18
+ export {
19
+ Portal
20
+ };
21
+ //# sourceMappingURL=Portal.native.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/Portal.native.tsx"],
4
+ "sourcesContent": ["import { YStack, YStackProps } from '@tamagui/stacks'\nimport * as React from 'react'\n// @ts-ignore\nimport { RootTagContext } from 'react-native'\nimport { createPortal } from 'react-native/Libraries/Renderer/shims/ReactNative'\n\nimport { PortalProps } from './PortalProps'\n\nexport const Portal = (props: PortalProps) => {\n const rootTag = React.useContext(RootTagContext)\n\n const contents = (\n <YStack\n pointerEvents=\"box-none\"\n fullscreen\n position=\"absolute\"\n maxWidth=\"100%\"\n zIndex={100000}\n {...props}\n />\n )\n\n if (rootTag) {\n return createPortal(contents, rootTag)\n }\n\n if (process.env.NODE_ENV === 'development') {\n // eslint-disable-next-line no-console\n console.warn(\n `Missing rootTag, this is a bug - you may need a different React Native version, or to avoid using \"modal\" on native.`\n )\n }\n\n return null\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAA2B;AACpC,YAAY,WAAW;AAEvB,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAItB,MAAM,SAAS,CAAC,UAAuB;AAC5C,QAAM,UAAU,MAAM,WAAW,cAAc;AAE/C,QAAM,WACJ,CAAC,OACC,cAAc,WACd,WACA,SAAS,WACT,SAAS,OACT,QAAQ,SACJ,OACN;AAGF,MAAI,SAAS;AACX,WAAO,aAAa,UAAU,OAAO;AAAA,EACvC;AAEA,MAAI,QAAQ,IAAI,aAAa,eAAe;AAE1C,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=PortalProps.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
package/dist/jsx/index.js CHANGED
@@ -1 +1,3 @@
1
1
  export * from "./Portal";
2
+ export * from "./GorhomPortal";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.tsx"],
4
+ "sourcesContent": ["export * from './Portal'\nexport * from './GorhomPortal'\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,24 +1,26 @@
1
1
  {
2
2
  "name": "@tamagui/portal",
3
- "version": "1.0.1-beta.21",
4
- "sideEffects": true,
3
+ "version": "1.0.1-beta.211",
5
4
  "source": "src/index.ts",
6
- "typings": "types",
5
+ "types": "./types/index.d.ts",
7
6
  "main": "dist/cjs",
8
7
  "module": "dist/esm",
9
- "module:jsx": "dist/jsx",
10
8
  "files": [
9
+ "src",
11
10
  "types",
12
11
  "dist"
13
12
  ],
14
13
  "scripts": {
15
14
  "build": "tamagui-build",
16
15
  "watch": "tamagui-build --watch",
16
+ "lint": "eslint",
17
+ "lint:fix": "yarn lint --fix",
17
18
  "clean": "tamagui-build clean",
18
19
  "clean:build": "tamagui-build clean:build"
19
20
  },
20
21
  "dependencies": {
21
- "@tamagui/stacks": "^1.0.1-beta.21"
22
+ "@tamagui/core": "^1.0.1-beta.211",
23
+ "@tamagui/stacks": "^1.0.1-beta.211"
22
24
  },
23
25
  "peerDependencies": {
24
26
  "react": "*",
@@ -26,8 +28,8 @@
26
28
  "react-native": "*"
27
29
  },
28
30
  "devDependencies": {
29
- "@tamagui/build": "^1.0.1-beta.21",
30
- "@types/react-native": "^0.67.3",
31
+ "@tamagui/build": "^1.0.1-beta.211",
32
+ "@types/react-native": "^0.69.2",
31
33
  "react": "*",
32
34
  "react-dom": "*",
33
35
  "react-native": "*"
@@ -0,0 +1,402 @@
1
+ // from https://github.com/gorhom/react-native-portal
2
+ // MIT License Copyright (c) 2020 Mo Gorhom
3
+ // fixing SSR issue
4
+
5
+ import { useDidFinishSSR } from '@tamagui/core'
6
+ import { ReactNode, startTransition, useMemo, useRef } from 'react'
7
+ import React, { createContext, memo, useCallback, useContext, useEffect, useReducer } from 'react'
8
+
9
+ interface PortalType {
10
+ name: string
11
+ node: ReactNode
12
+ }
13
+
14
+ enum ACTIONS {
15
+ REGISTER_HOST,
16
+ DEREGISTER_HOST,
17
+ ADD_UPDATE_PORTAL,
18
+ REMOVE_PORTAL,
19
+ }
20
+
21
+ const INITIAL_STATE = {}
22
+
23
+ export { ACTIONS, INITIAL_STATE }
24
+
25
+ export interface AddUpdatePortalAction {
26
+ type: ACTIONS
27
+ hostName: string
28
+ portalName: string
29
+ node: ReactNode
30
+ }
31
+
32
+ export interface RemovePortalAction {
33
+ type: ACTIONS
34
+ hostName: string
35
+ portalName: string
36
+ }
37
+
38
+ export interface RegisterHostAction {
39
+ type: ACTIONS
40
+ hostName: string
41
+ }
42
+
43
+ export interface UnregisterHostAction {
44
+ type: ACTIONS
45
+ hostName: string
46
+ }
47
+
48
+ export type ActionTypes =
49
+ | AddUpdatePortalAction
50
+ | RemovePortalAction
51
+ | RegisterHostAction
52
+ | UnregisterHostAction
53
+
54
+ const registerHost = (state: Record<string, Array<PortalType>>, hostName: string) => {
55
+ if (!(hostName in state)) {
56
+ state[hostName] = []
57
+ }
58
+ return state
59
+ }
60
+
61
+ const deregisterHost = (state: Record<string, Array<PortalType>>, hostName: string) => {
62
+ delete state[hostName]
63
+ return state
64
+ }
65
+
66
+ const addUpdatePortal = (
67
+ state: Record<string, Array<PortalType>>,
68
+ hostName: string,
69
+ portalName: string,
70
+ node: any
71
+ ) => {
72
+ if (!(hostName in state)) {
73
+ state = registerHost(state, hostName)
74
+ }
75
+
76
+ /**
77
+ * updated portal, if it was already added.
78
+ */
79
+ const index = state[hostName].findIndex((item) => item.name === portalName)
80
+ if (index !== -1) {
81
+ state[hostName][index].node = node
82
+ } else {
83
+ state[hostName].push({
84
+ name: portalName,
85
+ node,
86
+ })
87
+ }
88
+ return state
89
+ }
90
+
91
+ const removePortal = (
92
+ state: Record<string, Array<PortalType>>,
93
+ hostName: string,
94
+ portalName: string
95
+ ) => {
96
+ if (!(hostName in state)) {
97
+ // eslint-disable-next-line no-console
98
+ console.log(`Failed to remove portal '${portalName}', '${hostName}' was not registered!`)
99
+ return state
100
+ }
101
+
102
+ const index = state[hostName].findIndex((item) => item.name === portalName)
103
+ if (index !== -1) state[hostName].splice(index, 1)
104
+ return state
105
+ }
106
+
107
+ const reducer = (state: Record<string, Array<PortalType>>, action: ActionTypes) => {
108
+ const { type } = action
109
+ switch (type) {
110
+ case ACTIONS.REGISTER_HOST:
111
+ return registerHost({ ...state }, action.hostName)
112
+ case ACTIONS.DEREGISTER_HOST:
113
+ return deregisterHost({ ...state }, action.hostName)
114
+ case ACTIONS.ADD_UPDATE_PORTAL:
115
+ return addUpdatePortal(
116
+ { ...state },
117
+ action.hostName,
118
+ (action as AddUpdatePortalAction).portalName,
119
+ (action as AddUpdatePortalAction).node
120
+ )
121
+ case ACTIONS.REMOVE_PORTAL:
122
+ return removePortal({ ...state }, action.hostName, (action as RemovePortalAction).portalName)
123
+ default:
124
+ return state
125
+ }
126
+ }
127
+
128
+ const PortalStateContext = createContext<Record<string, Array<PortalType>> | null>(null)
129
+ const PortalDispatchContext = createContext<React.Dispatch<ActionTypes> | null>(null)
130
+
131
+ const usePortalState = (hostName: string) => {
132
+ const state = useContext(PortalStateContext)
133
+
134
+ if (state === null) {
135
+ throw new Error(
136
+ "'PortalStateContext' cannot be null, please add 'PortalProvider' to the root component."
137
+ )
138
+ }
139
+
140
+ return state[hostName] || []
141
+ }
142
+
143
+ export const usePortal = (hostName = 'root') => {
144
+ const dispatch = useContext(PortalDispatchContext)
145
+
146
+ if (dispatch === null) {
147
+ throw new Error(
148
+ "'PortalDispatchContext' cannot be null, please add 'PortalProvider' to the root component."
149
+ )
150
+ }
151
+
152
+ //#region methods
153
+ const registerHost = useCallback(() => {
154
+ dispatch({
155
+ type: ACTIONS.REGISTER_HOST,
156
+ hostName: hostName,
157
+ })
158
+ // eslint-disable-next-line react-hooks/exhaustive-deps
159
+ }, [])
160
+
161
+ const deregisterHost = useCallback(() => {
162
+ dispatch({
163
+ type: ACTIONS.DEREGISTER_HOST,
164
+ hostName: hostName,
165
+ })
166
+ // eslint-disable-next-line react-hooks/exhaustive-deps
167
+ }, [])
168
+
169
+ const addUpdatePortal = useCallback((name: string, node: ReactNode) => {
170
+ dispatch({
171
+ type: ACTIONS.ADD_UPDATE_PORTAL,
172
+ hostName,
173
+ portalName: name,
174
+ node,
175
+ })
176
+ // eslint-disable-next-line react-hooks/exhaustive-deps
177
+ }, [])
178
+
179
+ const removePortal = useCallback((name: string) => {
180
+ dispatch({
181
+ type: ACTIONS.REMOVE_PORTAL,
182
+ hostName,
183
+ portalName: name,
184
+ })
185
+ // eslint-disable-next-line react-hooks/exhaustive-deps
186
+ }, [])
187
+ //#endregion
188
+
189
+ return {
190
+ registerHost,
191
+ deregisterHost,
192
+ addPortal: addUpdatePortal,
193
+ updatePortal: addUpdatePortal,
194
+ removePortal,
195
+ }
196
+ }
197
+
198
+ export interface PortalProviderProps {
199
+ /**
200
+ * Defines whether to add a default root host or not.
201
+ *
202
+ * @default true
203
+ * @type boolean
204
+ */
205
+ shouldAddRootHost?: boolean
206
+
207
+ /**
208
+ * Defines the root portal host name.
209
+ *
210
+ * @default "root"
211
+ * @type string
212
+ */
213
+ rootHostName?: string
214
+
215
+ children: ReactNode | ReactNode[]
216
+ }
217
+
218
+ const PortalProviderComponent = ({
219
+ rootHostName = 'root',
220
+ shouldAddRootHost = true,
221
+ children,
222
+ }: PortalProviderProps) => {
223
+ const [state, dispatch] = useReducer(reducer, INITIAL_STATE)
224
+ const transitionDispatch = useMemo(() => {
225
+ const next = (value: any) => {
226
+ startTransition(() => {
227
+ dispatch(value)
228
+ })
229
+ }
230
+ return next as typeof dispatch
231
+ }, [dispatch])
232
+ return (
233
+ <PortalDispatchContext.Provider value={transitionDispatch}>
234
+ <PortalStateContext.Provider value={state}>
235
+ {children}
236
+ {shouldAddRootHost && <PortalHost name={rootHostName} />}
237
+ </PortalStateContext.Provider>
238
+ </PortalDispatchContext.Provider>
239
+ )
240
+ }
241
+
242
+ export const PortalProvider = memo(PortalProviderComponent)
243
+ PortalProvider.displayName = 'PortalProvider'
244
+
245
+ export interface PortalHostProps {
246
+ /**
247
+ * Host's key or name to be used as an identifier.
248
+ * @type string
249
+ */
250
+ name: string
251
+ }
252
+
253
+ const PortalHostComponent = ({ name }: PortalHostProps) => {
254
+ //#region hooks
255
+ const isServer = !useDidFinishSSR()
256
+ const state = usePortalState(name)
257
+ const { registerHost, deregisterHost } = usePortal(name)
258
+ //#endregion
259
+
260
+ //#region effects
261
+ useEffect(() => {
262
+ if (isServer) return
263
+ registerHost()
264
+ return () => {
265
+ deregisterHost()
266
+ }
267
+ // eslint-disable-next-line react-hooks/exhaustive-deps
268
+ }, [isServer])
269
+ //#endregion
270
+
271
+ //#region render
272
+ return <>{state.map((item) => item.node)}</>
273
+ //#endregion
274
+ }
275
+
276
+ export const PortalHost = memo(PortalHostComponent)
277
+ PortalHost.displayName = 'PortalHost'
278
+
279
+ export interface PortalItemProps {
280
+ /**
281
+ * Portal's key or name to be used as an identifier.
282
+ * @type string
283
+ * @default nanoid generated unique key.
284
+ */
285
+ name?: string
286
+ /**
287
+ * Host's name to teleport the portal content to.
288
+ * @type string
289
+ * @default 'root'
290
+ */
291
+ hostName?: string
292
+ /**
293
+ * Override internal mounting functionality, this is useful
294
+ * if you want to trigger any action before mounting the portal content.
295
+ * @type (mount?: () => void) => void
296
+ * @default undefined
297
+ */
298
+ handleOnMount?: (mount: () => void) => void
299
+ /**
300
+ * Override internal un-mounting functionality, this is useful
301
+ * if you want to trigger any action before un-mounting the portal content.
302
+ * @type (unmount?: () => void) => void
303
+ * @default undefined
304
+ */
305
+ handleOnUnmount?: (unmount: () => void) => void
306
+ /**
307
+ * Override internal updating functionality, this is useful
308
+ * if you want to trigger any action before updating the portal content.
309
+ * @type (update?: () => void) => void
310
+ * @default undefined
311
+ */
312
+ handleOnUpdate?: (update: () => void) => void
313
+ /**
314
+ * Portal's content.
315
+ * @type ReactNode
316
+ * @default undefined
317
+ */
318
+ children?: ReactNode | ReactNode[]
319
+ }
320
+
321
+ const PortalComponent = ({
322
+ name: _providedName,
323
+ hostName,
324
+ handleOnMount: _providedHandleOnMount,
325
+ handleOnUnmount: _providedHandleOnUnmount,
326
+ handleOnUpdate: _providedHandleOnUpdate,
327
+ children,
328
+ }: PortalItemProps) => {
329
+ //#region hooks
330
+ const { addPortal: addUpdatePortal, removePortal } = usePortal(hostName)
331
+ //#endregion
332
+
333
+ let id = 0
334
+ const nanoid = () => {
335
+ id = (id + 1) % Number.MAX_SAFE_INTEGER
336
+ return `${id}`
337
+ }
338
+
339
+ //#region variables
340
+ const name = useMemo(() => _providedName || nanoid(), [_providedName])
341
+ //#endregion
342
+
343
+ //#region refs
344
+ const handleOnMountRef = useRef<Function>()
345
+ const handleOnUnmountRef = useRef<Function>()
346
+ const handleOnUpdateRef = useRef<Function>()
347
+ //#endregion
348
+
349
+ //#region callbacks
350
+ const handleOnMount = useCallback(() => {
351
+ if (_providedHandleOnMount) {
352
+ _providedHandleOnMount(() => addUpdatePortal(name, children))
353
+ } else {
354
+ addUpdatePortal(name, children)
355
+ }
356
+ // eslint-disable-next-line react-hooks/exhaustive-deps
357
+ }, [_providedHandleOnMount, addUpdatePortal])
358
+ handleOnMountRef.current = handleOnMount
359
+
360
+ const handleOnUnmount = useCallback(() => {
361
+ if (_providedHandleOnUnmount) {
362
+ _providedHandleOnUnmount(() => removePortal(name))
363
+ } else {
364
+ removePortal(name)
365
+ }
366
+ // eslint-disable-next-line react-hooks/exhaustive-deps
367
+ }, [_providedHandleOnUnmount, removePortal])
368
+ handleOnUnmountRef.current = handleOnUnmount
369
+
370
+ const handleOnUpdate = useCallback(() => {
371
+ if (_providedHandleOnUpdate) {
372
+ _providedHandleOnUpdate(() => addUpdatePortal(name, children))
373
+ } else {
374
+ addUpdatePortal(name, children)
375
+ }
376
+ // eslint-disable-next-line react-hooks/exhaustive-deps
377
+ }, [_providedHandleOnUpdate, addUpdatePortal, children])
378
+ handleOnUpdateRef.current = handleOnUpdate
379
+ //#endregion
380
+
381
+ //#region effects
382
+ useEffect(() => {
383
+ handleOnMountRef.current?.()
384
+ return () => {
385
+ handleOnUnmountRef.current?.()
386
+
387
+ // remove callbacks refs
388
+ handleOnMountRef.current = undefined
389
+ handleOnUnmountRef.current = undefined
390
+ handleOnUpdateRef.current = undefined
391
+ }
392
+ }, [])
393
+ useEffect(() => {
394
+ handleOnUpdateRef.current?.()
395
+ }, [children])
396
+ //#endregion
397
+
398
+ return null
399
+ }
400
+
401
+ export const PortalItem = memo(PortalComponent)
402
+ PortalItem.displayName = 'Portal'
@@ -0,0 +1,40 @@
1
+ import { YStack } from '@tamagui/stacks'
2
+ import * as React from 'react'
3
+ // @ts-ignore
4
+ import { Platform, RootTagContext } from 'react-native'
5
+ import { createPortal } from 'react-native/Libraries/Renderer/shims/ReactNative'
6
+
7
+ import { PortalItem } from './GorhomPortal'
8
+ import { PortalProps } from './PortalProps'
9
+
10
+ export const Portal = (props: PortalProps) => {
11
+ const rootTag = React.useContext(RootTagContext)
12
+
13
+ const contents = (
14
+ <YStack
15
+ pointerEvents="box-none"
16
+ fullscreen
17
+ position="absolute"
18
+ maxWidth="100%"
19
+ zIndex={100000}
20
+ {...props}
21
+ />
22
+ )
23
+
24
+ if (Platform.OS === 'android') {
25
+ return <PortalItem name="_tamagui_root_portal">{contents}</PortalItem>
26
+ }
27
+
28
+ if (rootTag) {
29
+ return createPortal(contents, rootTag)
30
+ }
31
+
32
+ if (process.env.NODE_ENV === 'development') {
33
+ // eslint-disable-next-line no-console
34
+ console.warn(
35
+ `Missing rootTag, this is a bug - you may need a different React Native version, or to avoid using "modal" on native.`
36
+ )
37
+ }
38
+
39
+ return null
40
+ }
package/src/Portal.tsx ADDED
@@ -0,0 +1,37 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+ import '@tamagui/polyfill-dev'
3
+
4
+ import { isWeb, useIsomorphicLayoutEffect } from '@tamagui/core'
5
+ import { YStack } from '@tamagui/stacks'
6
+ import * as React from 'react'
7
+ import { createPortal } from 'react-dom'
8
+
9
+ import { PortalProps } from './PortalProps'
10
+
11
+ export const Portal = ({ host = globalThis.document?.body, ...props }: PortalProps) => {
12
+ const contents = (
13
+ <YStack
14
+ pointerEvents="box-none"
15
+ contain="strict"
16
+ fullscreen
17
+ // @ts-expect-error ok on web
18
+ position={isWeb ? 'fixed' : 'absolute'}
19
+ maxWidth={isWeb ? '100vw' : '100%'}
20
+ maxHeight={isWeb ? '100vh' : '100%'}
21
+ {...props}
22
+ />
23
+ )
24
+
25
+ const [hostElement, setHostElement] = React.useState<any>(null)
26
+
27
+ useIsomorphicLayoutEffect(() => {
28
+ setHostElement(host)
29
+ }, [host])
30
+
31
+ if (hostElement) {
32
+ return createPortal(contents, hostElement)
33
+ }
34
+
35
+ // ssr return null
36
+ return null
37
+ }
@@ -0,0 +1,6 @@
1
+ import { YStackProps } from '@tamagui/stacks'
2
+
3
+ export type PortalProps = YStackProps & {
4
+ host?: any // element
5
+ inactive?: boolean
6
+ }
package/src/index.tsx ADDED
@@ -0,0 +1,2 @@
1
+ export * from './Portal'
2
+ export * from './GorhomPortal'