@natykufsky/react-iframe 1.0.15

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 ADDED
@@ -0,0 +1,85 @@
1
+
2
+ # react-iframe
3
+
4
+ A standalone React library to manage multi-instance IFrame workspaces with persistence, memory management, and cross-window communication.
5
+
6
+ ## Features
7
+ - **Persistent DOM**: IFrames are cached (hidden), not unmounted.
8
+ - **Hibernation**: Automatically unloads inactive tabs after a timeout to save memory.
9
+ - **LRU Management**: Automatically closes least-recently-used tabs when maximum capacity is reached.
10
+ - **Persistence**: Session recovery via LocalStorage.
11
+ - **Bridge Support**: Easy communication between parent and IFrame.
12
+
13
+ ## Components
14
+
15
+ ### `TabProvider`
16
+ Wrap your application with this provider.
17
+
18
+ ```tsx
19
+ import { TabProvider } from '@natykufsky/react-iframe';
20
+
21
+ function App() {
22
+ return (
23
+ <TabProvider persist={true} maxTabs={10}>
24
+ <Dashboard />
25
+ </TabProvider>
26
+ );
27
+ }
28
+ ```
29
+
30
+ ### `TabList`
31
+ The tab navigation bar.
32
+
33
+ ```tsx
34
+ import { TabList } from '@natykufsky/react-iframe';
35
+ import '@natykufsky/react-iframe/styles.css';
36
+
37
+ // ... inside a component
38
+ <TabList />
39
+ ```
40
+
41
+ ### `TabViews`
42
+ The container for all iframes.
43
+
44
+ ```tsx
45
+ import { TabViews } from '@natykufsky/react-iframe';
46
+
47
+ // ... inside a component
48
+ <TabViews hibernationMinutes={30} />
49
+ ```
50
+
51
+ ## Hook: `useTabs`
52
+
53
+ ```tsx
54
+ const { addTab, removeTab, focusTab, tabs, activeTabId } = useTabs();
55
+
56
+ const openPage = () => {
57
+ addTab({
58
+ id: 'user-profile',
59
+ title: 'User Profile',
60
+ url: '/admin/users/1/edit',
61
+ icon: 'user'
62
+ });
63
+ };
64
+ ```
65
+
66
+ ## IFrame Bridge
67
+
68
+ Include the bridge script in your child pages (e.g., in a Laravel layout):
69
+
70
+ ```html
71
+ <script src="/path/to/ReFrameBridge.js"></script>
72
+ <script>
73
+ // Close the current tab from inside the iframe
74
+ reFrame.close();
75
+
76
+ // Set tab title
77
+ reFrame.setTitle('Editing User: Naty');
78
+ </script>
79
+ ```
80
+
81
+ In the React parent, use the `useIFrameBridge` hook:
82
+
83
+ ```tsx
84
+ useIFrameBridge(); // Listens for postMessage events
85
+ ```
@@ -0,0 +1,48 @@
1
+
2
+ /**
3
+ * ReFrameBridge.js
4
+ * Include this script in your IFrame pages to communicate with the parent ReFrame container.
5
+ */
6
+ (function() {
7
+ const ReFrame = {
8
+ getTabId: function() {
9
+ // Usually passed via URL params or set by the parent
10
+ const urlParams = new URLSearchParams(window.location.search);
11
+ return urlParams.get('reframe_id') || window.name;
12
+ },
13
+
14
+ postAction: function(action, payload = {}) {
15
+ const message = {
16
+ type: 'REFRAME_ACTION',
17
+ action: action,
18
+ payload: {
19
+ id: this.getTabId(),
20
+ ...payload
21
+ }
22
+ };
23
+ window.parent.postMessage(message, '*');
24
+ },
25
+
26
+ close: function() {
27
+ this.postAction('CLOSE_SELF');
28
+ },
29
+
30
+ setTitle: function(title) {
31
+ this.postAction('SET_TITLE', { title: title });
32
+ document.title = title;
33
+ },
34
+
35
+ notify: function(message, type = 'info') {
36
+ this.postAction('NOTIFICATION', { message: message, type: type });
37
+ },
38
+
39
+ navigate: function(url) {
40
+ this.postAction('NAVIGATE', { url: url });
41
+ }
42
+ };
43
+
44
+ window.reFrame = ReFrame;
45
+
46
+ // Auto-discovery: If title changes, maybe notify parent?
47
+ // MutationObserver could be used here to auto-sync title
48
+ })();
@@ -0,0 +1,6 @@
1
+ import { Tab } from '../types';
2
+ export declare function TabItem({ tab, isActive }: {
3
+ tab: Tab;
4
+ isActive: boolean;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ export declare function TabList(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ interface TabViewProps {
2
+ id: string;
3
+ url: string;
4
+ isActive: boolean;
5
+ isHibernated: boolean;
6
+ onLoad?: () => void;
7
+ }
8
+ export declare function LoadingOverlay(): import("react/jsx-runtime").JSX.Element;
9
+ export declare function HibernationPlaceholder({ onWake, title }: {
10
+ onWake: () => void;
11
+ title: string;
12
+ }): import("react/jsx-runtime").JSX.Element;
13
+ export declare function TabView({ id, url, isActive, isHibernated, title, wakeTab }: TabViewProps & {
14
+ title: string;
15
+ wakeTab: (id: string) => void;
16
+ }): import("react/jsx-runtime").JSX.Element;
17
+ export {};
@@ -0,0 +1,5 @@
1
+ interface TabViewsProps {
2
+ hibernationMinutes?: number;
3
+ }
4
+ export declare function TabViews({ hibernationMinutes }: TabViewsProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,18 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { ReFrameState, ReFrameAction, Tab } from '../types';
3
+ interface ReFrameContextType {
4
+ state: ReFrameState;
5
+ dispatch: React.Dispatch<ReFrameAction>;
6
+ addTab: (tab: Omit<Tab, 'lastAccessed' | 'isHibernated'>) => void;
7
+ removeTab: (id: string) => void;
8
+ focusTab: (id: string) => void;
9
+ closeOthers: (id: string) => void;
10
+ }
11
+ interface ProviderProps {
12
+ children: ReactNode;
13
+ persist?: boolean;
14
+ maxTabs?: number;
15
+ }
16
+ export declare function ReFrameProvider({ children, persist, maxTabs }: ProviderProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare const useReFrame: () => ReFrameContextType;
18
+ export {};
@@ -0,0 +1,2 @@
1
+ import { ReFrameAction, ReFrameState } from '../types';
2
+ export declare const reFrameReducer: (state: ReFrameState, action: ReFrameAction) => ReFrameState;
@@ -0,0 +1 @@
1
+ export declare const useIFrameBridge: () => null;
@@ -0,0 +1,12 @@
1
+ import { Tab } from '../types';
2
+ export declare const useTabs: () => {
3
+ tabs: Tab[];
4
+ activeTab: Tab | undefined;
5
+ activeTabId: string | null;
6
+ addTab: (tab: Omit<Tab, "lastAccessed" | "isHibernated">) => void;
7
+ removeTab: (id: string) => void;
8
+ focusTab: (id: string) => void;
9
+ closeOthers: (id: string) => void;
10
+ updateTab: (id: string, updates: Partial<Tab>) => void;
11
+ reorderTabs: (sourceIndex: number, destinationIndex: number) => void;
12
+ };
@@ -0,0 +1,7 @@
1
+ export * from './context/TabProvider';
2
+ export * from './components/TabList';
3
+ export * from './components/TabView';
4
+ export * from './components/TabViews';
5
+ export * from './hooks/useTabs';
6
+ export * from './hooks/useIFrameBridge';
7
+ export * from './types';