react-multi-tab 1.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.
- package/README.md +190 -0
- package/dist/adapters/react-router.cjs +41 -0
- package/dist/adapters/react-router.cjs.map +1 -0
- package/dist/adapters/react-router.d.cts +33 -0
- package/dist/adapters/react-router.d.ts +33 -0
- package/dist/adapters/react-router.mjs +39 -0
- package/dist/adapters/react-router.mjs.map +1 -0
- package/dist/index.cjs +632 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +276 -0
- package/dist/index.d.ts +276 -0
- package/dist/index.mjs +618 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types-Df_5I7eH.d.cts +103 -0
- package/dist/types-Df_5I7eH.d.ts +103 -0
- package/package.json +117 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/store.ts","../src/components/MultiTabProvider.tsx","../src/components/TabList.tsx","../src/hooks/useInternalContext.ts","../src/components/TabTrigger.tsx","../src/components/TabPanel.tsx","../src/context/TabInstanceContext.ts","../src/components/TabContent.tsx","../src/components/TabPanels.tsx","../src/components/TabCloseButton.tsx","../src/hooks/useMultiTab.ts","../src/hooks/useTabData.ts","../src/registry.ts","../src/adapters/memory.ts","../src/adapters/search-params.ts"],"names":["createContext","useRef","useEffect","useCallback","useMemo","jsx","useContext","useSyncExternalStore"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createContext } from \"react\";\nimport type { MultiTabContextValue } from \"./types\";\n\n/**\n * Internal React context — not exported from the public API.\n * Consumers interact via `useMultiTab` and `useTabData` hooks.\n */\nexport const MultiTabContext = createContext<MultiTabContextValue | null>(null);\n","import type { MultiTabState, TabInstance } from \"./types\";\n\nexport type Listener = () => void;\n\nexport interface MultiTabStore {\n getState: () => MultiTabState;\n subscribe: (listener: Listener) => () => void;\n dispatch: (action: Action) => void;\n}\n\nexport type Action =\n | { type: \"OPEN_TAB\"; tab: TabInstance; activate: boolean }\n | { type: \"CLOSE_TAB\"; instanceId: string }\n | { type: \"ACTIVATE_TAB\"; instanceId: string }\n | { type: \"CLOSE_ALL\" }\n | { type: \"CLOSE_OTHERS\"; instanceId: string }\n | { type: \"SET_DATA\"; instanceId: string; data: Record<string, unknown> }\n | { type: \"REMOVE_DATA\"; instanceId: string }\n | { type: \"RESTORE\"; state: Partial<MultiTabState> };\n\nfunction reducer(state: MultiTabState, action: Action): MultiTabState {\n switch (action.type) {\n case \"OPEN_TAB\": {\n const activate = action.activate;\n const newActiveId = activate ? action.tab.instanceId : state.activeTabId;\n const newHistory = activate\n ? [\n ...state.activeTabHistory.filter(\n (id) => id !== action.tab.instanceId\n ),\n action.tab.instanceId,\n ]\n : state.activeTabHistory;\n\n return {\n ...state,\n tabs: [...state.tabs, action.tab],\n activeTabId: newActiveId,\n activeTabHistory: newHistory,\n };\n }\n case \"CLOSE_TAB\": {\n const newTabs = state.tabs.filter(\n (t) => t.instanceId !== action.instanceId\n );\n const newHistory = state.activeTabHistory.filter(\n (id) => id !== action.instanceId\n ); // Remove from history\n\n let newActive = state.activeTabId;\n if (state.activeTabId === action.instanceId) {\n // Find the last valid active tab from history\n const previousValidActive =\n newHistory.length > 0 ? newHistory[newHistory.length - 1] : null;\n newActive =\n previousValidActive ||\n (newTabs.length > 0 ? newTabs[newTabs.length - 1].instanceId : null);\n }\n\n const { [action.instanceId]: _removed, ...restData } = state.tabData;\n return {\n tabs: newTabs,\n activeTabId: newActive,\n tabData: restData,\n activeTabHistory: newHistory,\n };\n }\n case \"ACTIVATE_TAB\": {\n if (!state.tabs.some((t) => t.instanceId === action.instanceId))\n return state;\n\n const newHistory = [\n ...state.activeTabHistory.filter((id) => id !== action.instanceId),\n action.instanceId,\n ];\n return {\n ...state,\n activeTabId: action.instanceId,\n activeTabHistory: newHistory,\n };\n }\n case \"CLOSE_ALL\":\n return { tabs: [], activeTabId: null, tabData: {}, activeTabHistory: [] };\n case \"CLOSE_OTHERS\": {\n const kept = state.tabs.filter((t) => t.instanceId === action.instanceId);\n const keptIds = new Set(kept.map((t) => t.instanceId));\n const keptData: Record<string, Record<string, unknown>> = {};\n for (const id of keptIds) {\n if (state.tabData[id]) keptData[id] = state.tabData[id];\n }\n const newHistory = state.activeTabHistory.filter(\n (id) => id === action.instanceId\n );\n return {\n tabs: kept,\n activeTabId: action.instanceId,\n tabData: keptData,\n activeTabHistory: newHistory,\n };\n }\n case \"SET_DATA\":\n return {\n ...state,\n tabData: {\n ...state.tabData,\n [action.instanceId]: {\n ...(state.tabData[action.instanceId] ?? {}),\n ...action.data,\n },\n },\n };\n case \"REMOVE_DATA\": {\n const { [action.instanceId]: _removed, ...rest } = state.tabData;\n return { ...state, tabData: rest };\n }\n case \"RESTORE\": {\n const restoredActive = action.state.activeTabId;\n const newHistory = restoredActive\n ? [\n ...state.activeTabHistory.filter((id) => id !== restoredActive),\n restoredActive,\n ]\n : state.activeTabHistory;\n return { ...state, ...action.state, activeTabHistory: newHistory };\n }\n default:\n return state;\n }\n}\n\nexport function createMultiTabStore(\n initialState: MultiTabState\n): MultiTabStore {\n let state = initialState;\n const listeners = new Set<Listener>();\n\n const getState = () => state;\n\n const dispatch = (action: Action) => {\n state = reducer(state, action);\n listeners.forEach((listener) => listener());\n };\n\n const subscribe = (listener: Listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n };\n\n return {\n getState,\n dispatch,\n subscribe,\n };\n}\n","import { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { MultiTabContext } from \"../context\";\nimport { createMultiTabStore } from \"../store\";\nimport type {\n MultiTabProviderProps,\n OpenTabOptions,\n TabInstance,\n} from \"../types\";\n\n// ---------------------------------------------------------------------------\n// Instance ID generator\n// ---------------------------------------------------------------------------\n\nlet counter = 0;\n\nfunction generateInstanceId(pageId: string): string {\n counter += 1;\n return `${pageId}-${counter}`;\n}\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport function MultiTabProvider({\n registry,\n adapter,\n defaultActiveTab,\n children,\n onTabOpen,\n onTabClose,\n onTabChange,\n}: MultiTabProviderProps) {\n // Initialize the external store exactly once\n const store = useRef(\n createMultiTabStore({\n tabs: [],\n activeTabId: defaultActiveTab ?? null,\n tabData: {},\n activeTabHistory: defaultActiveTab ? [defaultActiveTab] : [],\n })\n ).current;\n\n // Keep callback refs so they're always up-to-date\n const cbRef = useRef({ onTabOpen, onTabClose, onTabChange });\n cbRef.current = { onTabOpen, onTabClose, onTabChange };\n\n // Track previous active tab to fire `onTabChange` properly.\n // We'll use a local state or subscribe to store to detect active tab changes.\n const prevActiveRef = useRef<string | null>(defaultActiveTab ?? null);\n\n useEffect(\n () =>\n store.subscribe(() => {\n const state = store.getState();\n if (\n state.activeTabId !== null &&\n state.activeTabId !== prevActiveRef.current\n ) {\n cbRef.current.onTabChange?.(state.activeTabId);\n }\n prevActiveRef.current = state.activeTabId;\n }),\n [store]\n );\n\n // ---- Adapter: restore on mount -------------------------------------------\n const initialised = useRef(false);\n useEffect(() => {\n if (initialised.current || !adapter) return;\n initialised.current = true;\n\n const saved = adapter.read();\n if (!saved || saved.tabs.length === 0) return;\n\n const restoredTabs: TabInstance[] = saved.tabs\n .map((instanceId) => {\n const parts = instanceId.split(\"-\");\n for (let i = parts.length - 1; i >= 1; i--) {\n const candidateId = parts.slice(0, i).join(\"-\");\n const page = registry.getPage(candidateId);\n if (page) {\n return {\n instanceId,\n pageId: page.id,\n label: page.label,\n closable: page.closable !== false,\n } satisfies TabInstance;\n }\n }\n return null;\n })\n .filter((t): t is TabInstance => t !== null);\n\n if (restoredTabs.length > 0) {\n const activeTab =\n saved.activeTab &&\n restoredTabs.some((t) => t.instanceId === saved.activeTab)\n ? saved.activeTab\n : restoredTabs[restoredTabs.length - 1].instanceId;\n\n store.dispatch({\n type: \"RESTORE\",\n state: { tabs: restoredTabs, activeTabId: activeTab },\n });\n }\n }, [adapter, registry, store]);\n\n // ---- Adapter: persist on change ------------------------------------------\n useEffect(() => {\n if (!adapter) return;\n return store.subscribe(() => {\n const { tabs, activeTabId } = store.getState();\n adapter.write(tabs, activeTabId);\n });\n }, [adapter, store]);\n\n // ---- Adapter: subscribe to external changes ------------------------------\n useEffect(() => {\n if (!adapter?.subscribe) return;\n const unsubscribe = adapter.subscribe(() => {\n const saved = adapter.read();\n const currentState = store.getState();\n if (saved?.activeTab && saved.activeTab !== currentState.activeTabId) {\n store.dispatch({ type: \"ACTIVATE_TAB\", instanceId: saved.activeTab });\n }\n });\n return unsubscribe;\n }, [adapter, store]);\n\n // ---- Adapter: cleanup on unmount -----------------------------------------\n useEffect(() => () => adapter?.destroy?.(), [adapter]);\n\n // ---- Actions -------------------------------------------------------------\n\n const openTab = useCallback(\n (pageId: string, options?: OpenTabOptions): string => {\n const page = registry.getPage(pageId);\n if (!page) {\n throw new Error(\n `react-multi-tab: Page \"${pageId}\" not found in registry.`\n );\n }\n\n const instanceId = options?.instanceId ?? generateInstanceId(pageId);\n const tab: TabInstance = {\n instanceId,\n pageId,\n label: options?.label ?? page.label,\n closable: page.closable !== false,\n };\n\n store.dispatch({\n type: \"OPEN_TAB\",\n tab,\n activate: options?.activate !== false,\n });\n cbRef.current.onTabOpen?.(tab);\n\n return instanceId;\n },\n [registry, store]\n );\n\n const closeTab = useCallback(\n (instanceId: string) => {\n store.dispatch({ type: \"CLOSE_TAB\", instanceId });\n cbRef.current.onTabClose?.(instanceId);\n },\n [store]\n );\n\n const activateTab = useCallback(\n (instanceId: string) => {\n store.dispatch({ type: \"ACTIVATE_TAB\", instanceId });\n },\n [store]\n );\n\n const closeAllTabs = useCallback(() => {\n store.dispatch({ type: \"CLOSE_ALL\" });\n }, [store]);\n\n const closeOtherTabs = useCallback(\n (instanceId: string) => {\n store.dispatch({ type: \"CLOSE_OTHERS\", instanceId });\n },\n [store]\n );\n\n const setTabData = useCallback(\n (instanceId: string, data: Record<string, unknown>) => {\n store.dispatch({ type: \"SET_DATA\", instanceId, data });\n },\n [store]\n );\n\n const getTabData = useCallback(\n (instanceId: string): Record<string, unknown> =>\n store.getState().tabData[instanceId] ?? {},\n [store]\n );\n\n const removeTabData = useCallback(\n (instanceId: string) => {\n store.dispatch({ type: \"REMOVE_DATA\", instanceId });\n },\n [store]\n );\n\n // ---- Context value -------------------------------------------------------\n\n const contextValue = useMemo(\n () => ({\n store,\n registry,\n openTab,\n closeTab,\n activateTab,\n closeAllTabs,\n closeOtherTabs,\n setTabData,\n getTabData,\n removeTabData,\n }),\n [\n store,\n registry,\n openTab,\n closeTab,\n activateTab,\n closeAllTabs,\n closeOtherTabs,\n setTabData,\n getTabData,\n removeTabData,\n ]\n );\n\n return (\n <MultiTabContext.Provider value={contextValue}>\n {children}\n </MultiTabContext.Provider>\n );\n}\n","import { useCallback, useRef } from \"react\";\n\n/**\n * Props for {@link TabList}.\n */\nexport interface TabListProps {\n children: React.ReactNode;\n /** Accessible label for the tab list. */\n \"aria-label\"?: string;\n /** ID of an element that labels the tab list. */\n \"aria-labelledby\"?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Accessible container for tab triggers.\n *\n * Implements the **WAI-ARIA Tabs** pattern:\n * - `role=\"tablist\"`\n * - `Arrow Left / Right` — move focus between tabs\n * - `Home / End` — jump to first / last tab\n *\n * @example\n * ```tsx\n * <TabList aria-label=\"Open pages\">\n * {tabs.map(t => <TabTrigger key={t.instanceId} instanceId={t.instanceId} />)}\n * </TabList>\n * ```\n */\nexport function TabList({\n children,\n className,\n style,\n ...ariaProps\n}: TabListProps) {\n const listRef = useRef<HTMLDivElement>(null);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n const tabElements =\n listRef.current?.querySelectorAll<HTMLElement>('[role=\"tab\"]');\n if (!tabElements || tabElements.length === 0) return;\n\n const tabs = Array.from(tabElements);\n const currentIndex = tabs.findIndex(\n (el) => el === document.activeElement\n );\n\n let nextIndex: number | null = null;\n\n switch (e.key) {\n case \"ArrowRight\":\n case \"ArrowDown\":\n e.preventDefault();\n nextIndex = currentIndex < tabs.length - 1 ? currentIndex + 1 : 0;\n break;\n\n case \"ArrowLeft\":\n case \"ArrowUp\":\n e.preventDefault();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : tabs.length - 1;\n break;\n\n case \"Home\":\n e.preventDefault();\n nextIndex = 0;\n break;\n\n case \"End\":\n e.preventDefault();\n nextIndex = tabs.length - 1;\n break;\n\n default:\n return;\n }\n\n if (nextIndex !== null) {\n tabs[nextIndex].focus();\n }\n },\n []\n );\n\n return (\n <div\n ref={listRef}\n role=\"tablist\"\n className={className}\n style={style}\n onKeyDown={handleKeyDown}\n {...ariaProps}\n >\n {children}\n </div>\n );\n}\n","import { useContext } from \"react\";\nimport { MultiTabContext } from \"../context\";\nimport type { MultiTabContextValue } from \"../types\";\n\n/**\n * Internal hook — use `useMultiTab` or `useTabData` instead.\n *\n * @throws If called outside a `<MultiTabProvider>`.\n * @internal\n */\nexport function useInternalContext(): MultiTabContextValue {\n const ctx = useContext(MultiTabContext);\n if (!ctx) {\n throw new Error(\n \"react-multi-tab: Hooks must be used within a <MultiTabProvider>.\"\n );\n }\n return ctx;\n}\n","import { useCallback } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport { useInternalContext } from \"../hooks/useInternalContext\";\n\n/**\n * Props for {@link TabTrigger}.\n */\nexport interface TabTriggerProps {\n /** Instance ID of the tab this trigger controls. */\n instanceId: string;\n children: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n disabled?: boolean;\n}\n\n/**\n * Accessible tab trigger button.\n *\n * Implements the **WAI-ARIA** `tab` role:\n * - `role=\"tab\"`\n * - `aria-selected` reflects active state\n * - `aria-controls` points to the matching `tabpanel`\n * - Roving `tabIndex` (`0` for active, `-1` for inactive)\n * - `Enter` / `Space` activates the tab\n *\n * @example\n * ```tsx\n * <TabTrigger instanceId={tab.instanceId}>\n * {tab.label}\n * <TabCloseButton instanceId={tab.instanceId} />\n * </TabTrigger>\n * ```\n */\nexport function TabTrigger({\n instanceId,\n children,\n className,\n style,\n disabled = false,\n}: TabTriggerProps) {\n const { store, activateTab } = useInternalContext();\n const state = useSyncExternalStore(store.subscribe, store.getState);\n const isActive = state.activeTabId === instanceId;\n\n const handleClick = useCallback(() => {\n if (!disabled) activateTab(instanceId);\n }, [instanceId, disabled, activateTab]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if ((e.key === \"Enter\" || e.key === \" \") && !disabled) {\n e.preventDefault();\n activateTab(instanceId);\n }\n },\n [instanceId, disabled, activateTab]\n );\n\n return (\n <div\n role=\"tab\"\n id={`rmt-tab-${instanceId}`}\n aria-selected={isActive}\n aria-controls={`rmt-tabpanel-${instanceId}`}\n tabIndex={isActive ? 0 : -1}\n className={className}\n style={style}\n aria-disabled={disabled}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n data-state={isActive ? \"active\" : \"inactive\"}\n >\n {children}\n </div>\n );\n}\n","/**\n * Props for {@link TabPanel}.\n */\nexport interface TabPanelProps {\n /** Instance ID of the tab this panel belongs to. */\n instanceId: string;\n children: React.ReactNode;\n /** Whether the panel is hidden (inactive tab). */\n hidden?: boolean;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Accessible tab panel.\n *\n * Implements the **WAI-ARIA** `tabpanel` role:\n * - `role=\"tabpanel\"`\n * - `aria-labelledby` pointing to the matching `TabTrigger`\n * - `tabIndex={0}` for keyboard focusability\n * - Uses the `hidden` HTML attribute for inactive panels (keeps state\n * mounted — no re-mount on tab switch).\n *\n * @example\n * ```tsx\n * <TabPanel instanceId={tab.instanceId} hidden={!isActive}>\n * <MyPageComponent />\n * </TabPanel>\n * ```\n */\nexport function TabPanel({\n instanceId,\n children,\n hidden = false,\n className,\n style,\n}: TabPanelProps) {\n return (\n <div\n role=\"tabpanel\"\n id={`rmt-tabpanel-${instanceId}`}\n aria-labelledby={`rmt-tab-${instanceId}`}\n tabIndex={0}\n hidden={hidden}\n className={className}\n style={style}\n >\n {children}\n </div>\n );\n}\n","import { createContext, useContext } from \"react\";\n\n/**\n * Context that provides the current tab instance ID.\n * This is meant to be wrapped around each rendered tab's content.\n */\nexport const TabInstanceContext = createContext<string | null>(null);\n\n/**\n * Hook to retrieve the current tab's instance ID.\n * Throws an error if used outside a TabInstanceContext.\n * Extremely useful for integrating with Redux or when components\n * need to automatically know which tab they belong to.\n */\nexport function useTabInstanceId(): string {\n const instanceId = useContext(TabInstanceContext);\n if (!instanceId) {\n throw new Error(\n \"react-multi-tab: useTabInstanceId must be used within a component rendered inside a Tab.\"\n );\n }\n return instanceId;\n}\n","import { TabInstanceContext } from \"../context/TabInstanceContext\";\n\nexport interface TabContentProps {\n instanceId: string;\n children: React.ReactNode;\n}\n\n/**\n * A wrapper component that provides the `TabInstanceContext` to all children.\n * This allows hooks like `useTabData` and `useTabInstanceId` to automatically\n * resolve the active tab's instanceId without it being explicitly passed.\n *\n * @example\n * ```tsx\n * <TabContent instanceId={activeTab.instanceId}>\n * <ActivePageComponent />\n * </TabContent>\n * ```\n */\nexport function TabContent({ instanceId, children }: TabContentProps) {\n return (\n <TabInstanceContext.Provider value={instanceId}>\n {children}\n </TabInstanceContext.Provider>\n );\n}\n","import { useSyncExternalStore } from \"react\";\nimport { useInternalContext } from \"../hooks/useInternalContext\";\nimport { TabContent } from \"./TabContent\";\nimport { TabPanel } from \"./TabPanel\";\n\n/**\n * Props for {@link TabPanels}.\n */\nexport interface TabPanelsProps {\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Renders **all** open tab panels and hides inactive ones.\n *\n * This is the simplest way to display tab content. Each page component\n * receives its `instanceId`, `data`, and `setData` as props automatically.\n *\n * Inactive panels stay mounted (using the `hidden` attribute) so their\n * state is preserved across tab switches.\n *\n * @example\n * ```tsx\n * <TabPanels />\n * ```\n */\nexport function TabPanels({ className, style }: TabPanelsProps) {\n const { store, registry, setTabData } = useInternalContext();\n const state = useSyncExternalStore(store.subscribe, store.getState);\n\n return (\n <div className={className} style={style}>\n {state.tabs.map((tab) => {\n const page = registry.getPage(tab.pageId);\n if (!page) return null;\n\n const isActive = state.activeTabId === tab.instanceId;\n const data = state.tabData[tab.instanceId] ?? {};\n const Component = page.component;\n\n return (\n <TabPanel\n key={tab.instanceId}\n instanceId={tab.instanceId}\n hidden={!isActive}\n >\n <TabContent instanceId={tab.instanceId}>\n <Component\n instanceId={tab.instanceId}\n data={data}\n setData={(update) =>\n setTabData(tab.instanceId, update as Record<string, unknown>)\n }\n />\n </TabContent>\n </TabPanel>\n );\n })}\n </div>\n );\n}\n","import { useCallback } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport { useInternalContext } from \"../hooks/useInternalContext\";\n\n/**\n * Props for {@link TabCloseButton}.\n */\nexport interface TabCloseButtonProps {\n /** Instance ID of the tab to close. */\n instanceId: string;\n /** Custom content (default: `×`). */\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n /** Override the auto-generated aria-label. */\n \"aria-label\"?: string;\n}\n\n/**\n * Button that closes a specific tab.\n *\n * Renders nothing if the tab's `closable` property is `false`.\n * Prevents the click from bubbling to `TabTrigger` so it doesn't\n * accidentally activate the tab.\n *\n * @example\n * ```tsx\n * <TabTrigger instanceId={tab.instanceId}>\n * {tab.label}\n * <TabCloseButton instanceId={tab.instanceId} />\n * </TabTrigger>\n * ```\n */\nexport function TabCloseButton({\n instanceId,\n children,\n className,\n style,\n \"aria-label\": ariaLabel,\n}: TabCloseButtonProps) {\n const { store, closeTab } = useInternalContext();\n const state = useSyncExternalStore(store.subscribe, store.getState);\n const tab = state.tabs.find((t) => t.instanceId === instanceId);\n\n const handleClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n closeTab(instanceId);\n },\n [instanceId, closeTab]\n );\n\n if (!tab || !tab.closable) return null;\n\n return (\n <button\n type=\"button\"\n aria-label={ariaLabel ?? `Close ${tab.label}`}\n className={className}\n style={style}\n onClick={handleClick}\n tabIndex={-1}\n >\n {children ?? \"×\"}\n </button>\n );\n}\n","import { useSyncExternalStore } from \"react\";\nimport type { OpenTabOptions, TabInstance } from \"../types\";\nimport { useInternalContext } from \"./useInternalContext\";\n\n/** Public return type of {@link useMultiTab}. */\nexport interface UseMultiTabReturn {\n /** Currently open tabs. */\n tabs: TabInstance[];\n /** Instance ID of the active tab, or `null` if none. */\n activeTabId: string | null;\n /** Open a new tab for the given page ID. Returns the instance ID. */\n openTab: (pageId: string, options?: OpenTabOptions) => string;\n /** Close a tab by instance ID. */\n closeTab: (instanceId: string) => void;\n /** Activate (switch to) a tab by instance ID. */\n activateTab: (instanceId: string) => void;\n /** Close every open tab. */\n closeAllTabs: () => void;\n /** Close all tabs except the specified one. */\n closeOtherTabs: (instanceId: string) => void;\n}\n\n/**\n * Primary hook for managing tabs.\n *\n * @example\n * ```tsx\n * const { tabs, activeTabId, openTab, closeTab } = useMultiTab();\n * ```\n */\nexport function useMultiTab(): UseMultiTabReturn {\n const {\n store,\n openTab,\n closeTab,\n activateTab,\n closeAllTabs,\n closeOtherTabs,\n } = useInternalContext();\n\n // Subscribe to the store to get the latest tabs and activeTabId\n const state = useSyncExternalStore(store.subscribe, store.getState);\n\n return {\n tabs: state.tabs,\n activeTabId: state.activeTabId,\n openTab,\n closeTab,\n activateTab,\n closeAllTabs,\n closeOtherTabs,\n };\n}\n","import { useCallback, useContext } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport { TabInstanceContext } from \"../context/TabInstanceContext\";\nimport { useInternalContext } from \"./useInternalContext\";\n\nconst EMPTY_DATA = Object.freeze({});\n\n/**\n * Read and write per-tab data with full TypeScript generics.\n *\n * When no `instanceId` is provided, the hook automatically targets the\n * ID from the surrounding `TabContent`. If not inside a `TabContent`,\n * it falls back to the globally active tab.\n *\n * This hook is highly optimized using `useSyncExternalStore` to prevent\n * unnecessary re-renders. A component using this hook will ONLY re-render\n * when the specific data for its resolved `instanceId` changes!\n *\n * @typeParam TData – Shape of the data stored for this tab instance.\n *\n * @example\n * ```tsx\n * interface FormData { name: string; email: string }\n *\n * function MyPage() {\n * const [data, setData] = useTabData<FormData>();\n * // data : FormData\n * // setData: (update: Partial<FormData>) => void\n * }\n * ```\n */\nexport function useTabData<TData = Record<string, unknown>>(\n instanceId?: string\n): [TData, (update: Partial<TData>) => void] {\n const { store, setTabData } = useInternalContext();\n const contextId = useContext(TabInstanceContext);\n\n // Fallback requires us to check store state. We do it once per render safely\n // since activeTabId rarely changes without the store updating anyway.\n const fallbackId = store.getState().activeTabId;\n const resolvedId = instanceId ?? contextId ?? fallbackId;\n\n const getSnapshot = useCallback(() => {\n if (!resolvedId) return EMPTY_DATA as unknown as TData;\n const tabData = store.getState().tabData[resolvedId];\n return (tabData ?? EMPTY_DATA) as unknown as TData;\n }, [resolvedId, store]);\n\n const data = useSyncExternalStore(store.subscribe, getSnapshot);\n\n const setData = useCallback(\n (update: Partial<TData>) => {\n if (resolvedId) {\n setTabData(resolvedId, update as Record<string, unknown>);\n }\n },\n [resolvedId, setTabData]\n );\n\n return [data, setData];\n}\n","import type { PageDefinition, PageRegistry } from \"./types\";\n\n/**\n * Create an immutable page registry from an array of page definitions.\n *\n * @example\n * ```ts\n * const registry = createPageRegistry([\n * { id: 'dashboard', label: 'Dashboard', component: DashboardPage },\n * { id: 'settings', label: 'Settings', component: SettingsPage },\n * ]);\n * ```\n *\n * @throws If any page is missing `id`, `label`, or `component`.\n * @throws If duplicate `id` values are found.\n */\nexport function createPageRegistry(pages: PageDefinition[]): PageRegistry {\n const ids = new Set<string>();\n\n for (const page of pages) {\n if (!page.id) {\n throw new Error(\"react-multi-tab: Page definition must have an id.\");\n }\n if (!page.label) {\n throw new Error(`react-multi-tab: Page \"${page.id}\" must have a label.`);\n }\n if (!page.component) {\n throw new Error(\n `react-multi-tab: Page \"${page.id}\" must have a component.`\n );\n }\n if (ids.has(page.id)) {\n throw new Error(`react-multi-tab: Duplicate page id: \"${page.id}\".`);\n }\n ids.add(page.id);\n }\n\n // Shallow-copy so mutations to the original array don't affect the registry.\n const frozen = [...pages];\n\n return {\n pages: frozen,\n getPage: (id: string) => frozen.find((p) => p.id === id),\n };\n}\n","import type { URLAdapter } from \"../types\";\n\n/**\n * In-memory adapter — no URL synchronisation.\n *\n * This is the implicit default when no `adapter` prop is passed to\n * `MultiTabProvider`. Useful for embedded UIs or tests.\n */\nexport function memoryAdapter(): URLAdapter {\n return {\n read: () => null,\n write: () => {\n /* noop */\n },\n };\n}\n","import type { TabInstance, URLAdapter } from \"../types\";\n\n/** Options for {@link searchParamsAdapter}. */\nexport interface SearchParamsAdapterOptions {\n /** Query-string key for tab instance IDs. @default \"tabs\" */\n tabsParam?: string;\n /** Query-string key for the active tab. @default \"active\" */\n activeParam?: string;\n}\n\n/**\n * URL adapter that uses the vanilla browser `URLSearchParams` +\n * `history.replaceState` APIs.\n *\n * **No dependency on any router library** — works in any SPA.\n *\n * @example\n * ```tsx\n * import { searchParamsAdapter } from 'react-multi-tab';\n *\n * <MultiTabProvider adapter={searchParamsAdapter()} registry={registry}>\n * ```\n */\nexport function searchParamsAdapter(\n options?: SearchParamsAdapterOptions\n): URLAdapter {\n const tabsKey = options?.tabsParam ?? \"tabs\";\n const activeKey = options?.activeParam ?? \"active\";\n\n return {\n read() {\n if (typeof window === \"undefined\") return null;\n\n const params = new URLSearchParams(window.location.search);\n const tabsStr = params.get(tabsKey);\n const activeTab = params.get(activeKey);\n\n if (!tabsStr) return null;\n\n const tabs = tabsStr.split(\",\").filter(Boolean);\n return { tabs, activeTab };\n },\n\n write(tabs: TabInstance[], activeTabId: string | null) {\n if (typeof window === \"undefined\") return;\n\n const params = new URLSearchParams(window.location.search);\n\n if (tabs.length > 0) {\n params.set(tabsKey, tabs.map((t) => t.instanceId).join(\",\"));\n if (activeTabId) {\n params.set(activeKey, activeTabId);\n } else {\n params.delete(activeKey);\n }\n } else {\n params.delete(tabsKey);\n params.delete(activeKey);\n }\n\n const qs = params.toString().replace(/%2C/g, \",\");\n const newUrl = qs\n ? `${window.location.pathname}?${qs}`\n : window.location.pathname;\n\n window.history.replaceState(null, \"\", newUrl);\n },\n\n subscribe(callback: () => void) {\n window.addEventListener(\"popstate\", callback);\n return () => window.removeEventListener(\"popstate\", callback);\n },\n };\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { M as MultiTabProviderProps, T as TabInstance, O as OpenTabOptions, P as PageDefinition, a as PageRegistry, U as URLAdapter } from './types-Df_5I7eH.cjs';
|
|
3
|
+
export { b as MultiTabState, c as TabComponentProps } from './types-Df_5I7eH.cjs';
|
|
4
|
+
|
|
5
|
+
declare function MultiTabProvider({ registry, adapter, defaultActiveTab, children, onTabOpen, onTabClose, onTabChange, }: MultiTabProviderProps): react.JSX.Element;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Props for {@link TabList}.
|
|
9
|
+
*/
|
|
10
|
+
interface TabListProps {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
/** Accessible label for the tab list. */
|
|
13
|
+
"aria-label"?: string;
|
|
14
|
+
/** ID of an element that labels the tab list. */
|
|
15
|
+
"aria-labelledby"?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Accessible container for tab triggers.
|
|
21
|
+
*
|
|
22
|
+
* Implements the **WAI-ARIA Tabs** pattern:
|
|
23
|
+
* - `role="tablist"`
|
|
24
|
+
* - `Arrow Left / Right` — move focus between tabs
|
|
25
|
+
* - `Home / End` — jump to first / last tab
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <TabList aria-label="Open pages">
|
|
30
|
+
* {tabs.map(t => <TabTrigger key={t.instanceId} instanceId={t.instanceId} />)}
|
|
31
|
+
* </TabList>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare function TabList({ children, className, style, ...ariaProps }: TabListProps): react.JSX.Element;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Props for {@link TabTrigger}.
|
|
38
|
+
*/
|
|
39
|
+
interface TabTriggerProps {
|
|
40
|
+
/** Instance ID of the tab this trigger controls. */
|
|
41
|
+
instanceId: string;
|
|
42
|
+
children: React.ReactNode;
|
|
43
|
+
className?: string;
|
|
44
|
+
style?: React.CSSProperties;
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Accessible tab trigger button.
|
|
49
|
+
*
|
|
50
|
+
* Implements the **WAI-ARIA** `tab` role:
|
|
51
|
+
* - `role="tab"`
|
|
52
|
+
* - `aria-selected` reflects active state
|
|
53
|
+
* - `aria-controls` points to the matching `tabpanel`
|
|
54
|
+
* - Roving `tabIndex` (`0` for active, `-1` for inactive)
|
|
55
|
+
* - `Enter` / `Space` activates the tab
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* <TabTrigger instanceId={tab.instanceId}>
|
|
60
|
+
* {tab.label}
|
|
61
|
+
* <TabCloseButton instanceId={tab.instanceId} />
|
|
62
|
+
* </TabTrigger>
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function TabTrigger({ instanceId, children, className, style, disabled, }: TabTriggerProps): react.JSX.Element;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Props for {@link TabPanel}.
|
|
69
|
+
*/
|
|
70
|
+
interface TabPanelProps {
|
|
71
|
+
/** Instance ID of the tab this panel belongs to. */
|
|
72
|
+
instanceId: string;
|
|
73
|
+
children: React.ReactNode;
|
|
74
|
+
/** Whether the panel is hidden (inactive tab). */
|
|
75
|
+
hidden?: boolean;
|
|
76
|
+
className?: string;
|
|
77
|
+
style?: React.CSSProperties;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Accessible tab panel.
|
|
81
|
+
*
|
|
82
|
+
* Implements the **WAI-ARIA** `tabpanel` role:
|
|
83
|
+
* - `role="tabpanel"`
|
|
84
|
+
* - `aria-labelledby` pointing to the matching `TabTrigger`
|
|
85
|
+
* - `tabIndex={0}` for keyboard focusability
|
|
86
|
+
* - Uses the `hidden` HTML attribute for inactive panels (keeps state
|
|
87
|
+
* mounted — no re-mount on tab switch).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```tsx
|
|
91
|
+
* <TabPanel instanceId={tab.instanceId} hidden={!isActive}>
|
|
92
|
+
* <MyPageComponent />
|
|
93
|
+
* </TabPanel>
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare function TabPanel({ instanceId, children, hidden, className, style, }: TabPanelProps): react.JSX.Element;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Props for {@link TabPanels}.
|
|
100
|
+
*/
|
|
101
|
+
interface TabPanelsProps {
|
|
102
|
+
className?: string;
|
|
103
|
+
style?: React.CSSProperties;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Renders **all** open tab panels and hides inactive ones.
|
|
107
|
+
*
|
|
108
|
+
* This is the simplest way to display tab content. Each page component
|
|
109
|
+
* receives its `instanceId`, `data`, and `setData` as props automatically.
|
|
110
|
+
*
|
|
111
|
+
* Inactive panels stay mounted (using the `hidden` attribute) so their
|
|
112
|
+
* state is preserved across tab switches.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```tsx
|
|
116
|
+
* <TabPanels />
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare function TabPanels({ className, style }: TabPanelsProps): react.JSX.Element;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Props for {@link TabCloseButton}.
|
|
123
|
+
*/
|
|
124
|
+
interface TabCloseButtonProps {
|
|
125
|
+
/** Instance ID of the tab to close. */
|
|
126
|
+
instanceId: string;
|
|
127
|
+
/** Custom content (default: `×`). */
|
|
128
|
+
children?: React.ReactNode;
|
|
129
|
+
className?: string;
|
|
130
|
+
style?: React.CSSProperties;
|
|
131
|
+
/** Override the auto-generated aria-label. */
|
|
132
|
+
"aria-label"?: string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Button that closes a specific tab.
|
|
136
|
+
*
|
|
137
|
+
* Renders nothing if the tab's `closable` property is `false`.
|
|
138
|
+
* Prevents the click from bubbling to `TabTrigger` so it doesn't
|
|
139
|
+
* accidentally activate the tab.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* <TabTrigger instanceId={tab.instanceId}>
|
|
144
|
+
* {tab.label}
|
|
145
|
+
* <TabCloseButton instanceId={tab.instanceId} />
|
|
146
|
+
* </TabTrigger>
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function TabCloseButton({ instanceId, children, className, style, "aria-label": ariaLabel, }: TabCloseButtonProps): react.JSX.Element | null;
|
|
150
|
+
|
|
151
|
+
interface TabContentProps {
|
|
152
|
+
instanceId: string;
|
|
153
|
+
children: React.ReactNode;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* A wrapper component that provides the `TabInstanceContext` to all children.
|
|
157
|
+
* This allows hooks like `useTabData` and `useTabInstanceId` to automatically
|
|
158
|
+
* resolve the active tab's instanceId without it being explicitly passed.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* <TabContent instanceId={activeTab.instanceId}>
|
|
163
|
+
* <ActivePageComponent />
|
|
164
|
+
* </TabContent>
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
declare function TabContent({ instanceId, children }: TabContentProps): react.JSX.Element;
|
|
168
|
+
|
|
169
|
+
/** Public return type of {@link useMultiTab}. */
|
|
170
|
+
interface UseMultiTabReturn {
|
|
171
|
+
/** Currently open tabs. */
|
|
172
|
+
tabs: TabInstance[];
|
|
173
|
+
/** Instance ID of the active tab, or `null` if none. */
|
|
174
|
+
activeTabId: string | null;
|
|
175
|
+
/** Open a new tab for the given page ID. Returns the instance ID. */
|
|
176
|
+
openTab: (pageId: string, options?: OpenTabOptions) => string;
|
|
177
|
+
/** Close a tab by instance ID. */
|
|
178
|
+
closeTab: (instanceId: string) => void;
|
|
179
|
+
/** Activate (switch to) a tab by instance ID. */
|
|
180
|
+
activateTab: (instanceId: string) => void;
|
|
181
|
+
/** Close every open tab. */
|
|
182
|
+
closeAllTabs: () => void;
|
|
183
|
+
/** Close all tabs except the specified one. */
|
|
184
|
+
closeOtherTabs: (instanceId: string) => void;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Primary hook for managing tabs.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```tsx
|
|
191
|
+
* const { tabs, activeTabId, openTab, closeTab } = useMultiTab();
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
declare function useMultiTab(): UseMultiTabReturn;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Read and write per-tab data with full TypeScript generics.
|
|
198
|
+
*
|
|
199
|
+
* When no `instanceId` is provided, the hook automatically targets the
|
|
200
|
+
* ID from the surrounding `TabContent`. If not inside a `TabContent`,
|
|
201
|
+
* it falls back to the globally active tab.
|
|
202
|
+
*
|
|
203
|
+
* This hook is highly optimized using `useSyncExternalStore` to prevent
|
|
204
|
+
* unnecessary re-renders. A component using this hook will ONLY re-render
|
|
205
|
+
* when the specific data for its resolved `instanceId` changes!
|
|
206
|
+
*
|
|
207
|
+
* @typeParam TData – Shape of the data stored for this tab instance.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```tsx
|
|
211
|
+
* interface FormData { name: string; email: string }
|
|
212
|
+
*
|
|
213
|
+
* function MyPage() {
|
|
214
|
+
* const [data, setData] = useTabData<FormData>();
|
|
215
|
+
* // data : FormData
|
|
216
|
+
* // setData: (update: Partial<FormData>) => void
|
|
217
|
+
* }
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
declare function useTabData<TData = Record<string, unknown>>(instanceId?: string): [TData, (update: Partial<TData>) => void];
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Hook to retrieve the current tab's instance ID.
|
|
224
|
+
* Throws an error if used outside a TabInstanceContext.
|
|
225
|
+
* Extremely useful for integrating with Redux or when components
|
|
226
|
+
* need to automatically know which tab they belong to.
|
|
227
|
+
*/
|
|
228
|
+
declare function useTabInstanceId(): string;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create an immutable page registry from an array of page definitions.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* const registry = createPageRegistry([
|
|
236
|
+
* { id: 'dashboard', label: 'Dashboard', component: DashboardPage },
|
|
237
|
+
* { id: 'settings', label: 'Settings', component: SettingsPage },
|
|
238
|
+
* ]);
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @throws If any page is missing `id`, `label`, or `component`.
|
|
242
|
+
* @throws If duplicate `id` values are found.
|
|
243
|
+
*/
|
|
244
|
+
declare function createPageRegistry(pages: PageDefinition[]): PageRegistry;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* In-memory adapter — no URL synchronisation.
|
|
248
|
+
*
|
|
249
|
+
* This is the implicit default when no `adapter` prop is passed to
|
|
250
|
+
* `MultiTabProvider`. Useful for embedded UIs or tests.
|
|
251
|
+
*/
|
|
252
|
+
declare function memoryAdapter(): URLAdapter;
|
|
253
|
+
|
|
254
|
+
/** Options for {@link searchParamsAdapter}. */
|
|
255
|
+
interface SearchParamsAdapterOptions {
|
|
256
|
+
/** Query-string key for tab instance IDs. @default "tabs" */
|
|
257
|
+
tabsParam?: string;
|
|
258
|
+
/** Query-string key for the active tab. @default "active" */
|
|
259
|
+
activeParam?: string;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* URL adapter that uses the vanilla browser `URLSearchParams` +
|
|
263
|
+
* `history.replaceState` APIs.
|
|
264
|
+
*
|
|
265
|
+
* **No dependency on any router library** — works in any SPA.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```tsx
|
|
269
|
+
* import { searchParamsAdapter } from 'react-multi-tab';
|
|
270
|
+
*
|
|
271
|
+
* <MultiTabProvider adapter={searchParamsAdapter()} registry={registry}>
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
declare function searchParamsAdapter(options?: SearchParamsAdapterOptions): URLAdapter;
|
|
275
|
+
|
|
276
|
+
export { MultiTabProvider, MultiTabProviderProps, OpenTabOptions, PageDefinition, PageRegistry, type SearchParamsAdapterOptions, TabCloseButton, type TabCloseButtonProps, TabContent, TabInstance, TabList, type TabListProps, TabPanel, type TabPanelProps, TabPanels, type TabPanelsProps, TabTrigger, type TabTriggerProps, URLAdapter, type UseMultiTabReturn, createPageRegistry, memoryAdapter, searchParamsAdapter, useMultiTab, useTabData, useTabInstanceId };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { M as MultiTabProviderProps, T as TabInstance, O as OpenTabOptions, P as PageDefinition, a as PageRegistry, U as URLAdapter } from './types-Df_5I7eH.js';
|
|
3
|
+
export { b as MultiTabState, c as TabComponentProps } from './types-Df_5I7eH.js';
|
|
4
|
+
|
|
5
|
+
declare function MultiTabProvider({ registry, adapter, defaultActiveTab, children, onTabOpen, onTabClose, onTabChange, }: MultiTabProviderProps): react.JSX.Element;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Props for {@link TabList}.
|
|
9
|
+
*/
|
|
10
|
+
interface TabListProps {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
/** Accessible label for the tab list. */
|
|
13
|
+
"aria-label"?: string;
|
|
14
|
+
/** ID of an element that labels the tab list. */
|
|
15
|
+
"aria-labelledby"?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Accessible container for tab triggers.
|
|
21
|
+
*
|
|
22
|
+
* Implements the **WAI-ARIA Tabs** pattern:
|
|
23
|
+
* - `role="tablist"`
|
|
24
|
+
* - `Arrow Left / Right` — move focus between tabs
|
|
25
|
+
* - `Home / End` — jump to first / last tab
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* <TabList aria-label="Open pages">
|
|
30
|
+
* {tabs.map(t => <TabTrigger key={t.instanceId} instanceId={t.instanceId} />)}
|
|
31
|
+
* </TabList>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare function TabList({ children, className, style, ...ariaProps }: TabListProps): react.JSX.Element;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Props for {@link TabTrigger}.
|
|
38
|
+
*/
|
|
39
|
+
interface TabTriggerProps {
|
|
40
|
+
/** Instance ID of the tab this trigger controls. */
|
|
41
|
+
instanceId: string;
|
|
42
|
+
children: React.ReactNode;
|
|
43
|
+
className?: string;
|
|
44
|
+
style?: React.CSSProperties;
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Accessible tab trigger button.
|
|
49
|
+
*
|
|
50
|
+
* Implements the **WAI-ARIA** `tab` role:
|
|
51
|
+
* - `role="tab"`
|
|
52
|
+
* - `aria-selected` reflects active state
|
|
53
|
+
* - `aria-controls` points to the matching `tabpanel`
|
|
54
|
+
* - Roving `tabIndex` (`0` for active, `-1` for inactive)
|
|
55
|
+
* - `Enter` / `Space` activates the tab
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* <TabTrigger instanceId={tab.instanceId}>
|
|
60
|
+
* {tab.label}
|
|
61
|
+
* <TabCloseButton instanceId={tab.instanceId} />
|
|
62
|
+
* </TabTrigger>
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function TabTrigger({ instanceId, children, className, style, disabled, }: TabTriggerProps): react.JSX.Element;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Props for {@link TabPanel}.
|
|
69
|
+
*/
|
|
70
|
+
interface TabPanelProps {
|
|
71
|
+
/** Instance ID of the tab this panel belongs to. */
|
|
72
|
+
instanceId: string;
|
|
73
|
+
children: React.ReactNode;
|
|
74
|
+
/** Whether the panel is hidden (inactive tab). */
|
|
75
|
+
hidden?: boolean;
|
|
76
|
+
className?: string;
|
|
77
|
+
style?: React.CSSProperties;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Accessible tab panel.
|
|
81
|
+
*
|
|
82
|
+
* Implements the **WAI-ARIA** `tabpanel` role:
|
|
83
|
+
* - `role="tabpanel"`
|
|
84
|
+
* - `aria-labelledby` pointing to the matching `TabTrigger`
|
|
85
|
+
* - `tabIndex={0}` for keyboard focusability
|
|
86
|
+
* - Uses the `hidden` HTML attribute for inactive panels (keeps state
|
|
87
|
+
* mounted — no re-mount on tab switch).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```tsx
|
|
91
|
+
* <TabPanel instanceId={tab.instanceId} hidden={!isActive}>
|
|
92
|
+
* <MyPageComponent />
|
|
93
|
+
* </TabPanel>
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare function TabPanel({ instanceId, children, hidden, className, style, }: TabPanelProps): react.JSX.Element;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Props for {@link TabPanels}.
|
|
100
|
+
*/
|
|
101
|
+
interface TabPanelsProps {
|
|
102
|
+
className?: string;
|
|
103
|
+
style?: React.CSSProperties;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Renders **all** open tab panels and hides inactive ones.
|
|
107
|
+
*
|
|
108
|
+
* This is the simplest way to display tab content. Each page component
|
|
109
|
+
* receives its `instanceId`, `data`, and `setData` as props automatically.
|
|
110
|
+
*
|
|
111
|
+
* Inactive panels stay mounted (using the `hidden` attribute) so their
|
|
112
|
+
* state is preserved across tab switches.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```tsx
|
|
116
|
+
* <TabPanels />
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare function TabPanels({ className, style }: TabPanelsProps): react.JSX.Element;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Props for {@link TabCloseButton}.
|
|
123
|
+
*/
|
|
124
|
+
interface TabCloseButtonProps {
|
|
125
|
+
/** Instance ID of the tab to close. */
|
|
126
|
+
instanceId: string;
|
|
127
|
+
/** Custom content (default: `×`). */
|
|
128
|
+
children?: React.ReactNode;
|
|
129
|
+
className?: string;
|
|
130
|
+
style?: React.CSSProperties;
|
|
131
|
+
/** Override the auto-generated aria-label. */
|
|
132
|
+
"aria-label"?: string;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Button that closes a specific tab.
|
|
136
|
+
*
|
|
137
|
+
* Renders nothing if the tab's `closable` property is `false`.
|
|
138
|
+
* Prevents the click from bubbling to `TabTrigger` so it doesn't
|
|
139
|
+
* accidentally activate the tab.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* <TabTrigger instanceId={tab.instanceId}>
|
|
144
|
+
* {tab.label}
|
|
145
|
+
* <TabCloseButton instanceId={tab.instanceId} />
|
|
146
|
+
* </TabTrigger>
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function TabCloseButton({ instanceId, children, className, style, "aria-label": ariaLabel, }: TabCloseButtonProps): react.JSX.Element | null;
|
|
150
|
+
|
|
151
|
+
interface TabContentProps {
|
|
152
|
+
instanceId: string;
|
|
153
|
+
children: React.ReactNode;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* A wrapper component that provides the `TabInstanceContext` to all children.
|
|
157
|
+
* This allows hooks like `useTabData` and `useTabInstanceId` to automatically
|
|
158
|
+
* resolve the active tab's instanceId without it being explicitly passed.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* <TabContent instanceId={activeTab.instanceId}>
|
|
163
|
+
* <ActivePageComponent />
|
|
164
|
+
* </TabContent>
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
declare function TabContent({ instanceId, children }: TabContentProps): react.JSX.Element;
|
|
168
|
+
|
|
169
|
+
/** Public return type of {@link useMultiTab}. */
|
|
170
|
+
interface UseMultiTabReturn {
|
|
171
|
+
/** Currently open tabs. */
|
|
172
|
+
tabs: TabInstance[];
|
|
173
|
+
/** Instance ID of the active tab, or `null` if none. */
|
|
174
|
+
activeTabId: string | null;
|
|
175
|
+
/** Open a new tab for the given page ID. Returns the instance ID. */
|
|
176
|
+
openTab: (pageId: string, options?: OpenTabOptions) => string;
|
|
177
|
+
/** Close a tab by instance ID. */
|
|
178
|
+
closeTab: (instanceId: string) => void;
|
|
179
|
+
/** Activate (switch to) a tab by instance ID. */
|
|
180
|
+
activateTab: (instanceId: string) => void;
|
|
181
|
+
/** Close every open tab. */
|
|
182
|
+
closeAllTabs: () => void;
|
|
183
|
+
/** Close all tabs except the specified one. */
|
|
184
|
+
closeOtherTabs: (instanceId: string) => void;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Primary hook for managing tabs.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```tsx
|
|
191
|
+
* const { tabs, activeTabId, openTab, closeTab } = useMultiTab();
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
declare function useMultiTab(): UseMultiTabReturn;
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Read and write per-tab data with full TypeScript generics.
|
|
198
|
+
*
|
|
199
|
+
* When no `instanceId` is provided, the hook automatically targets the
|
|
200
|
+
* ID from the surrounding `TabContent`. If not inside a `TabContent`,
|
|
201
|
+
* it falls back to the globally active tab.
|
|
202
|
+
*
|
|
203
|
+
* This hook is highly optimized using `useSyncExternalStore` to prevent
|
|
204
|
+
* unnecessary re-renders. A component using this hook will ONLY re-render
|
|
205
|
+
* when the specific data for its resolved `instanceId` changes!
|
|
206
|
+
*
|
|
207
|
+
* @typeParam TData – Shape of the data stored for this tab instance.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```tsx
|
|
211
|
+
* interface FormData { name: string; email: string }
|
|
212
|
+
*
|
|
213
|
+
* function MyPage() {
|
|
214
|
+
* const [data, setData] = useTabData<FormData>();
|
|
215
|
+
* // data : FormData
|
|
216
|
+
* // setData: (update: Partial<FormData>) => void
|
|
217
|
+
* }
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
declare function useTabData<TData = Record<string, unknown>>(instanceId?: string): [TData, (update: Partial<TData>) => void];
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Hook to retrieve the current tab's instance ID.
|
|
224
|
+
* Throws an error if used outside a TabInstanceContext.
|
|
225
|
+
* Extremely useful for integrating with Redux or when components
|
|
226
|
+
* need to automatically know which tab they belong to.
|
|
227
|
+
*/
|
|
228
|
+
declare function useTabInstanceId(): string;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Create an immutable page registry from an array of page definitions.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* const registry = createPageRegistry([
|
|
236
|
+
* { id: 'dashboard', label: 'Dashboard', component: DashboardPage },
|
|
237
|
+
* { id: 'settings', label: 'Settings', component: SettingsPage },
|
|
238
|
+
* ]);
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @throws If any page is missing `id`, `label`, or `component`.
|
|
242
|
+
* @throws If duplicate `id` values are found.
|
|
243
|
+
*/
|
|
244
|
+
declare function createPageRegistry(pages: PageDefinition[]): PageRegistry;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* In-memory adapter — no URL synchronisation.
|
|
248
|
+
*
|
|
249
|
+
* This is the implicit default when no `adapter` prop is passed to
|
|
250
|
+
* `MultiTabProvider`. Useful for embedded UIs or tests.
|
|
251
|
+
*/
|
|
252
|
+
declare function memoryAdapter(): URLAdapter;
|
|
253
|
+
|
|
254
|
+
/** Options for {@link searchParamsAdapter}. */
|
|
255
|
+
interface SearchParamsAdapterOptions {
|
|
256
|
+
/** Query-string key for tab instance IDs. @default "tabs" */
|
|
257
|
+
tabsParam?: string;
|
|
258
|
+
/** Query-string key for the active tab. @default "active" */
|
|
259
|
+
activeParam?: string;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* URL adapter that uses the vanilla browser `URLSearchParams` +
|
|
263
|
+
* `history.replaceState` APIs.
|
|
264
|
+
*
|
|
265
|
+
* **No dependency on any router library** — works in any SPA.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```tsx
|
|
269
|
+
* import { searchParamsAdapter } from 'react-multi-tab';
|
|
270
|
+
*
|
|
271
|
+
* <MultiTabProvider adapter={searchParamsAdapter()} registry={registry}>
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
declare function searchParamsAdapter(options?: SearchParamsAdapterOptions): URLAdapter;
|
|
275
|
+
|
|
276
|
+
export { MultiTabProvider, MultiTabProviderProps, OpenTabOptions, PageDefinition, PageRegistry, type SearchParamsAdapterOptions, TabCloseButton, type TabCloseButtonProps, TabContent, TabInstance, TabList, type TabListProps, TabPanel, type TabPanelProps, TabPanels, type TabPanelsProps, TabTrigger, type TabTriggerProps, URLAdapter, type UseMultiTabReturn, createPageRegistry, memoryAdapter, searchParamsAdapter, useMultiTab, useTabData, useTabInstanceId };
|