@cactuslab/native-navigation-react
Advanced tools
Comparing version 0.0.9 to 1.0.0
import type { AllComponentOptions, ClickEventData, ComponentId, DismissOptions, DismissResult, NativeNavigationPlugin } from '@cactuslab/native-navigation'; | ||
import type { Plugin } from '@capacitor/core'; | ||
import React from 'react'; | ||
import type { MessageListener } from './types'; | ||
interface ContextInit { | ||
componentId: ComponentId; | ||
pathname: string; | ||
search?: string; | ||
hash?: string; | ||
state?: unknown; | ||
stack?: ComponentId; | ||
@@ -10,6 +15,6 @@ plugin: NativeNavigationPlugin & Plugin; | ||
} | ||
export declare function createReactContext(options: ContextInit): CapacitorNativeNavigationContext; | ||
export declare function createReactContext(options: ContextInit): NativeNavigationContext; | ||
declare type ClickListenerFunc = (data: ClickEventData) => void; | ||
declare type RemoveListenerFunction = () => void; | ||
interface CapacitorNativeNavigationContext { | ||
export interface NativeNavigationContext { | ||
/** | ||
@@ -19,2 +24,6 @@ * The component id. Will be undefined if not in a native context. | ||
componentId?: string; | ||
pathname: string; | ||
search?: string; | ||
hash?: string; | ||
state?: unknown; | ||
/** | ||
@@ -43,5 +52,7 @@ * The id of the stack containing this component, if any. | ||
addClickListener: (func: ClickListenerFunc) => RemoveListenerFunction; | ||
addMessageListener: (type: string, listener: MessageListener) => void; | ||
removeMessageListener: (type: string, listener: MessageListener) => void; | ||
} | ||
export declare const Context: React.Context<CapacitorNativeNavigationContext>; | ||
export declare function useNativeNavigationContext(): CapacitorNativeNavigationContext; | ||
export declare const Context: React.Context<NativeNavigationContext>; | ||
export declare function useNativeNavigationContext(): NativeNavigationContext; | ||
export {}; |
import React, { useContext } from 'react'; | ||
export function createReactContext(options) { | ||
const { componentId: id, stack, viewWindow, plugin } = options; | ||
const { componentId, pathname, search, hash, state, stack, viewWindow, plugin } = options; | ||
const context = { | ||
componentId: id, | ||
componentId, | ||
pathname, | ||
search, | ||
hash, | ||
state, | ||
stack, | ||
@@ -10,3 +14,3 @@ viewWindow, | ||
return plugin.setOptions({ | ||
id: options.id || id, | ||
id: options.id || componentId, | ||
animated: options.animated, | ||
@@ -17,10 +21,10 @@ options, | ||
dismiss: async function (options) { | ||
return plugin.dismiss(Object.assign({ id }, options)); | ||
return plugin.dismiss(Object.assign({ id: componentId }, options)); | ||
}, | ||
addClickListener: function (func) { | ||
let handle; | ||
plugin.addListener(`click:${id}`, func).then(result => { | ||
plugin.addListener(`click:${componentId}`, func).then(result => { | ||
handle = result; | ||
}).catch(reason => { | ||
console.warn(`NativeNavigation: Failed to add click listener for ${id}, this may cause some navigation buttons to fail: ${reason}`); | ||
console.warn(`NativeNavigation: Failed to add click listener for ${componentId}, this may cause some navigation buttons to fail: ${reason}`); | ||
}); | ||
@@ -32,6 +36,28 @@ return function () { | ||
else { | ||
console.warn(`NativeNavigation: Failed to remove listener for ${id}. This may cause a memory leak.`); | ||
console.warn(`NativeNavigation: Failed to remove listener for ${componentId}. This may cause a memory leak.`); | ||
} | ||
}; | ||
}, | ||
addMessageListener(type, listener) { | ||
if (!listener.nativeNavigationAdapters) { | ||
listener.nativeNavigationAdapters = {}; | ||
} | ||
const adapter = listener.nativeNavigationAdapters[type] = listener.nativeNavigationAdapters[type] || function (event) { | ||
const customEvent = event; | ||
const data = customEvent.detail; | ||
if (!type || data.type === type) { | ||
listener(data); | ||
} | ||
}; | ||
viewWindow.addEventListener('nativenavigationmessage', adapter); | ||
}, | ||
removeMessageListener(type, listener) { | ||
if (listener.nativeNavigationAdapters) { | ||
const adapter = listener.nativeNavigationAdapters[type]; | ||
if (adapter) { | ||
viewWindow.removeEventListener('nativenavigationmessage', adapter); | ||
delete listener.nativeNavigationAdapters[type]; | ||
} | ||
} | ||
}, | ||
}; | ||
@@ -41,2 +67,3 @@ return context; | ||
const DEFAULT_CONTEXT = { | ||
pathname: '', | ||
viewWindow: window, | ||
@@ -53,3 +80,9 @@ setOptions: async function () { | ||
}; | ||
} | ||
}, | ||
addMessageListener() { | ||
/* noop */ | ||
}, | ||
removeMessageListener() { | ||
/* noop */ | ||
}, | ||
}; | ||
@@ -56,0 +89,0 @@ export const Context = React.createContext(DEFAULT_CONTEXT); |
import type { NativeNavigationPlugin } from '@cactuslab/native-navigation'; | ||
import type { Plugin } from '@capacitor/core'; | ||
import type { NativeNavigationReactRoot } from './types'; | ||
export { useNativeNavigationContext } from './context'; | ||
export { useNativeNavigationContext, NativeNavigationContext } from './context'; | ||
export { NativeNavigationReactRoot, NativeNavigationReactRootProps } from './types'; | ||
@@ -6,0 +6,0 @@ interface Options { |
@@ -27,2 +27,3 @@ import { initViewHandler } from '@cactuslab/native-navigation'; | ||
destroyView, | ||
messageView, | ||
ready, | ||
@@ -49,3 +50,3 @@ } | ||
reactRoots[id] = reactRoot; | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data)); | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data, viewWindow)); | ||
} | ||
@@ -63,9 +64,16 @@ else { | ||
} | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data)); | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data, viewWindow)); | ||
} | ||
function messageView(viewWindow, data) { | ||
viewWindow.dispatchEvent(new CustomEvent('nativenavigationmessage', { detail: data })); | ||
} | ||
function render(viewWindow, reactRoot, props) { | ||
const { id } = props; | ||
const { id, pathname, search, hash, state, stack } = props; | ||
const context = createReactContext({ | ||
componentId: id, | ||
stack: props.stack, | ||
pathname, | ||
search, | ||
hash, | ||
state, | ||
stack, | ||
viewWindow, | ||
@@ -72,0 +80,0 @@ plugin, |
@@ -1,10 +0,17 @@ | ||
import type { ComponentId, CreateViewEventData } from '@cactuslab/native-navigation'; | ||
import type { ComponentId, CreateViewEventData, MessageEventData } from '@cactuslab/native-navigation'; | ||
import type React from 'react'; | ||
export interface NativeNavigationReactRootProps { | ||
id: ComponentId; | ||
path: string; | ||
pathname: string; | ||
search?: string; | ||
hash?: string; | ||
state?: unknown; | ||
stack?: ComponentId; | ||
/** | ||
* The Window that the component is rendered in. | ||
*/ | ||
viewWindow: Window; | ||
} | ||
export declare type NativeNavigationReactRoot = React.ComponentType<NativeNavigationReactRootProps>; | ||
export declare function toNativeNavigationReactRootProps(data: CreateViewEventData): NativeNavigationReactRootProps; | ||
export declare function toNativeNavigationReactRootProps(data: CreateViewEventData, viewWindow: Window): NativeNavigationReactRootProps; | ||
export declare type MessageListener = (data: MessageEventData) => void; |
@@ -1,10 +0,6 @@ | ||
export function toNativeNavigationReactRootProps(data) { | ||
const props = { | ||
id: data.id, | ||
path: data.path, | ||
state: data.state, | ||
stack: data.stack, | ||
}; | ||
import { parsePath } from './utils'; | ||
export function toNativeNavigationReactRootProps(data, viewWindow) { | ||
const props = Object.assign(Object.assign({ id: data.id }, parsePath(data.path)), { state: data.state, stack: data.stack, viewWindow }); | ||
return props; | ||
} | ||
//# sourceMappingURL=types.js.map |
@@ -15,5 +15,9 @@ 'use strict'; | ||
function createReactContext(options) { | ||
const { componentId: id, stack, viewWindow, plugin } = options; | ||
const { componentId, pathname, search, hash, state, stack, viewWindow, plugin } = options; | ||
const context = { | ||
componentId: id, | ||
componentId, | ||
pathname, | ||
search, | ||
hash, | ||
state, | ||
stack, | ||
@@ -23,3 +27,3 @@ viewWindow, | ||
return plugin.setOptions({ | ||
id: options.id || id, | ||
id: options.id || componentId, | ||
animated: options.animated, | ||
@@ -30,10 +34,10 @@ options, | ||
dismiss: async function (options) { | ||
return plugin.dismiss(Object.assign({ id }, options)); | ||
return plugin.dismiss(Object.assign({ id: componentId }, options)); | ||
}, | ||
addClickListener: function (func) { | ||
let handle; | ||
plugin.addListener(`click:${id}`, func).then(result => { | ||
plugin.addListener(`click:${componentId}`, func).then(result => { | ||
handle = result; | ||
}).catch(reason => { | ||
console.warn(`NativeNavigation: Failed to add click listener for ${id}, this may cause some navigation buttons to fail: ${reason}`); | ||
console.warn(`NativeNavigation: Failed to add click listener for ${componentId}, this may cause some navigation buttons to fail: ${reason}`); | ||
}); | ||
@@ -45,6 +49,28 @@ return function () { | ||
else { | ||
console.warn(`NativeNavigation: Failed to remove listener for ${id}. This may cause a memory leak.`); | ||
console.warn(`NativeNavigation: Failed to remove listener for ${componentId}. This may cause a memory leak.`); | ||
} | ||
}; | ||
}, | ||
addMessageListener(type, listener) { | ||
if (!listener.nativeNavigationAdapters) { | ||
listener.nativeNavigationAdapters = {}; | ||
} | ||
const adapter = listener.nativeNavigationAdapters[type] = listener.nativeNavigationAdapters[type] || function (event) { | ||
const customEvent = event; | ||
const data = customEvent.detail; | ||
if (!type || data.type === type) { | ||
listener(data); | ||
} | ||
}; | ||
viewWindow.addEventListener('nativenavigationmessage', adapter); | ||
}, | ||
removeMessageListener(type, listener) { | ||
if (listener.nativeNavigationAdapters) { | ||
const adapter = listener.nativeNavigationAdapters[type]; | ||
if (adapter) { | ||
viewWindow.removeEventListener('nativenavigationmessage', adapter); | ||
delete listener.nativeNavigationAdapters[type]; | ||
} | ||
} | ||
}, | ||
}; | ||
@@ -54,2 +80,3 @@ return context; | ||
const DEFAULT_CONTEXT = { | ||
pathname: '', | ||
viewWindow: window, | ||
@@ -66,3 +93,9 @@ setOptions: async function () { | ||
}; | ||
} | ||
}, | ||
addMessageListener() { | ||
/* noop */ | ||
}, | ||
removeMessageListener() { | ||
/* noop */ | ||
}, | ||
}; | ||
@@ -323,9 +356,29 @@ const Context = React__default["default"].createContext(DEFAULT_CONTEXT); | ||
function toNativeNavigationReactRootProps(data) { | ||
const props = { | ||
id: data.id, | ||
path: data.path, | ||
state: data.state, | ||
stack: data.stack, | ||
function parsePath(path) { | ||
const result = { | ||
pathname: path, | ||
}; | ||
const s = path.indexOf('?'); | ||
if (s !== -1) { | ||
result.pathname = path.substring(0, s); | ||
let search = path.substring(s); | ||
const h = search.indexOf('#'); | ||
if (h !== -1) { | ||
result.hash = search.substring(h); | ||
search = search.substring(0, h); | ||
} | ||
result.search = search; | ||
} | ||
else { | ||
const h = path.indexOf('#'); | ||
if (h !== -1) { | ||
result.hash = path.substring(h); | ||
result.pathname = path.substring(0, h); | ||
} | ||
} | ||
return result; | ||
} | ||
function toNativeNavigationReactRootProps(data, viewWindow) { | ||
const props = Object.assign(Object.assign({ id: data.id }, parsePath(data.path)), { state: data.state, stack: data.stack, viewWindow }); | ||
return props; | ||
@@ -353,2 +406,3 @@ } | ||
destroyView, | ||
messageView, | ||
ready, | ||
@@ -375,3 +429,3 @@ } | ||
reactRoots[id] = reactRoot; | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data)); | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data, viewWindow)); | ||
} | ||
@@ -389,9 +443,16 @@ else { | ||
} | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data)); | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data, viewWindow)); | ||
} | ||
function messageView(viewWindow, data) { | ||
viewWindow.dispatchEvent(new CustomEvent('nativenavigationmessage', { detail: data })); | ||
} | ||
function render(viewWindow, reactRoot, props) { | ||
const { id } = props; | ||
const { id, pathname, search, hash, state, stack } = props; | ||
const context = createReactContext({ | ||
componentId: id, | ||
stack: props.stack, | ||
pathname, | ||
search, | ||
hash, | ||
state, | ||
stack, | ||
viewWindow, | ||
@@ -398,0 +459,0 @@ plugin, |
@@ -10,5 +10,9 @@ var CapacitorNativeNavigationReact = (function (exports, nativeNavigation, React, ReactDOM) { | ||
function createReactContext(options) { | ||
const { componentId: id, stack, viewWindow, plugin } = options; | ||
const { componentId, pathname, search, hash, state, stack, viewWindow, plugin } = options; | ||
const context = { | ||
componentId: id, | ||
componentId, | ||
pathname, | ||
search, | ||
hash, | ||
state, | ||
stack, | ||
@@ -18,3 +22,3 @@ viewWindow, | ||
return plugin.setOptions({ | ||
id: options.id || id, | ||
id: options.id || componentId, | ||
animated: options.animated, | ||
@@ -25,10 +29,10 @@ options, | ||
dismiss: async function (options) { | ||
return plugin.dismiss(Object.assign({ id }, options)); | ||
return plugin.dismiss(Object.assign({ id: componentId }, options)); | ||
}, | ||
addClickListener: function (func) { | ||
let handle; | ||
plugin.addListener(`click:${id}`, func).then(result => { | ||
plugin.addListener(`click:${componentId}`, func).then(result => { | ||
handle = result; | ||
}).catch(reason => { | ||
console.warn(`NativeNavigation: Failed to add click listener for ${id}, this may cause some navigation buttons to fail: ${reason}`); | ||
console.warn(`NativeNavigation: Failed to add click listener for ${componentId}, this may cause some navigation buttons to fail: ${reason}`); | ||
}); | ||
@@ -40,6 +44,28 @@ return function () { | ||
else { | ||
console.warn(`NativeNavigation: Failed to remove listener for ${id}. This may cause a memory leak.`); | ||
console.warn(`NativeNavigation: Failed to remove listener for ${componentId}. This may cause a memory leak.`); | ||
} | ||
}; | ||
}, | ||
addMessageListener(type, listener) { | ||
if (!listener.nativeNavigationAdapters) { | ||
listener.nativeNavigationAdapters = {}; | ||
} | ||
const adapter = listener.nativeNavigationAdapters[type] = listener.nativeNavigationAdapters[type] || function (event) { | ||
const customEvent = event; | ||
const data = customEvent.detail; | ||
if (!type || data.type === type) { | ||
listener(data); | ||
} | ||
}; | ||
viewWindow.addEventListener('nativenavigationmessage', adapter); | ||
}, | ||
removeMessageListener(type, listener) { | ||
if (listener.nativeNavigationAdapters) { | ||
const adapter = listener.nativeNavigationAdapters[type]; | ||
if (adapter) { | ||
viewWindow.removeEventListener('nativenavigationmessage', adapter); | ||
delete listener.nativeNavigationAdapters[type]; | ||
} | ||
} | ||
}, | ||
}; | ||
@@ -49,2 +75,3 @@ return context; | ||
const DEFAULT_CONTEXT = { | ||
pathname: '', | ||
viewWindow: window, | ||
@@ -61,3 +88,9 @@ setOptions: async function () { | ||
}; | ||
} | ||
}, | ||
addMessageListener() { | ||
/* noop */ | ||
}, | ||
removeMessageListener() { | ||
/* noop */ | ||
}, | ||
}; | ||
@@ -318,9 +351,29 @@ const Context = React__default["default"].createContext(DEFAULT_CONTEXT); | ||
function toNativeNavigationReactRootProps(data) { | ||
const props = { | ||
id: data.id, | ||
path: data.path, | ||
state: data.state, | ||
stack: data.stack, | ||
function parsePath(path) { | ||
const result = { | ||
pathname: path, | ||
}; | ||
const s = path.indexOf('?'); | ||
if (s !== -1) { | ||
result.pathname = path.substring(0, s); | ||
let search = path.substring(s); | ||
const h = search.indexOf('#'); | ||
if (h !== -1) { | ||
result.hash = search.substring(h); | ||
search = search.substring(0, h); | ||
} | ||
result.search = search; | ||
} | ||
else { | ||
const h = path.indexOf('#'); | ||
if (h !== -1) { | ||
result.hash = path.substring(h); | ||
result.pathname = path.substring(0, h); | ||
} | ||
} | ||
return result; | ||
} | ||
function toNativeNavigationReactRootProps(data, viewWindow) { | ||
const props = Object.assign(Object.assign({ id: data.id }, parsePath(data.path)), { state: data.state, stack: data.stack, viewWindow }); | ||
return props; | ||
@@ -348,2 +401,3 @@ } | ||
destroyView, | ||
messageView, | ||
ready, | ||
@@ -370,3 +424,3 @@ } | ||
reactRoots[id] = reactRoot; | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data)); | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data, viewWindow)); | ||
} | ||
@@ -384,9 +438,16 @@ else { | ||
} | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data)); | ||
render(viewWindow, reactRoot, toNativeNavigationReactRootProps(data, viewWindow)); | ||
} | ||
function messageView(viewWindow, data) { | ||
viewWindow.dispatchEvent(new CustomEvent('nativenavigationmessage', { detail: data })); | ||
} | ||
function render(viewWindow, reactRoot, props) { | ||
const { id } = props; | ||
const { id, pathname, search, hash, state, stack } = props; | ||
const context = createReactContext({ | ||
componentId: id, | ||
stack: props.stack, | ||
pathname, | ||
search, | ||
hash, | ||
state, | ||
stack, | ||
viewWindow, | ||
@@ -393,0 +454,0 @@ plugin, |
{ | ||
"name": "@cactuslab/native-navigation-react", | ||
"version": "0.0.9", | ||
"version": "1.0.0", | ||
"description": "React support for Native navigation for Capacitor apps", | ||
@@ -30,3 +30,3 @@ "main": "dist/plugin.cjs.js", | ||
"devDependencies": { | ||
"@cactuslab/native-navigation": "^0.0.8", | ||
"@cactuslab/native-navigation": "^0.1.0", | ||
"@capacitor/core": "^4.0.0", | ||
@@ -44,3 +44,3 @@ "@ionic/eslint-config": "^0.3.0", | ||
"peerDependencies": { | ||
"@cactuslab/native-navigation": "^0.0.8", | ||
"@cactuslab/native-navigation": "^0.1.0", | ||
"@capacitor/core": "^4.0.0", | ||
@@ -47,0 +47,0 @@ "react": "^18.2.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
164510
21
1515
1
1