@thoughtbot/superglue 2.0.0-alpha.10 → 2.0.0-alpha.11
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/dist/action_creators.d.mts +1 -1
- package/dist/action_creators.development.mjs +13 -0
- package/dist/action_creators.development.mjs.map +1 -0
- package/dist/action_creators.js +7 -0
- package/dist/action_creators.mjs +1 -1
- package/dist/chunk-AEIBTV6M.development.mjs +2860 -0
- package/dist/chunk-AEIBTV6M.development.mjs.map +1 -0
- package/dist/{chunk-J2XH5QTK.mjs → chunk-ILWYFGLA.mjs} +38 -8
- package/dist/chunk-ILWYFGLA.mjs.map +1 -0
- package/dist/cjs/action_creators.cjs +37 -7
- package/dist/cjs/action_creators.cjs.map +1 -1
- package/dist/cjs/action_creators.development.cjs +2791 -0
- package/dist/cjs/action_creators.development.cjs.map +1 -0
- package/dist/cjs/superglue.cjs +70 -9
- package/dist/cjs/superglue.cjs.map +1 -1
- package/dist/cjs/superglue.development.cjs +3215 -0
- package/dist/cjs/superglue.development.cjs.map +1 -0
- package/dist/{index-j0c-9ZLt.d.mts → index-DwEjetER.d.mts} +8 -10
- package/dist/index.js +7 -0
- package/dist/superglue.d.mts +2 -2
- package/dist/superglue.development.mjs +417 -0
- package/dist/superglue.development.mjs.map +1 -0
- package/dist/superglue.mjs +34 -3
- package/dist/superglue.mjs.map +1 -1
- package/npm/action_creators.js +7 -0
- package/npm/index.js +7 -0
- package/package.json +35 -11
- package/scripts/copy-wrappers.js +37 -0
- package/thoughtbot-superglue-2.0.0-alpha.11.tgz +0 -0
- package/tsconfig.json +1 -0
- package/tsup.config.ts +57 -1
- package/dist/chunk-J2XH5QTK.mjs.map +0 -1
- package/thoughtbot-superglue-2.0.0-alpha.10.tgz +0 -0
package/dist/superglue.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../lib/index.tsx","../lib/hooks/useStreamSource.tsx","../lib/hooks/index.ts","../lib/hooks/useContent.tsx","../lib/hooks/useSetFragment.tsx","../lib/components/Navigation.tsx","../lib/reducers/index.ts"],"sourcesContent":["import React, { useRef, useMemo } from 'react'\nimport { config } from './config'\nimport { urlToPageKey, ujsHandlers, argsForHistory } from './utils'\nimport { saveAndProcessPage } from './action_creators'\nimport { historyChange, setCSRFToken, receiveResponse } from './actions'\nimport { Provider } from 'react-redux'\n\nimport { CableContext, StreamActions } from './hooks/useStreamSource'\nimport { createConsumer } from '@rails/actioncable'\n\nimport { createBrowserHistory, createMemoryHistory } from 'history'\n\nimport { NavigationProvider } from './components/Navigation'\nexport { NavigationProvider, NavigationContext } from './components/Navigation'\nexport { saveAndProcessPage } from './action_creators'\nexport {\n beforeFetch,\n beforeVisit,\n beforeRemote,\n copyPage,\n removePage,\n saveResponse,\n receiveResponse,\n GRAFTING_ERROR,\n GRAFTING_SUCCESS,\n} from './actions'\nexport * from './types'\n\nimport {\n SaveResponse,\n ApplicationProps,\n NavigateTo,\n SuperglueStore,\n SetupProps,\n} from './types'\nexport { superglueReducer, pageReducer, rootReducer } from './reducers'\nexport { getIn } from './utils/immutability'\nexport { urlToPageKey }\nexport * from './hooks'\nexport { unproxy } from './hooks/useContent'\n\nfunction getConfig(name: string) {\n if (typeof document !== 'undefined') {\n const element = document.head.querySelector(\n `meta[name='action-cable-${name}']`\n )\n if (element) {\n return element.getAttribute('content') || '/cable'\n } else {\n return '/cable'\n }\n } else {\n return '/cable'\n }\n}\n\nconst cable = createConsumer(getConfig('url'))\n\nconst hasWindow = typeof window !== 'undefined'\n\nconst createHistory = () => {\n if (hasWindow) {\n // This is used for client side rendering\n return createBrowserHistory({})\n } else {\n // This is used for server side rendering\n return createMemoryHistory({})\n }\n}\n\nexport const prepareStore = (\n store: SuperglueStore,\n initialPage: SaveResponse,\n path: string\n) => {\n const initialPageKey = urlToPageKey(path)\n const { csrfToken } = initialPage\n\n store.dispatch(\n historyChange({\n pageKey: initialPageKey,\n })\n )\n store.dispatch(\n receiveResponse({ pageKey: initialPageKey, response: initialPage })\n )\n store.dispatch(saveAndProcessPage(initialPageKey, initialPage))\n store.dispatch(setCSRFToken({ csrfToken }))\n}\n\n/**\n * This is the setup function that the Application calls. Use this function if\n * you like to build your own Application component.\n */\nexport const setup = ({\n initialPage,\n baseUrl,\n path,\n store,\n buildVisitAndRemote,\n history,\n navigatorRef,\n}: SetupProps) => {\n config.baseUrl = baseUrl\n\n const { visit, remote } = buildVisitAndRemote(navigatorRef, store)\n\n const initialPageKey = urlToPageKey(path)\n const nextHistory = history || createHistory()\n nextHistory.replace(...argsForHistory(path))\n prepareStore(store, initialPage, path)\n\n const handlers = ujsHandlers({\n visit,\n remote,\n ujsAttributePrefix: 'data-sg',\n store,\n })\n\n const streamActions = new StreamActions({ remote, store })\n\n return {\n visit,\n remote,\n nextHistory,\n initialPageKey,\n ujs: handlers,\n streamActions,\n }\n}\n\n/**\n * The entry point to your superglue application. It sets up the redux Provider,\n * redux state and the Navigation component.\n *\n * This is a simple component, you can override this by copying the source code and\n * use the exported methods used by this component (`start` and `ujsHandler`).\n */\nfunction Application({\n initialPage,\n baseUrl,\n path,\n store,\n buildVisitAndRemote,\n history,\n mapping,\n ...rest\n}: ApplicationProps) {\n const navigatorRef = useRef<{ navigateTo: NavigateTo } | null>(null)\n\n const { visit, remote, nextHistory, initialPageKey, ujs, streamActions } =\n useMemo(() => {\n return setup({\n initialPage,\n baseUrl,\n path,\n store,\n buildVisitAndRemote,\n history,\n navigatorRef,\n })\n }, [])\n\n // The Nav component is pretty bare and can be inherited from for custom\n // behavior or replaced with your own.\n return (\n <div onClick={ujs.onClick} onSubmit={ujs.onSubmit} {...rest}>\n <Provider store={store}>\n <CableContext.Provider value={{ streamActions, cable }}>\n <NavigationProvider\n ref={navigatorRef}\n visit={visit}\n remote={remote}\n mapping={mapping}\n history={nextHistory}\n initialPageKey={initialPageKey}\n />\n </CableContext.Provider>\n </Provider>\n </div>\n )\n}\n\nexport { Application }\n","import {\n ChannelNameWithParams,\n Consumer,\n Subscription,\n} from '@rails/actioncable'\nimport { useState, useEffect, useRef, createContext, useContext } from 'react'\nimport { ApplicationRemote, FragmentPath } from '../types'\nimport { useSuperglue } from '.'\nimport debounce from 'lodash.debounce'\nimport type { DebouncedFunc } from 'lodash'\nimport { lastRequestIds } from '../utils'\nimport {\n streamPrepend,\n streamAppend,\n streamSave,\n handleStreamMessage,\n} from '../action_creators/stream'\n\n/**\n * Channel configuration for stream sources\n * @public\n */\nexport type StreamSourceProps = string | ChannelNameWithParams\n\nexport type StreamMessage =\n | {\n action: 'handleStreamMessage'\n data: JSONMappable\n fragmentIds: string[]\n handler: 'append' | 'prepend' | 'save'\n options: Record<string, string>\n fragments: FragmentPath[]\n }\n | {\n action: 'handleStreamMessage'\n handler: 'refresh'\n requestId: string\n options: Record<string, string>\n }\n\nimport { SuperglueStore, JSONMappable } from '../types'\n\n/**\n * Actions for handling stream operations like append, prepend, save and refresh\n * @public\n */\nexport class StreamActions {\n public attributePrefix: string\n public remote: DebouncedFunc<ApplicationRemote>\n private store: SuperglueStore\n\n constructor({\n remote,\n store,\n }: {\n remote: ApplicationRemote\n store: SuperglueStore\n }) {\n this.store = store\n this.remote = debounce(remote, 300)\n }\n\n refresh(pageKey: string) {\n this.remote(pageKey)\n }\n\n prepend(\n fragments: string[],\n data: JSONMappable,\n options: { saveAs?: string } = {}\n ) {\n this.store.dispatch(streamPrepend(fragments, data, options))\n }\n\n save(fragment: string, data: JSONMappable) {\n this.store.dispatch(streamSave(fragment, data))\n }\n\n append(\n fragments: string[],\n data: JSONMappable,\n options: { saveAs?: string } = {}\n ) {\n this.store.dispatch(streamAppend(fragments, data, options))\n }\n\n handle(rawMessage: string, currentPageKey: string) {\n const message = JSON.parse(rawMessage) as StreamMessage\n const { superglue } = this.store.getState()\n const nextPageKey = superglue.currentPageKey\n\n if (message.action === 'handleStreamMessage') {\n if (\n message.handler === 'refresh' &&\n currentPageKey === nextPageKey &&\n !lastRequestIds.has(message.requestId)\n ) {\n this.refresh(currentPageKey)\n }\n\n if (message.handler !== 'refresh') {\n this.store.dispatch(handleStreamMessage(rawMessage))\n }\n }\n }\n}\n\nexport const CableContext = createContext<{\n cable: Consumer | null\n streamActions: StreamActions | null\n}>({\n cable: null,\n streamActions: null,\n})\n\n/**\n * Creates a subscription to an ActionCable channel for real-time streaming\n * updates.\n *\n * This hook manages the lifecycle of an ActionCable subscription, automatically\n * connecting when the cable is available and cleaning up on unmount. Stream\n * messages are processed through StreamActions to update the Redux store.\n *\n * Typically used with channel configuration generated by the Rails helper\n * `stream_from_props` helper in your `props` templates.\n *\n * * @example\n * Using the helper:\n *\n * ```ruby\n * # app/views/chat_rooms/show.json.props\n * json.chatChannel stream_from_props(\"messages\")\n * ```\n * ```tsx\n * const content = useContent()\n * const { connected } = useStreamSource(content.chatChannel)\n * ```\n *\n * @example\n * Basic channel subscription:\n * ```tsx\n * const { connected } = useStreamSource('ChatChannel')\n * ```\n *\n * @example\n * Channel with parameters:\n * ```tsx\n * const { connected } = useStreamSource({\n * channel: 'ChatChannel',\n * room_id: roomId\n * })\n * ```\n *\n * @example\n * Using connection status:\n * ```tsx\n * const { connected, subscription } = useStreamSource('NotificationsChannel')\n *\n * return (\n * <div>\n * {connected ? 'Connected' : 'Connecting...'}\n * {subscription && <span>Subscription active</span>}\n * </div>\n * )\n * ```\n *\n * @param channel - Channel configuration as string or ChannelNameWithParams object,\n * typically generated by Rails `stream_from_props` helper\n * @returns Object containing connection status and subscription instance\n *\n * @public\n */\nexport function useStreamSource(channel: StreamSourceProps): {\n /** Whether the ActionCable subscription is currently connected */\n connected: boolean\n /** The active ActionCable subscription instance, null if not connected */\n subscription: Subscription | null\n} {\n const { cable, streamActions } = useContext(CableContext)\n const [connected, setConnected] = useState(false)\n const { currentPageKey } = useSuperglue()\n const subscriptionRef = useRef<Subscription | null>(null)\n\n useEffect(() => {\n if (cable) {\n const subscription = cable.subscriptions.create(channel, {\n received: (message) => {\n streamActions?.handle(message, currentPageKey)\n },\n connected: () => {\n setConnected(true)\n },\n disconnected: () => setConnected(false),\n })\n\n subscriptionRef.current = subscription\n\n return () => subscription.unsubscribe()\n } else {\n subscriptionRef.current = null\n setConnected(false)\n\n return () => {}\n }\n }, [cable, JSON.stringify(channel), currentPageKey])\n\n return {\n connected,\n subscription: subscriptionRef.current,\n }\n}\n","import { useSelector } from 'react-redux'\nimport { RootState, SuperglueState } from '../types'\nexport { useContent, unproxy } from './useContent'\nexport { useSetFragment } from './useSetFragment'\nexport { useStreamSource } from './useStreamSource'\n\n/**\n * A lightweight hook that grabs the superglue state from the store.\n */\nexport function useSuperglue() {\n return useSelector<RootState, SuperglueState>((state) => state.superglue)\n}\n","import { useSelector, useStore } from 'react-redux'\nimport { useMemo, useRef } from 'react'\nimport {\n JSONMappable,\n RootState,\n Unproxy,\n Fragment,\n FragmentRef,\n} from '../types'\nimport { useSuperglue } from './index'\nimport { createProxy, unproxy as unproxyUtil } from '../utils/proxy'\n\nexport type FragmentProxy = { __fragment: true }\n\n/**\n * A proxy type that enables reactive access to nested content with automatic fragment resolution\n */\nexport type ProxiedContent<T> = T extends Fragment<infer U, true>\n ? ProxiedContent<U> & FragmentProxy\n : T extends Fragment<infer U, false | undefined>\n ? (ProxiedContent<U> & FragmentProxy) | undefined\n : T extends (infer U)[]\n ? ProxiedContent<U>[]\n : T extends object\n ? { [K in keyof T]: ProxiedContent<T[K]> }\n : T\n\n/**\n * Union type for fragment references, accepting either FragmentRef objects or string IDs\n * @public\n */\nexport type FragmentRefOrId = FragmentRef | string\n\n/**\n * Returns a proxy for accessing your page's content e.g, `index.json.props`,\n * `show.json.props`, etc.\n *\n * For advanced scenarios where you are using Fragments.\n *\n * ```js\n * {\n * data: {\n * body: {\n * cart: {__id: 'user_cart'}\n * },\n * footer: {title: \"welcome\"}},\n * },\n * fragments: {user_cart: {total: 100}}\n * }\n * ```\n *\n * The proxy will lazily and automatically resolve any {@link FragmentRef}s making it\n * as easy as\n *\n * ```\n * const data = useContent()\n * const total = data.body.cart.total\n * ```\n *\n * The hook will also automatically tracks fragment dependencies and triggers\n * re-renders only when accessed fragments change.\n *\n * @template T - The data type being accessed (defaults to JSONMappable)\n * @returns Reactive proxy to page data or fragment data, undefined if fragment not found\n *\n * @example\n * ```tsx\n * // Access current page data\n * const page = useContent()\n *\n * // Access specific fragment by reference\n * const user = useContent({__id: 'user_123'})\n *\n * // Access specific fragment by ID string\n * const cart = useContent('userCart')\n * ```\n */\nexport function useContent<T = JSONMappable>(): ProxiedContent<T>\n\n/**\n * Passing in a fragment to useContent allows us to scope the tracking of\n * fragments to that hook usage. Its useful in performance scenarios where you\n * want a child component to update, but not the parent.\n *\n *\n * ```js\n * import {unproxy} from '@thoughtbot/superglue'\n *\n * const content = useContent()\n * const rawContent = unproxy(content)\n *\n * <h1>{content.title}</h1>\n * <SlidingCart cartRef={rawContent.cart} />\n * ```\n *\n * then in SlidingCart\n *\n * ```js\n * const SlidingCart = (cartRef) => {\n * const cart = useContent(cartRef)\n * }\n * ```\n *\n * SlidingCart will update only if the fragment referenced by `cartRef` updates.\n *\n * @param fragmentRef Optional fragment reference for scoped access\n */\nexport function useContent<T = JSONMappable>(\n fragmentRef: FragmentRefOrId\n): ProxiedContent<T>\nexport function useContent<T = JSONMappable>(\n fragmentRef?: FragmentRefOrId\n): ProxiedContent<T> | undefined {\n const superglueState = useSuperglue()\n const currentPageKey = superglueState.currentPageKey\n\n const dependencies = useRef<Set<string>>(new Set())\n // const fragmentsHookRef = useRef<RootState['fragments']>({})\n\n const fragmentId =\n typeof fragmentRef === 'string' ? fragmentRef : fragmentRef?.__id\n const sourceData = useSelector((state: RootState) => {\n if (fragmentId) {\n return state.fragments[fragmentId]\n } else {\n return state.pages[currentPageKey].data\n }\n })\n\n const trackedFragments = useSelector(\n (state: RootState) => state.fragments,\n (oldFragments, newFragments) => {\n if (oldFragments === newFragments) {\n return true\n }\n\n return Array.from(dependencies.current).every((id: string) => {\n const prevVal = oldFragments[id]\n const nextVal = newFragments[id]\n return prevVal === nextVal\n })\n }\n )\n\n // Update the ref BEFORE the useMemo so proxy creation sees current fragments\n // fragmentsHookRef.current = fragments\n\n const store = useStore<RootState>()\n\n const proxy = useMemo(() => {\n const proxyCache = new WeakMap()\n\n if (fragmentId && !sourceData) {\n return undefined\n }\n\n return createProxy(\n sourceData,\n { current: store.getState().fragments },\n dependencies.current,\n proxyCache\n ) as ProxiedContent<T>\n }, [sourceData, trackedFragments])\n\n return proxy\n}\n\n/**\n * Extracts the underlying state from an {@link useContent} proxy\n *\n */\nexport function unproxy<T>(proxy: T): Unproxy<T> {\n return unproxyUtil(proxy)\n}\n","import { useDispatch, useSelector } from 'react-redux'\nimport { Immer } from 'immer'\nimport { saveFragment } from '../actions'\nimport { RootState, Fragment } from '../types'\nimport { Unproxy } from '../types'\nimport { FragmentProxy } from './useContent'\n\nconst immer = new Immer()\nimmer.setAutoFreeze(false)\n\n/**\n * Utility type to extract the data type from a Fragment wrapper\n * @public\n */\nexport type Unpack<T> = T extends Fragment<infer U, unknown>\n ? U\n : T extends FragmentProxy\n ? T\n : never\n/**\n * Hook for mutating fragments using Immer drafts.\n *\n * @example\n * ```tsx\n * const set = useSetFragment()\n *\n * // Update via fragment reference\n * set(userRef, draft => {\n * draft.name = \"Updated Name\"\n * draft.email = \"new@email.com\"\n * })\n *\n * // Update via fragment ID directly\n * set('user_123', draft => {\n * draft.profile.bio = \"Updated bio\"\n * })\n * ```\n *\n */\nexport function useSetFragment() {\n const dispatch = useDispatch()\n const fragments = useSelector((state: RootState) => state.fragments)\n\n /**\n * Updates a fragment using a {@link FragmentRef} object.\n *\n * @param fragmentRef - Fragment reference object containing __id\n * @param updater - Immer draft function for mutating fragment data\n */\n function setter<T extends Fragment<unknown, unknown>>(\n fragmentRef: T,\n updater: (draft: Unproxy<Unpack<T>>) => void\n ): void\n\n /**\n * Updates a fragment using a fragment ID string.\n *\n * @param fragmentId - The fragment ID string\n * @param updater - Immer draft function for mutating fragment data\n */\n function setter<T = unknown>(\n fragmentId: string,\n updater: (draft: T) => void\n ): void\n\n function setter(\n fragmentRefOrId: Fragment<unknown, unknown> | string,\n updater: (draft: unknown) => void\n ): void {\n const fragmentId =\n typeof fragmentRefOrId === 'string'\n ? fragmentRefOrId\n : fragmentRefOrId.__id\n\n const currentFragment = fragments[fragmentId]\n\n if (currentFragment === undefined) {\n throw new Error(`Fragment with id \"${fragmentId}\" not found`)\n }\n\n const updatedFragment = immer.produce(currentFragment, updater)\n\n dispatch(\n saveFragment({\n fragmentId: fragmentId,\n data: updatedFragment,\n })\n )\n }\n\n return setter\n}\n","import React, {\n createContext,\n useEffect,\n useLayoutEffect,\n forwardRef,\n useImperativeHandle,\n ForwardedRef,\n} from 'react'\nimport { urlToPageKey } from '../utils'\nimport { removePage, setActivePage } from '../actions'\nimport {\n HistoryState,\n RootState,\n NavigateTo,\n NavigationContextProps,\n NavigationProviderProps,\n AllPages,\n SuperglueState,\n} from '../types'\nimport { Update } from 'history'\nimport { useDispatch, useSelector, useStore } from 'react-redux'\n\nconst NavigationContext = createContext<NavigationContextProps>(\n {} as NavigationContextProps\n)\n\nconst hasWindow = typeof window !== 'undefined'\n\nconst setWindowScroll = (posX: number, posY: number): void => {\n hasWindow && window.scrollTo(posX, posY)\n}\n\nconst notFound = (identifier: string | undefined): never => {\n let reminder = ''\n if (!identifier) {\n reminder =\n 'Did you forget to add `json.componentIdentifier` in your application.json.props layout?'\n }\n\n const error = new Error(\n `Superglue Nav component was looking for ${identifier} but could not find it in your mapping. ${reminder}`\n )\n\n throw error\n}\n\nconst NavigationProvider = forwardRef(function NavigationProvider(\n { history, visit, remote, mapping }: NavigationProviderProps,\n ref: ForwardedRef<{ navigateTo: NavigateTo | null }>\n) {\n const dispatch = useDispatch()\n const pages = useSelector<RootState, AllPages>((state) => state.pages)\n const superglue = useSelector<RootState, SuperglueState>(\n (state) => state.superglue\n )\n const currentPageKey = useSelector<RootState, string>(\n (state) => state.superglue.currentPageKey\n )\n const store = useStore<RootState>()\n\n useEffect(() => {\n return history.listen(onHistoryChange)\n }, [])\n\n useLayoutEffect(() => {\n const state = history.location.state as HistoryState\n if (state && 'superglue' in state) {\n const { posX, posY } = state\n setWindowScroll(posX, posY)\n }\n }, [currentPageKey])\n\n useImperativeHandle(\n ref,\n () => {\n return {\n navigateTo,\n }\n },\n []\n )\n\n const onHistoryChange = ({ location, action }: Update): void => {\n const state = location.state as HistoryState\n\n if (action !== 'POP') {\n return\n }\n\n if (!state && location.hash !== '') {\n const nextPageKey = urlToPageKey(location.pathname + location.search)\n const containsKey = !!pages[nextPageKey]\n if (containsKey) {\n history.replace(\n {\n pathname: location.pathname,\n search: location.search,\n hash: location.hash,\n },\n {\n superglue: true,\n posY: window.pageYOffset,\n posX: window.pageXOffset,\n }\n )\n }\n }\n\n if (state && 'superglue' in state) {\n const pageKey = urlToPageKey(location.pathname + location.search)\n const prevPageKey = store.getState().superglue.currentPageKey\n const containsKey = !!pages[pageKey]\n\n if (containsKey) {\n const { restoreStrategy } = pages[pageKey]\n\n switch (restoreStrategy) {\n case 'fromCacheOnly':\n dispatch(setActivePage({ pageKey }))\n break\n case 'fromCacheAndRevisitInBackground':\n dispatch(setActivePage({ pageKey }))\n visit(pageKey, { revisit: true })\n break\n case 'revisitOnly':\n default:\n visit(pageKey, { revisit: true }).then(() => {\n const noNav =\n prevPageKey === store.getState().superglue.currentPageKey\n if (noNav) {\n // When \"POP'ed\", revisiting (using revisit: true) a page can result in\n // a redirect, or a render of the same page.\n //\n // When its a redirect, calculateNavAction will correctly set the\n // navigationAction to `replace` this is the noop scenario.\n //\n // When its the same page, navigationAction is set to `none` and\n // no navigation took place. In that case, we have to set the\n // activePage otherwise the user is stuck on the original page.\n dispatch(setActivePage({ pageKey }))\n }\n })\n }\n } else {\n visit(pageKey, { revisit: true }).then(() => {\n const noNav =\n prevPageKey === store.getState().superglue.currentPageKey\n if (noNav) {\n dispatch(setActivePage({ pageKey }))\n }\n })\n }\n }\n }\n\n const navigateTo: NavigateTo = (\n path,\n { action } = {\n action: 'push',\n }\n ) => {\n if (action === 'none') {\n return false\n }\n\n const nextPageKey = urlToPageKey(path)\n const hasPage = Object.prototype.hasOwnProperty.call(\n store.getState().pages,\n nextPageKey\n )\n\n if (hasPage) {\n const location = history.location\n const state = location.state as HistoryState\n const historyArgs = [\n path,\n {\n superglue: true,\n posY: 0,\n posX: 0,\n },\n ] as const\n\n if (action === 'push') {\n if (hasWindow) {\n history.replace(\n {\n pathname: location.pathname,\n search: location.search,\n hash: location.hash,\n },\n {\n ...state,\n posY: window.scrollY,\n posX: window.scrollX,\n }\n )\n }\n\n history.push(...historyArgs)\n dispatch(setActivePage({ pageKey: nextPageKey }))\n }\n\n if (action === 'replace') {\n history.replace(...historyArgs)\n\n if (currentPageKey !== nextPageKey) {\n dispatch(setActivePage({ pageKey: nextPageKey }))\n dispatch(removePage({ pageKey: currentPageKey }))\n }\n }\n return true\n } else {\n console.warn(\n `\\`navigateTo\\` was called , but could not find\n the pageKey in the store. This may happen when the wrong\n content_location was set in your non-get controller action.\n No navigation will take place`\n )\n return false\n }\n }\n\n const { search } = superglue\n const { componentIdentifier } = pages[currentPageKey]\n const Component = mapping[componentIdentifier]\n\n if (Component) {\n return (\n <NavigationContext.Provider\n value={{ pageKey: currentPageKey, search, navigateTo, visit, remote }}\n >\n <Component />\n </NavigationContext.Provider>\n )\n } else {\n notFound(componentIdentifier)\n }\n})\n\nexport { NavigationContext, NavigationProvider }\n","import { setIn, urlToPageKey, parsePageKey } from '../utils'\nimport type { Action } from '@reduxjs/toolkit'\nimport {\n saveResponse,\n handleGraft,\n historyChange,\n copyPage,\n setCSRFToken,\n setActivePage,\n removePage,\n handleFragmentGraft,\n saveFragment,\n appendToFragment,\n prependToFragment,\n} from '../actions'\nimport { config } from '../config'\nimport {\n AllPages,\n Page,\n SaveResponse,\n FragmentPath,\n GraftResponse,\n SuperglueState,\n JSONMappable,\n AllFragments,\n} from '../types'\n\nfunction constrainPagesSize(state: AllPages) {\n const { maxPages } = config\n const allPageKeys = Object.keys(state)\n const cacheTimesRecentFirst = allPageKeys\n .map((key) => state[key].savedAt)\n .sort((a, b) => b - a)\n\n for (const key of Array.from(allPageKeys)) {\n if (state[key].savedAt <= cacheTimesRecentFirst[maxPages - 1]) {\n delete state[key]\n }\n }\n}\n\nfunction handleSaveResponse(\n state: AllPages,\n pageKey: string,\n page: SaveResponse\n): AllPages {\n state = { ...state }\n\n const nextPage: Page = {\n ...page,\n savedAt: Date.now(),\n }\n constrainPagesSize(state)\n state[pageKey] = nextPage\n\n return state\n}\n\nexport function appendReceivedFragmentsOntoPage(\n state: AllPages,\n pageKey: string,\n receivedFragments: FragmentPath[]\n): AllPages {\n if (!pageKey) {\n return state\n }\n\n if (receivedFragments.length === 0) {\n return state\n }\n\n const currentPage = state[pageKey]\n const { fragments: prevFragments = [] } = currentPage\n const nextFragments = [...prevFragments]\n const existingKeys: Record<string, boolean> = {}\n prevFragments.forEach((frag) => (existingKeys[frag.path] = true))\n\n receivedFragments.forEach((frag) => {\n if (!existingKeys[frag.path]) {\n nextFragments.push(frag)\n }\n })\n\n const nextPage = {\n ...currentPage,\n fragments: nextFragments,\n }\n\n const nextState = { ...state }\n nextState[pageKey] = nextPage\n\n return nextState\n}\n\nexport function graftNodeOntoTarget<T extends JSONMappable>(\n state: T,\n pageKey: string,\n node: JSONMappable,\n pathToNode: string\n): T {\n if (!node) {\n console.warn(\n 'There was no node returned in the response. Do you have the correct key path in your props_at?'\n )\n return state\n }\n\n if (!pathToNode || !pageKey) {\n return state\n }\n const fullPathToNode = [pageKey, pathToNode].join('.')\n return setIn(state, fullPathToNode, node)\n}\n\nfunction handleFragmentGraftResponse(\n state: AllFragments,\n key: string,\n response: GraftResponse\n): AllFragments {\n const target = state[key]\n\n if (!target) {\n const error = new Error(\n `Superglue was looking for ${key} in your fragments, but could not find it.`\n )\n throw error\n }\n const { data: receivedNode, path: pathToNode } = response\n\n return graftNodeOntoTarget(state, key, receivedNode, pathToNode)\n}\n\nfunction handleGraftResponse(\n state: AllPages,\n pageKey: string,\n page: GraftResponse\n): AllPages {\n const currentPage = state[pageKey]\n if (!currentPage) {\n const error = new Error(\n `Superglue was looking for ${pageKey} in your state, but could not find it in your mapping. Did you forget to pass in a valid pageKey to this.props.remote or this.props.visit?`\n )\n throw error\n }\n const {\n data: receivedNode,\n path: pathToNode,\n fragments: receivedFragments = [],\n } = page\n\n return [\n (nextState: AllPages) =>\n graftNodeOntoTarget(nextState, pageKey, receivedNode, pathToNode),\n (nextState: AllPages) =>\n appendReceivedFragmentsOntoPage(nextState, pageKey, receivedFragments),\n ].reduce((memo, fn) => fn(memo), state)\n}\n\nexport function pageReducer(state: AllPages = {}, action: Action): AllPages {\n if (removePage.match(action)) {\n const { pageKey } = action.payload\n const nextState = { ...state }\n delete nextState[pageKey]\n\n return nextState\n }\n\n if (copyPage.match(action)) {\n const nextState = { ...state }\n const { from, to } = action.payload\n\n nextState[urlToPageKey(to)] = JSON.parse(JSON.stringify(nextState[from]))\n\n return nextState\n }\n\n if (handleGraft.match(action)) {\n const { pageKey, page } = action.payload\n\n return handleGraftResponse(state, pageKey, page)\n }\n\n if (saveResponse.match(action)) {\n const { pageKey, page } = action.payload\n const nextState = handleSaveResponse(state, pageKey, page)\n return nextState\n }\n\n return state\n}\n\nexport function superglueReducer(\n state: SuperglueState = {\n currentPageKey: '',\n search: {},\n assets: [],\n },\n action: Action\n): SuperglueState {\n if (setCSRFToken.match(action)) {\n const { csrfToken } = action.payload\n return { ...state, csrfToken: csrfToken }\n }\n\n if (setActivePage.match(action)) {\n const { pageKey } = action.payload\n const { search } = parsePageKey(pageKey)\n\n return {\n ...state,\n search,\n currentPageKey: pageKey,\n }\n }\n\n if (historyChange.match(action)) {\n const { pageKey } = action.payload\n const { search } = parsePageKey(pageKey)\n\n return {\n ...state,\n currentPageKey: pageKey,\n search,\n }\n }\n\n if (saveResponse.match(action)) {\n const {\n page: { csrfToken, assets },\n } = action.payload\n\n return { ...state, csrfToken, assets }\n }\n\n return state\n}\n\nexport function fragmentReducer(\n state: AllFragments = {},\n action: Action\n): AllFragments {\n if (handleFragmentGraft.match(action)) {\n const { fragmentId, response } = action.payload\n return handleFragmentGraftResponse(state, fragmentId, response)\n }\n\n if (saveFragment.match(action)) {\n const { fragmentId, data } = action.payload\n\n return {\n ...state,\n [fragmentId]: data,\n }\n }\n\n if (appendToFragment.match(action)) {\n const { data, fragmentId } = action.payload\n let targetFragment = state[fragmentId]\n\n if (Array.isArray(targetFragment)) {\n targetFragment = [...targetFragment, data]\n\n return {\n ...state,\n [fragmentId]: targetFragment,\n }\n } else {\n return state\n }\n }\n\n if (prependToFragment.match(action)) {\n const { data, fragmentId } = action.payload\n let targetFragment = state[fragmentId]\n\n if (Array.isArray(targetFragment)) {\n targetFragment = [data, ...targetFragment]\n return {\n ...state,\n [fragmentId]: targetFragment,\n }\n } else {\n return state\n }\n }\n\n return state\n}\n\nexport const rootReducer = {\n superglue: superglueReducer,\n pages: pageReducer,\n fragments: fragmentReducer,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAOA,UAAS,UAAAC,SAAQ,WAAAC,gBAAe;AAKvC,SAAS,gBAAgB;;;ACAzB,SAAS,UAAU,WAAW,UAAAC,SAAQ,eAAe,kBAAkB;;;ACLvE,SAAS,eAAAC,oBAAmB;;;ACA5B,SAAS,aAAa,gBAAgB;AACtC,SAAS,SAAS,cAAc;AA6GzB,SAAS,WACd,aAC+B;AAC/B,QAAM,iBAAiB,aAAa;AACpC,QAAM,iBAAiB,eAAe;AAEtC,QAAM,eAAe,OAAoB,oBAAI,IAAI,CAAC;AAGlD,QAAM,aACJ,OAAO,gBAAgB,WAAW,cAAc,aAAa;AAC/D,QAAM,aAAa,YAAY,CAAC,UAAqB;AACnD,QAAI,YAAY;AACd,aAAO,MAAM,UAAU,UAAU;AAAA,IACnC,OAAO;AACL,aAAO,MAAM,MAAM,cAAc,EAAE;AAAA,IACrC;AAAA,EACF,CAAC;AAED,QAAM,mBAAmB;AAAA,IACvB,CAAC,UAAqB,MAAM;AAAA,IAC5B,CAAC,cAAc,iBAAiB;AAC9B,UAAI,iBAAiB,cAAc;AACjC,eAAO;AAAA,MACT;AAEA,aAAO,MAAM,KAAK,aAAa,OAAO,EAAE,MAAM,CAAC,OAAe;AAC5D,cAAM,UAAU,aAAa,EAAE;AAC/B,cAAM,UAAU,aAAa,EAAE;AAC/B,eAAO,YAAY;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AAKA,QAAM,QAAQ,SAAoB;AAElC,QAAM,QAAQ,QAAQ,MAAM;AAC1B,UAAM,aAAa,oBAAI,QAAQ;AAE/B,QAAI,cAAc,CAAC,YAAY;AAC7B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL;AAAA,MACA,EAAE,SAAS,MAAM,SAAS,EAAE,UAAU;AAAA,MACtC,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF,GAAG,CAAC,YAAY,gBAAgB,CAAC;AAEjC,SAAO;AACT;AAMO,SAASC,SAAW,OAAsB;AAC/C,SAAO,QAAY,KAAK;AAC1B;;;AC7KA,SAAS,aAAa,eAAAC,oBAAmB;AACzC,SAAS,aAAa;AAMtB,IAAM,QAAQ,IAAI,MAAM;AACxB,MAAM,cAAc,KAAK;AA+BlB,SAAS,iBAAiB;AAC/B,QAAM,WAAW,YAAY;AAC7B,QAAM,YAAYC,aAAY,CAAC,UAAqB,MAAM,SAAS;AAwBnE,WAAS,OACP,iBACA,SACM;AACN,UAAM,aACJ,OAAO,oBAAoB,WACvB,kBACA,gBAAgB;AAEtB,UAAM,kBAAkB,UAAU,UAAU;AAE5C,QAAI,oBAAoB,QAAW;AACjC,YAAM,IAAI,MAAM,qBAAqB,UAAU,aAAa;AAAA,IAC9D;AAEA,UAAM,kBAAkB,MAAM,QAAQ,iBAAiB,OAAO;AAE9D;AAAA,MACE,aAAa;AAAA,QACX;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;AFlFO,SAAS,eAAe;AAC7B,SAAOC,aAAuC,CAAC,UAAU,MAAM,SAAS;AAC1E;;;ADHA,OAAO,cAAc;AAsCd,IAAM,gBAAN,MAAoB;AAAA,EAKzB,YAAY;AAAA,IACV;AAAA,IACA;AAAA,EACF,GAGG;AACD,SAAK,QAAQ;AACb,SAAK,SAAS,SAAS,QAAQ,GAAG;AAAA,EACpC;AAAA,EAEA,QAAQ,SAAiB;AACvB,SAAK,OAAO,OAAO;AAAA,EACrB;AAAA,EAEA,QACE,WACA,MACA,UAA+B,CAAC,GAChC;AACA,SAAK,MAAM,SAAS,cAAc,WAAW,MAAM,OAAO,CAAC;AAAA,EAC7D;AAAA,EAEA,KAAK,UAAkB,MAAoB;AACzC,SAAK,MAAM,SAAS,WAAW,UAAU,IAAI,CAAC;AAAA,EAChD;AAAA,EAEA,OACE,WACA,MACA,UAA+B,CAAC,GAChC;AACA,SAAK,MAAM,SAAS,aAAa,WAAW,MAAM,OAAO,CAAC;AAAA,EAC5D;AAAA,EAEA,OAAO,YAAoB,gBAAwB;AACjD,UAAM,UAAU,KAAK,MAAM,UAAU;AACrC,UAAM,EAAE,UAAU,IAAI,KAAK,MAAM,SAAS;AAC1C,UAAM,cAAc,UAAU;AAE9B,QAAI,QAAQ,WAAW,uBAAuB;AAC5C,UACE,QAAQ,YAAY,aACpB,mBAAmB,eACnB,CAAC,eAAe,IAAI,QAAQ,SAAS,GACrC;AACA,aAAK,QAAQ,cAAc;AAAA,MAC7B;AAEA,UAAI,QAAQ,YAAY,WAAW;AACjC,aAAK,MAAM,SAAS,oBAAoB,UAAU,CAAC;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,eAAe,cAGzB;AAAA,EACD,OAAO;AAAA,EACP,eAAe;AACjB,CAAC;AA2DM,SAAS,gBAAgB,SAK9B;AACA,QAAM,EAAE,OAAAC,QAAO,cAAc,IAAI,WAAW,YAAY;AACxD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,EAAE,eAAe,IAAI,aAAa;AACxC,QAAM,kBAAkBC,QAA4B,IAAI;AAExD,YAAU,MAAM;AACd,QAAID,QAAO;AACT,YAAM,eAAeA,OAAM,cAAc,OAAO,SAAS;AAAA,QACvD,UAAU,CAAC,YAAY;AACrB,yBAAe,OAAO,SAAS,cAAc;AAAA,QAC/C;AAAA,QACA,WAAW,MAAM;AACf,uBAAa,IAAI;AAAA,QACnB;AAAA,QACA,cAAc,MAAM,aAAa,KAAK;AAAA,MACxC,CAAC;AAED,sBAAgB,UAAU;AAE1B,aAAO,MAAM,aAAa,YAAY;AAAA,IACxC,OAAO;AACL,sBAAgB,UAAU;AAC1B,mBAAa,KAAK;AAElB,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAAA,EACF,GAAG,CAACA,QAAO,KAAK,UAAU,OAAO,GAAG,cAAc,CAAC;AAEnD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,gBAAgB;AAAA,EAChC;AACF;;;AD1MA,SAAS,sBAAsB;AAE/B,SAAS,sBAAsB,2BAA2B;;;AKV1D,OAAO;AAAA,EACL,iBAAAE;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAaP,SAAS,eAAAC,cAAa,eAAAC,cAAa,YAAAC,iBAAgB;AAEnD,IAAM,oBAAoBC;AAAA,EACxB,CAAC;AACH;AAEA,IAAM,YAAY,OAAO,WAAW;AAEpC,IAAM,kBAAkB,CAAC,MAAc,SAAuB;AAC5D,eAAa,OAAO,SAAS,MAAM,IAAI;AACzC;AAEA,IAAM,WAAW,CAAC,eAA0C;AAC1D,MAAI,WAAW;AACf,MAAI,CAAC,YAAY;AACf,eACE;AAAA,EACJ;AAEA,QAAM,QAAQ,IAAI;AAAA,IAChB,2CAA2C,UAAU,2CAA2C,QAAQ;AAAA,EAC1G;AAEA,QAAM;AACR;AAEA,IAAM,qBAAqB,WAAW,SAASC,oBAC7C,EAAE,SAAS,OAAO,QAAQ,QAAQ,GAClC,KACA;AACA,QAAM,WAAWJ,aAAY;AAC7B,QAAM,QAAQC,aAAiC,CAAC,UAAU,MAAM,KAAK;AACrE,QAAM,YAAYA;AAAA,IAChB,CAAC,UAAU,MAAM;AAAA,EACnB;AACA,QAAM,iBAAiBA;AAAA,IACrB,CAAC,UAAU,MAAM,UAAU;AAAA,EAC7B;AACA,QAAM,QAAQC,UAAoB;AAElC,EAAAG,WAAU,MAAM;AACd,WAAO,QAAQ,OAAO,eAAe;AAAA,EACvC,GAAG,CAAC,CAAC;AAEL,kBAAgB,MAAM;AACpB,UAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAI,SAAS,eAAe,OAAO;AACjC,YAAM,EAAE,MAAM,KAAK,IAAI;AACvB,sBAAgB,MAAM,IAAI;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AAEnB;AAAA,IACE;AAAA,IACA,MAAM;AACJ,aAAO;AAAA,QACL;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,kBAAkB,CAAC,EAAE,UAAU,OAAO,MAAoB;AAC9D,UAAM,QAAQ,SAAS;AAEvB,QAAI,WAAW,OAAO;AACpB;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,SAAS,SAAS,IAAI;AAClC,YAAM,cAAc,aAAa,SAAS,WAAW,SAAS,MAAM;AACpE,YAAM,cAAc,CAAC,CAAC,MAAM,WAAW;AACvC,UAAI,aAAa;AACf,gBAAQ;AAAA,UACN;AAAA,YACE,UAAU,SAAS;AAAA,YACnB,QAAQ,SAAS;AAAA,YACjB,MAAM,SAAS;AAAA,UACjB;AAAA,UACA;AAAA,YACE,WAAW;AAAA,YACX,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,SAAS,eAAe,OAAO;AACjC,YAAM,UAAU,aAAa,SAAS,WAAW,SAAS,MAAM;AAChE,YAAM,cAAc,MAAM,SAAS,EAAE,UAAU;AAC/C,YAAM,cAAc,CAAC,CAAC,MAAM,OAAO;AAEnC,UAAI,aAAa;AACf,cAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO;AAEzC,gBAAQ,iBAAiB;AAAA,UACvB,KAAK;AACH,qBAAS,cAAc,EAAE,QAAQ,CAAC,CAAC;AACnC;AAAA,UACF,KAAK;AACH,qBAAS,cAAc,EAAE,QAAQ,CAAC,CAAC;AACnC,kBAAM,SAAS,EAAE,SAAS,KAAK,CAAC;AAChC;AAAA,UACF,KAAK;AAAA,UACL;AACE,kBAAM,SAAS,EAAE,SAAS,KAAK,CAAC,EAAE,KAAK,MAAM;AAC3C,oBAAM,QACJ,gBAAgB,MAAM,SAAS,EAAE,UAAU;AAC7C,kBAAI,OAAO;AAUT,yBAAS,cAAc,EAAE,QAAQ,CAAC,CAAC;AAAA,cACrC;AAAA,YACF,CAAC;AAAA,QACL;AAAA,MACF,OAAO;AACL,cAAM,SAAS,EAAE,SAAS,KAAK,CAAC,EAAE,KAAK,MAAM;AAC3C,gBAAM,QACJ,gBAAgB,MAAM,SAAS,EAAE,UAAU;AAC7C,cAAI,OAAO;AACT,qBAAS,cAAc,EAAE,QAAQ,CAAC,CAAC;AAAA,UACrC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAyB,CAC7B,MACA,EAAE,OAAO,IAAI;AAAA,IACX,QAAQ;AAAA,EACV,MACG;AACH,QAAI,WAAW,QAAQ;AACrB,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,aAAa,IAAI;AACrC,UAAM,UAAU,OAAO,UAAU,eAAe;AAAA,MAC9C,MAAM,SAAS,EAAE;AAAA,MACjB;AAAA,IACF;AAEA,QAAI,SAAS;AACX,YAAM,WAAW,QAAQ;AACzB,YAAM,QAAQ,SAAS;AACvB,YAAM,cAAc;AAAA,QAClB;AAAA,QACA;AAAA,UACE,WAAW;AAAA,UACX,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAEA,UAAI,WAAW,QAAQ;AACrB,YAAI,WAAW;AACb,kBAAQ;AAAA,YACN;AAAA,cACE,UAAU,SAAS;AAAA,cACnB,QAAQ,SAAS;AAAA,cACjB,MAAM,SAAS;AAAA,YACjB;AAAA,YACA;AAAA,cACE,GAAG;AAAA,cACH,MAAM,OAAO;AAAA,cACb,MAAM,OAAO;AAAA,YACf;AAAA,UACF;AAAA,QACF;AAEA,gBAAQ,KAAK,GAAG,WAAW;AAC3B,iBAAS,cAAc,EAAE,SAAS,YAAY,CAAC,CAAC;AAAA,MAClD;AAEA,UAAI,WAAW,WAAW;AACxB,gBAAQ,QAAQ,GAAG,WAAW;AAE9B,YAAI,mBAAmB,aAAa;AAClC,mBAAS,cAAc,EAAE,SAAS,YAAY,CAAC,CAAC;AAChD,mBAAS,WAAW,EAAE,SAAS,eAAe,CAAC,CAAC;AAAA,QAClD;AAAA,MACF;AACA,aAAO;AAAA,IACT,OAAO;AACL,cAAQ;AAAA,QACN;AAAA;AAAA;AAAA;AAAA,MAIF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,EAAE,oBAAoB,IAAI,MAAM,cAAc;AACpD,QAAM,YAAY,QAAQ,mBAAmB;AAE7C,MAAI,WAAW;AACb,WACE;AAAA,MAAC,kBAAkB;AAAA,MAAlB;AAAA,QACC,OAAO,EAAE,SAAS,gBAAgB,QAAQ,YAAY,OAAO,OAAO;AAAA;AAAA,MAEpE,oCAAC,eAAU;AAAA,IACb;AAAA,EAEJ,OAAO;AACL,aAAS,mBAAmB;AAAA,EAC9B;AACF,CAAC;;;ACnND,SAAS,mBAAmB,OAAiB;AAC3C,QAAM,EAAE,SAAS,IAAI;AACrB,QAAM,cAAc,OAAO,KAAK,KAAK;AACrC,QAAM,wBAAwB,YAC3B,IAAI,CAAC,QAAQ,MAAM,GAAG,EAAE,OAAO,EAC/B,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAEvB,aAAW,OAAO,MAAM,KAAK,WAAW,GAAG;AACzC,QAAI,MAAM,GAAG,EAAE,WAAW,sBAAsB,WAAW,CAAC,GAAG;AAC7D,aAAO,MAAM,GAAG;AAAA,IAClB;AAAA,EACF;AACF;AAEA,SAAS,mBACP,OACA,SACA,MACU;AACV,UAAQ,EAAE,GAAG,MAAM;AAEnB,QAAM,WAAiB;AAAA,IACrB,GAAG;AAAA,IACH,SAAS,KAAK,IAAI;AAAA,EACpB;AACA,qBAAmB,KAAK;AACxB,QAAM,OAAO,IAAI;AAEjB,SAAO;AACT;AAEO,SAAS,gCACd,OACA,SACA,mBACU;AACV,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,MAAI,kBAAkB,WAAW,GAAG;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,MAAM,OAAO;AACjC,QAAM,EAAE,WAAW,gBAAgB,CAAC,EAAE,IAAI;AAC1C,QAAM,gBAAgB,CAAC,GAAG,aAAa;AACvC,QAAM,eAAwC,CAAC;AAC/C,gBAAc,QAAQ,CAAC,SAAU,aAAa,KAAK,IAAI,IAAI,IAAK;AAEhE,oBAAkB,QAAQ,CAAC,SAAS;AAClC,QAAI,CAAC,aAAa,KAAK,IAAI,GAAG;AAC5B,oBAAc,KAAK,IAAI;AAAA,IACzB;AAAA,EACF,CAAC;AAED,QAAM,WAAW;AAAA,IACf,GAAG;AAAA,IACH,WAAW;AAAA,EACb;AAEA,QAAM,YAAY,EAAE,GAAG,MAAM;AAC7B,YAAU,OAAO,IAAI;AAErB,SAAO;AACT;AAEO,SAAS,oBACd,OACA,SACA,MACA,YACG;AACH,MAAI,CAAC,MAAM;AACT,YAAQ;AAAA,MACN;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,cAAc,CAAC,SAAS;AAC3B,WAAO;AAAA,EACT;AACA,QAAM,iBAAiB,CAAC,SAAS,UAAU,EAAE,KAAK,GAAG;AACrD,SAAO,MAAM,OAAO,gBAAgB,IAAI;AAC1C;AAEA,SAAS,4BACP,OACA,KACA,UACc;AACd,QAAM,SAAS,MAAM,GAAG;AAExB,MAAI,CAAC,QAAQ;AACX,UAAM,QAAQ,IAAI;AAAA,MAChB,6BAA6B,GAAG;AAAA,IAClC;AACA,UAAM;AAAA,EACR;AACA,QAAM,EAAE,MAAM,cAAc,MAAM,WAAW,IAAI;AAEjD,SAAO,oBAAoB,OAAO,KAAK,cAAc,UAAU;AACjE;AAEA,SAAS,oBACP,OACA,SACA,MACU;AACV,QAAM,cAAc,MAAM,OAAO;AACjC,MAAI,CAAC,aAAa;AAChB,UAAM,QAAQ,IAAI;AAAA,MAChB,6BAA6B,OAAO;AAAA,IACtC;AACA,UAAM;AAAA,EACR;AACA,QAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW,oBAAoB,CAAC;AAAA,EAClC,IAAI;AAEJ,SAAO;AAAA,IACL,CAAC,cACC,oBAAoB,WAAW,SAAS,cAAc,UAAU;AAAA,IAClE,CAAC,cACC,gCAAgC,WAAW,SAAS,iBAAiB;AAAA,EACzE,EAAE,OAAO,CAAC,MAAM,OAAO,GAAG,IAAI,GAAG,KAAK;AACxC;AAEO,SAAS,YAAY,QAAkB,CAAC,GAAG,QAA0B;AAC1E,MAAI,WAAW,MAAM,MAAM,GAAG;AAC5B,UAAM,EAAE,QAAQ,IAAI,OAAO;AAC3B,UAAM,YAAY,EAAE,GAAG,MAAM;AAC7B,WAAO,UAAU,OAAO;AAExB,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,MAAM,MAAM,GAAG;AAC1B,UAAM,YAAY,EAAE,GAAG,MAAM;AAC7B,UAAM,EAAE,MAAM,GAAG,IAAI,OAAO;AAE5B,cAAU,aAAa,EAAE,CAAC,IAAI,KAAK,MAAM,KAAK,UAAU,UAAU,IAAI,CAAC,CAAC;AAExE,WAAO;AAAA,EACT;AAEA,MAAI,YAAY,MAAM,MAAM,GAAG;AAC7B,UAAM,EAAE,SAAS,KAAK,IAAI,OAAO;AAEjC,WAAO,oBAAoB,OAAO,SAAS,IAAI;AAAA,EACjD;AAEA,MAAI,aAAa,MAAM,MAAM,GAAG;AAC9B,UAAM,EAAE,SAAS,KAAK,IAAI,OAAO;AACjC,UAAM,YAAY,mBAAmB,OAAO,SAAS,IAAI;AACzD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,iBACd,QAAwB;AAAA,EACtB,gBAAgB;AAAA,EAChB,QAAQ,CAAC;AAAA,EACT,QAAQ,CAAC;AACX,GACA,QACgB;AAChB,MAAI,aAAa,MAAM,MAAM,GAAG;AAC9B,UAAM,EAAE,UAAU,IAAI,OAAO;AAC7B,WAAO,EAAE,GAAG,OAAO,UAAqB;AAAA,EAC1C;AAEA,MAAI,cAAc,MAAM,MAAM,GAAG;AAC/B,UAAM,EAAE,QAAQ,IAAI,OAAO;AAC3B,UAAM,EAAE,OAAO,IAAI,aAAa,OAAO;AAEvC,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,gBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,cAAc,MAAM,MAAM,GAAG;AAC/B,UAAM,EAAE,QAAQ,IAAI,OAAO;AAC3B,UAAM,EAAE,OAAO,IAAI,aAAa,OAAO;AAEvC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,gBAAgB;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,aAAa,MAAM,MAAM,GAAG;AAC9B,UAAM;AAAA,MACJ,MAAM,EAAE,WAAW,OAAO;AAAA,IAC5B,IAAI,OAAO;AAEX,WAAO,EAAE,GAAG,OAAO,WAAW,OAAO;AAAA,EACvC;AAEA,SAAO;AACT;AAEO,SAAS,gBACd,QAAsB,CAAC,GACvB,QACc;AACd,MAAI,oBAAoB,MAAM,MAAM,GAAG;AACrC,UAAM,EAAE,YAAY,SAAS,IAAI,OAAO;AACxC,WAAO,4BAA4B,OAAO,YAAY,QAAQ;AAAA,EAChE;AAEA,MAAI,aAAa,MAAM,MAAM,GAAG;AAC9B,UAAM,EAAE,YAAY,KAAK,IAAI,OAAO;AAEpC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,CAAC,UAAU,GAAG;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,iBAAiB,MAAM,MAAM,GAAG;AAClC,UAAM,EAAE,MAAM,WAAW,IAAI,OAAO;AACpC,QAAI,iBAAiB,MAAM,UAAU;AAErC,QAAI,MAAM,QAAQ,cAAc,GAAG;AACjC,uBAAiB,CAAC,GAAG,gBAAgB,IAAI;AAEzC,aAAO;AAAA,QACL,GAAG;AAAA,QACH,CAAC,UAAU,GAAG;AAAA,MAChB;AAAA,IACF,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,kBAAkB,MAAM,MAAM,GAAG;AACnC,UAAM,EAAE,MAAM,WAAW,IAAI,OAAO;AACpC,QAAI,iBAAiB,MAAM,UAAU;AAErC,QAAI,MAAM,QAAQ,cAAc,GAAG;AACjC,uBAAiB,CAAC,MAAM,GAAG,cAAc;AACzC,aAAO;AAAA,QACL,GAAG;AAAA,QACH,CAAC,UAAU,GAAG;AAAA,MAChB;AAAA,IACF,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,cAAc;AAAA,EACzB,WAAW;AAAA,EACX,OAAO;AAAA,EACP,WAAW;AACb;;;AN5PA,SAAS,UAAU,MAAc;AAC/B,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,UAAU,SAAS,KAAK;AAAA,MAC5B,2BAA2B,IAAI;AAAA,IACjC;AACA,QAAI,SAAS;AACX,aAAO,QAAQ,aAAa,SAAS,KAAK;AAAA,IAC5C,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEA,IAAM,QAAQ,eAAe,UAAU,KAAK,CAAC;AAE7C,IAAMC,aAAY,OAAO,WAAW;AAEpC,IAAM,gBAAgB,MAAM;AAC1B,MAAIA,YAAW;AAEb,WAAO,qBAAqB,CAAC,CAAC;AAAA,EAChC,OAAO;AAEL,WAAO,oBAAoB,CAAC,CAAC;AAAA,EAC/B;AACF;AAEO,IAAM,eAAe,CAC1B,OACA,aACA,SACG;AACH,QAAM,iBAAiB,aAAa,IAAI;AACxC,QAAM,EAAE,UAAU,IAAI;AAEtB,QAAM;AAAA,IACJ,cAAc;AAAA,MACZ,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,QAAM;AAAA,IACJ,gBAAgB,EAAE,SAAS,gBAAgB,UAAU,YAAY,CAAC;AAAA,EACpE;AACA,QAAM,SAAS,mBAAmB,gBAAgB,WAAW,CAAC;AAC9D,QAAM,SAAS,aAAa,EAAE,UAAU,CAAC,CAAC;AAC5C;AAMO,IAAM,QAAQ,CAAC;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAkB;AAChB,SAAO,UAAU;AAEjB,QAAM,EAAE,OAAO,OAAO,IAAI,oBAAoB,cAAc,KAAK;AAEjE,QAAM,iBAAiB,aAAa,IAAI;AACxC,QAAM,cAAc,WAAW,cAAc;AAC7C,cAAY,QAAQ,GAAG,eAAe,IAAI,CAAC;AAC3C,eAAa,OAAO,aAAa,IAAI;AAErC,QAAM,WAAW,YAAY;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,IACpB;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,IAAI,cAAc,EAAE,QAAQ,MAAM,CAAC;AAEzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL;AAAA,EACF;AACF;AASA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqB;AACnB,QAAM,eAAeC,QAA0C,IAAI;AAEnE,QAAM,EAAE,OAAO,QAAQ,aAAa,gBAAgB,KAAK,cAAc,IACrEC,SAAQ,MAAM;AACZ,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAIP,SACE,gBAAAC,OAAA,cAAC,SAAI,SAAS,IAAI,SAAS,UAAU,IAAI,UAAW,GAAG,QACrD,gBAAAA,OAAA,cAAC,YAAS,SACR,gBAAAA,OAAA,cAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,eAAe,MAAM,KACnD,gBAAAA,OAAA;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA;AAAA,EACF,CACF,CACF,CACF;AAEJ;","names":["React","useRef","useMemo","useRef","useSelector","unproxy","useSelector","useSelector","useSelector","cable","useRef","createContext","useEffect","useDispatch","useSelector","useStore","createContext","NavigationProvider","useEffect","hasWindow","useRef","useMemo","React"]}
|
|
1
|
+
{"version":3,"sources":["../lib/index.tsx","../lib/hooks/useStreamSource.tsx","../lib/hooks/index.ts","../lib/hooks/useContent.tsx","../lib/hooks/useSetFragment.tsx","../lib/components/Navigation.tsx","../lib/reducers/index.ts"],"sourcesContent":["import React, { useRef, useMemo } from 'react'\nimport { config } from './config'\nimport { urlToPageKey, ujsHandlers, argsForHistory } from './utils'\nimport { saveAndProcessPage } from './action_creators'\nimport { historyChange, setCSRFToken, receiveResponse } from './actions'\nimport { Provider } from 'react-redux'\n\nimport { CableContext, StreamActions } from './hooks/useStreamSource'\nimport { createConsumer } from '@rails/actioncable'\n\nimport { createBrowserHistory, createMemoryHistory } from 'history'\n\nimport { NavigationProvider } from './components/Navigation'\nexport { NavigationProvider, NavigationContext } from './components/Navigation'\nexport { saveAndProcessPage } from './action_creators'\nexport {\n beforeFetch,\n beforeVisit,\n beforeRemote,\n copyPage,\n removePage,\n saveResponse,\n receiveResponse,\n GRAFTING_ERROR,\n GRAFTING_SUCCESS,\n} from './actions'\nexport * from './types'\n\nimport {\n SaveResponse,\n ApplicationProps,\n NavigateTo,\n SuperglueStore,\n SetupProps,\n} from './types'\nexport { superglueReducer, pageReducer, rootReducer } from './reducers'\nexport { getIn } from './utils/immutability'\nexport { urlToPageKey }\nexport * from './hooks'\nexport { unproxy } from './hooks/useContent'\n\nfunction getConfig(name: string) {\n if (typeof document !== 'undefined') {\n const element = document.head.querySelector(\n `meta[name='action-cable-${name}']`\n )\n if (element) {\n return element.getAttribute('content') || '/cable'\n } else {\n return '/cable'\n }\n } else {\n return '/cable'\n }\n}\n\nconst cable = createConsumer(getConfig('url'))\n\nconst hasWindow = typeof window !== 'undefined'\n\nconst createHistory = () => {\n if (hasWindow) {\n // This is used for client side rendering\n return createBrowserHistory({})\n } else {\n // This is used for server side rendering\n return createMemoryHistory({})\n }\n}\n\nexport const prepareStore = (\n store: SuperglueStore,\n initialPage: SaveResponse,\n path: string\n) => {\n const initialPageKey = urlToPageKey(path)\n const { csrfToken } = initialPage\n\n store.dispatch(\n historyChange({\n pageKey: initialPageKey,\n })\n )\n store.dispatch(\n receiveResponse({ pageKey: initialPageKey, response: initialPage })\n )\n store.dispatch(saveAndProcessPage(initialPageKey, initialPage))\n store.dispatch(setCSRFToken({ csrfToken }))\n}\n\n/**\n * This is the setup function that the Application calls. Use this function if\n * you like to build your own Application component.\n */\nexport const setup = ({\n initialPage,\n baseUrl,\n path,\n store,\n buildVisitAndRemote,\n history,\n navigatorRef,\n}: SetupProps) => {\n config.baseUrl = baseUrl\n\n const { visit, remote } = buildVisitAndRemote(navigatorRef, store)\n\n const initialPageKey = urlToPageKey(path)\n const nextHistory = history || createHistory()\n nextHistory.replace(...argsForHistory(path))\n prepareStore(store, initialPage, path)\n\n const handlers = ujsHandlers({\n visit,\n remote,\n ujsAttributePrefix: 'data-sg',\n store,\n })\n\n const streamActions = new StreamActions({ remote, store })\n\n return {\n visit,\n remote,\n nextHistory,\n initialPageKey,\n ujs: handlers,\n streamActions,\n }\n}\n\nif (process.env.NODE_ENV !== 'production') {\n console.info(\n '%cSuperglue Development Mode: ' +\n 'Remember to build for production before deploying.',\n 'font-weight:bold'\n )\n}\n\n/**\n * The entry point to your superglue application. It sets up the redux Provider,\n * redux state and the Navigation component.\n *\n * This is a simple component, you can override this by copying the source code and\n * use the exported methods used by this component (`start` and `ujsHandler`).\n */\nfunction Application({\n initialPage,\n baseUrl,\n path,\n store,\n buildVisitAndRemote,\n history,\n mapping,\n ...rest\n}: ApplicationProps) {\n const navigatorRef = useRef<{ navigateTo: NavigateTo } | null>(null)\n\n const { visit, remote, nextHistory, initialPageKey, ujs, streamActions } =\n useMemo(() => {\n return setup({\n initialPage,\n baseUrl,\n path,\n store,\n buildVisitAndRemote,\n history,\n navigatorRef,\n })\n }, [])\n\n // The Nav component is pretty bare and can be inherited from for custom\n // behavior or replaced with your own.\n return (\n <div onClick={ujs.onClick} onSubmit={ujs.onSubmit} {...rest}>\n <Provider store={store}>\n <CableContext.Provider value={{ streamActions, cable }}>\n <NavigationProvider\n ref={navigatorRef}\n visit={visit}\n remote={remote}\n mapping={mapping}\n history={nextHistory}\n initialPageKey={initialPageKey}\n />\n </CableContext.Provider>\n </Provider>\n </div>\n )\n}\n\nexport { Application }\n","import {\n ChannelNameWithParams,\n Consumer,\n Subscription,\n} from '@rails/actioncable'\nimport { useState, useEffect, useRef, createContext, useContext } from 'react'\nimport { ApplicationRemote, FragmentPath } from '../types'\nimport { useSuperglue } from '.'\nimport debounce from 'lodash.debounce'\nimport type { DebouncedFunc } from 'lodash'\nimport { lastRequestIds } from '../utils'\nimport {\n streamPrepend,\n streamAppend,\n streamSave,\n handleStreamMessage,\n} from '../action_creators/stream'\n\n/**\n * Channel configuration for stream sources\n * @public\n */\nexport type StreamSourceProps = string | ChannelNameWithParams\n\nexport type StreamMessage =\n | {\n action: 'handleStreamMessage'\n data: JSONMappable\n fragmentIds: string[]\n handler: 'append' | 'prepend' | 'save'\n options: Record<string, string>\n fragments: FragmentPath[]\n }\n | {\n action: 'handleStreamMessage'\n handler: 'refresh'\n requestId: string\n options: Record<string, string>\n }\n\nimport { SuperglueStore, JSONMappable } from '../types'\n\n/**\n * Actions for handling stream operations like append, prepend, save and refresh\n * @public\n */\nexport class StreamActions {\n public attributePrefix: string\n public remote: DebouncedFunc<ApplicationRemote>\n private store: SuperglueStore\n\n constructor({\n remote,\n store,\n }: {\n remote: ApplicationRemote\n store: SuperglueStore\n }) {\n this.store = store\n this.remote = debounce(remote, 300)\n }\n\n refresh(pageKey: string) {\n this.remote(pageKey)\n }\n\n prepend(\n fragments: string[],\n data: JSONMappable,\n options: { saveAs?: string } = {}\n ) {\n this.store.dispatch(streamPrepend(fragments, data, options))\n }\n\n save(fragment: string, data: JSONMappable) {\n this.store.dispatch(streamSave(fragment, data))\n }\n\n append(\n fragments: string[],\n data: JSONMappable,\n options: { saveAs?: string } = {}\n ) {\n this.store.dispatch(streamAppend(fragments, data, options))\n }\n\n handle(rawMessage: string, currentPageKey: string) {\n const message = JSON.parse(rawMessage) as StreamMessage\n const { superglue } = this.store.getState()\n const nextPageKey = superglue.currentPageKey\n\n if (message.action === 'handleStreamMessage') {\n if (\n message.handler === 'refresh' &&\n currentPageKey === nextPageKey &&\n !lastRequestIds.has(message.requestId)\n ) {\n this.refresh(currentPageKey)\n }\n\n if (message.handler !== 'refresh') {\n this.store.dispatch(handleStreamMessage(rawMessage))\n }\n }\n }\n}\n\nexport const CableContext = createContext<{\n cable: Consumer | null\n streamActions: StreamActions | null\n}>({\n cable: null,\n streamActions: null,\n})\n\n/**\n * Creates a subscription to an ActionCable channel for real-time streaming\n * updates.\n *\n * This hook manages the lifecycle of an ActionCable subscription, automatically\n * connecting when the cable is available and cleaning up on unmount. Stream\n * messages are processed through StreamActions to update the Redux store.\n *\n * Typically used with channel configuration generated by the Rails helper\n * `stream_from_props` helper in your `props` templates.\n *\n * * @example\n * Using the helper:\n *\n * ```ruby\n * # app/views/chat_rooms/show.json.props\n * json.chatChannel stream_from_props(\"messages\")\n * ```\n * ```tsx\n * const content = useContent()\n * const { connected } = useStreamSource(content.chatChannel)\n * ```\n *\n * @example\n * Basic channel subscription:\n * ```tsx\n * const { connected } = useStreamSource('ChatChannel')\n * ```\n *\n * @example\n * Channel with parameters:\n * ```tsx\n * const { connected } = useStreamSource({\n * channel: 'ChatChannel',\n * room_id: roomId\n * })\n * ```\n *\n * @example\n * Using connection status:\n * ```tsx\n * const { connected, subscription } = useStreamSource('NotificationsChannel')\n *\n * return (\n * <div>\n * {connected ? 'Connected' : 'Connecting...'}\n * {subscription && <span>Subscription active</span>}\n * </div>\n * )\n * ```\n *\n * @param channel - Channel configuration as string or ChannelNameWithParams object,\n * typically generated by Rails `stream_from_props` helper\n * @returns Object containing connection status and subscription instance\n *\n * @public\n */\nexport function useStreamSource(channel: StreamSourceProps): {\n /** Whether the ActionCable subscription is currently connected */\n connected: boolean\n /** The active ActionCable subscription instance, null if not connected */\n subscription: Subscription | null\n} {\n const { cable, streamActions } = useContext(CableContext)\n const [connected, setConnected] = useState(false)\n const { currentPageKey } = useSuperglue()\n const subscriptionRef = useRef<Subscription | null>(null)\n\n useEffect(() => {\n if (cable) {\n const subscription = cable.subscriptions.create(channel, {\n received: (message) => {\n streamActions?.handle(message, currentPageKey)\n },\n connected: () => {\n setConnected(true)\n },\n disconnected: () => setConnected(false),\n })\n\n subscriptionRef.current = subscription\n\n return () => subscription.unsubscribe()\n } else {\n subscriptionRef.current = null\n setConnected(false)\n\n return () => {}\n }\n }, [cable, JSON.stringify(channel), currentPageKey])\n\n return {\n connected,\n subscription: subscriptionRef.current,\n }\n}\n","import { useSelector } from 'react-redux'\nimport { RootState, SuperglueState } from '../types'\nexport { useContent, unproxy } from './useContent'\nexport { useSetFragment } from './useSetFragment'\nexport { useStreamSource } from './useStreamSource'\n\n/**\n * A lightweight hook that grabs the superglue state from the store.\n */\nexport function useSuperglue() {\n return useSelector<RootState, SuperglueState>((state) => state.superglue)\n}\n","import { useSelector, useStore } from 'react-redux'\nimport { useMemo, useRef } from 'react'\nimport {\n JSONMappable,\n RootState,\n Unproxy,\n FragmentRef,\n ReceiveType,\n} from '../types'\nimport { useSuperglue } from './index'\nimport { createProxy, unproxy as unproxyUtil } from '../utils/proxy'\n\nexport type FragmentProxy = { __fragment: true }\n\n/**\n * Union type for fragment references, accepting either FragmentRef objects or string IDs\n * @public\n */\nexport type FragmentRefOrId = FragmentRef | string\n\n/**\n * Returns a proxy for accessing your page's content e.g, `index.json.props`,\n * `show.json.props`, etc.\n *\n * For advanced scenarios where you are using Fragments.\n *\n * ```js\n * {\n * data: {\n * body: {\n * cart: {__id: 'user_cart'}\n * },\n * footer: {title: \"welcome\"}},\n * },\n * fragments: {user_cart: {total: 100}}\n * }\n * ```\n *\n * The proxy will lazily and automatically resolve any {@link FragmentRef}s making it\n * as easy as\n *\n * ```\n * const data = useContent()\n * const total = data.body.cart.total\n * ```\n *\n * The hook will also automatically tracks fragment dependencies and triggers\n * re-renders only when accessed fragments change.\n *\n * @template T - The data type being accessed (defaults to JSONMappable)\n * @returns Reactive proxy to page data or fragment data, undefined if fragment not found\n *\n * @example\n * ```tsx\n * // Access current page data\n * const page = useContent()\n *\n * // Access specific fragment by reference\n * const user = useContent({__id: 'user_123'})\n *\n * // Access specific fragment by ID string\n * const cart = useContent('userCart')\n * ```\n */\nexport function useContent<T = JSONMappable>(): T\n\n/**\n * Passing in a fragment to useContent allows us to scope the tracking of\n * fragments to that hook usage. Its useful in performance scenarios where you\n * want a child component to update, but not the parent.\n *\n *\n * ```js\n * import {unproxy} from '@thoughtbot/superglue'\n *\n * const content = useContent()\n * const rawContent = unproxy(content)\n *\n * <h1>{content.title}</h1>\n * <SlidingCart cartRef={rawContent.cart} />\n * ```\n *\n * then in SlidingCart\n *\n * ```js\n * const SlidingCart = (cartRef) => {\n * const cart = useContent(cartRef)\n * }\n * ```\n *\n * SlidingCart will update only if the fragment referenced by `cartRef` updates.\n *\n * @param fragmentRef Optional fragment reference for scoped access\n */\nexport function useContent<T = JSONMappable>(fragmentRef: FragmentRefOrId): T\nexport function useContent<T = JSONMappable>(\n fragmentRef?: FragmentRefOrId,\n __type?: ReceiveType<T>\n): T | undefined {\n const superglueState = useSuperglue()\n const currentPageKey = superglueState.currentPageKey\n\n const dependencies = useRef<Set<string>>(new Set())\n // const fragmentsHookRef = useRef<RootState['fragments']>({})\n\n const fragmentId =\n typeof fragmentRef === 'string' ? fragmentRef : fragmentRef?.__id\n const sourceData = useSelector((state: RootState) => {\n if (fragmentId) {\n return state.fragments[fragmentId]\n } else {\n return state.pages[currentPageKey].data\n }\n })\n\n const trackedFragments = useSelector(\n (state: RootState) => state.fragments,\n (oldFragments, newFragments) => {\n if (oldFragments === newFragments) {\n return true\n }\n\n return Array.from(dependencies.current).every((id: string) => {\n const prevVal = oldFragments[id]\n const nextVal = newFragments[id]\n return prevVal === nextVal\n })\n }\n )\n\n // Update the ref BEFORE the useMemo so proxy creation sees current fragments\n // fragmentsHookRef.current = fragments\n\n const store = useStore<RootState>()\n\n const proxy = useMemo(() => {\n const proxyCache = new WeakMap()\n\n if (fragmentId && !sourceData) {\n return undefined\n }\n\n const proxy = createProxy(\n sourceData,\n { current: store.getState().fragments },\n dependencies.current,\n proxyCache\n ) as T\n\n if (process.env.NODE_ENV !== 'production' && __type) {\n const proxyForValidation = createProxy(\n sourceData,\n { current: store.getState().fragments },\n new Set(),\n new WeakMap()\n ) as T\n\n import('@deepkit/type')\n .then(({ resolveReceiveType, validate }) => {\n // @ts-expect-error - ReceiveType<T> is transformed by Deepkit compiler\n const resolvedType = resolveReceiveType(__type)\n const errors = validate(proxyForValidation, resolvedType)\n\n if (errors.length > 0) {\n const formattedErrors = errors.map((e) => ({\n path: e.path,\n message: e.message,\n code: String(e.code),\n }))\n\n console.error(\n `[Superglue] Content validation failed for ${\n fragmentId || 'page'\n }:`,\n formattedErrors\n )\n }\n })\n .catch(() => {\n // Deepkit not installed - silently skip validation\n })\n }\n\n return proxy\n }, [sourceData, trackedFragments])\n\n return proxy\n}\n\n/**\n * Extracts the underlying state from an {@link useContent} proxy\n *\n */\nexport function unproxy<T>(proxy: T): Unproxy<T> {\n return unproxyUtil(proxy)\n}\n","import { useDispatch, useSelector } from 'react-redux'\nimport { Immer } from 'immer'\nimport { saveFragment } from '../actions'\nimport { RootState, Fragment } from '../types'\nimport { Unproxy } from '../types'\nimport { FragmentProxy } from './useContent'\n\nconst immer = new Immer()\nimmer.setAutoFreeze(false)\n\n/**\n * Utility type to extract the data type from a Fragment wrapper\n * @public\n */\nexport type Unpack<T> = T extends Fragment<infer U, unknown>\n ? U\n : T extends FragmentProxy\n ? T\n : never\n/**\n * Hook for mutating fragments using Immer drafts.\n *\n * @example\n * ```tsx\n * const set = useSetFragment()\n *\n * // Update via fragment reference\n * set(userRef, draft => {\n * draft.name = \"Updated Name\"\n * draft.email = \"new@email.com\"\n * })\n *\n * // Update via fragment ID directly\n * set('user_123', draft => {\n * draft.profile.bio = \"Updated bio\"\n * })\n * ```\n *\n */\nexport function useSetFragment() {\n const dispatch = useDispatch()\n const fragments = useSelector((state: RootState) => state.fragments)\n\n /**\n * Updates a fragment using a {@link FragmentRef} object.\n *\n * @param fragmentRef - Fragment reference object containing __id\n * @param updater - Immer draft function for mutating fragment data\n */\n function setter<T extends Fragment<unknown, unknown>>(\n fragmentRef: T,\n updater: (draft: Unproxy<Unpack<T>>) => void\n ): void\n\n /**\n * Updates a fragment using a fragment ID string.\n *\n * @param fragmentId - The fragment ID string\n * @param updater - Immer draft function for mutating fragment data\n */\n function setter<T = unknown>(\n fragmentId: string,\n updater: (draft: T) => void\n ): void\n\n function setter(\n fragmentRefOrId: Fragment<unknown, true> | string,\n updater: (draft: unknown) => void\n ): void {\n const fragmentId =\n typeof fragmentRefOrId === 'string'\n ? fragmentRefOrId\n : fragmentRefOrId.__id\n\n const currentFragment = fragments[fragmentId]\n\n if (currentFragment === undefined) {\n throw new Error(`Fragment with id \"${fragmentId}\" not found`)\n }\n\n const updatedFragment = immer.produce(currentFragment, updater)\n\n dispatch(\n saveFragment({\n fragmentId: fragmentId,\n data: updatedFragment,\n })\n )\n }\n\n return setter\n}\n","import React, {\n createContext,\n useEffect,\n useLayoutEffect,\n forwardRef,\n useImperativeHandle,\n ForwardedRef,\n} from 'react'\nimport { urlToPageKey } from '../utils'\nimport { removePage, setActivePage } from '../actions'\nimport {\n HistoryState,\n RootState,\n NavigateTo,\n NavigationContextProps,\n NavigationProviderProps,\n AllPages,\n SuperglueState,\n} from '../types'\nimport { Update } from 'history'\nimport { useDispatch, useSelector, useStore } from 'react-redux'\n\nconst NavigationContext = createContext<NavigationContextProps>(\n {} as NavigationContextProps\n)\n\nconst hasWindow = typeof window !== 'undefined'\n\nconst setWindowScroll = (posX: number, posY: number): void => {\n hasWindow && window.scrollTo(posX, posY)\n}\n\nconst notFound = (identifier: string | undefined): never => {\n let reminder = ''\n if (!identifier) {\n reminder =\n 'Did you forget to add `json.componentIdentifier` in your application.json.props layout?'\n }\n\n const error = new Error(\n `Superglue Nav component was looking for ${identifier} but could not find it in your mapping. ${reminder}`\n )\n\n throw error\n}\n\nconst NavigationProvider = forwardRef(function NavigationProvider(\n { history, visit, remote, mapping }: NavigationProviderProps,\n ref: ForwardedRef<{ navigateTo: NavigateTo | null }>\n) {\n const dispatch = useDispatch()\n const pages = useSelector<RootState, AllPages>((state) => state.pages)\n const superglue = useSelector<RootState, SuperglueState>(\n (state) => state.superglue\n )\n const currentPageKey = useSelector<RootState, string>(\n (state) => state.superglue.currentPageKey\n )\n const store = useStore<RootState>()\n\n useEffect(() => {\n return history.listen(onHistoryChange)\n }, [])\n\n useLayoutEffect(() => {\n const state = history.location.state as HistoryState\n if (state && 'superglue' in state) {\n const { posX, posY } = state\n setWindowScroll(posX, posY)\n }\n }, [currentPageKey])\n\n useImperativeHandle(\n ref,\n () => {\n return {\n navigateTo,\n }\n },\n []\n )\n\n const onHistoryChange = ({ location, action }: Update): void => {\n const state = location.state as HistoryState\n\n if (action !== 'POP') {\n return\n }\n\n if (!state && location.hash !== '') {\n const nextPageKey = urlToPageKey(location.pathname + location.search)\n const containsKey = !!pages[nextPageKey]\n if (containsKey) {\n history.replace(\n {\n pathname: location.pathname,\n search: location.search,\n hash: location.hash,\n },\n {\n superglue: true,\n posY: window.pageYOffset,\n posX: window.pageXOffset,\n }\n )\n }\n }\n\n if (state && 'superglue' in state) {\n const pageKey = urlToPageKey(location.pathname + location.search)\n const prevPageKey = store.getState().superglue.currentPageKey\n const containsKey = !!pages[pageKey]\n\n if (containsKey) {\n const { restoreStrategy } = pages[pageKey]\n\n switch (restoreStrategy) {\n case 'fromCacheOnly':\n dispatch(setActivePage({ pageKey }))\n break\n case 'fromCacheAndRevisitInBackground':\n dispatch(setActivePage({ pageKey }))\n visit(pageKey, { revisit: true })\n break\n case 'revisitOnly':\n default:\n visit(pageKey, { revisit: true }).then(() => {\n const noNav =\n prevPageKey === store.getState().superglue.currentPageKey\n if (noNav) {\n // When \"POP'ed\", revisiting (using revisit: true) a page can result in\n // a redirect, or a render of the same page.\n //\n // When its a redirect, calculateNavAction will correctly set the\n // navigationAction to `replace` this is the noop scenario.\n //\n // When its the same page, navigationAction is set to `none` and\n // no navigation took place. In that case, we have to set the\n // activePage otherwise the user is stuck on the original page.\n dispatch(setActivePage({ pageKey }))\n }\n })\n }\n } else {\n visit(pageKey, { revisit: true }).then(() => {\n const noNav =\n prevPageKey === store.getState().superglue.currentPageKey\n if (noNav) {\n dispatch(setActivePage({ pageKey }))\n }\n })\n }\n }\n }\n\n const navigateTo: NavigateTo = (\n path,\n { action } = {\n action: 'push',\n }\n ) => {\n if (action === 'none') {\n return false\n }\n\n const nextPageKey = urlToPageKey(path)\n const hasPage = Object.prototype.hasOwnProperty.call(\n store.getState().pages,\n nextPageKey\n )\n\n if (hasPage) {\n const location = history.location\n const state = location.state as HistoryState\n const historyArgs = [\n path,\n {\n superglue: true,\n posY: 0,\n posX: 0,\n },\n ] as const\n\n if (action === 'push') {\n if (hasWindow) {\n history.replace(\n {\n pathname: location.pathname,\n search: location.search,\n hash: location.hash,\n },\n {\n ...state,\n posY: window.scrollY,\n posX: window.scrollX,\n }\n )\n }\n\n history.push(...historyArgs)\n dispatch(setActivePage({ pageKey: nextPageKey }))\n }\n\n if (action === 'replace') {\n history.replace(...historyArgs)\n\n if (currentPageKey !== nextPageKey) {\n dispatch(setActivePage({ pageKey: nextPageKey }))\n dispatch(removePage({ pageKey: currentPageKey }))\n }\n }\n return true\n } else {\n console.warn(\n `\\`navigateTo\\` was called , but could not find\n the pageKey in the store. This may happen when the wrong\n content_location was set in your non-get controller action.\n No navigation will take place`\n )\n return false\n }\n }\n\n const { search } = superglue\n const { componentIdentifier } = pages[currentPageKey]\n const Component = mapping[componentIdentifier]\n\n if (Component) {\n return (\n <NavigationContext.Provider\n value={{ pageKey: currentPageKey, search, navigateTo, visit, remote }}\n >\n <Component />\n </NavigationContext.Provider>\n )\n } else {\n notFound(componentIdentifier)\n }\n})\n\nexport { NavigationContext, NavigationProvider }\n","import { setIn, urlToPageKey, parsePageKey } from '../utils'\nimport type { Action } from '@reduxjs/toolkit'\nimport {\n saveResponse,\n handleGraft,\n historyChange,\n copyPage,\n setCSRFToken,\n setActivePage,\n removePage,\n handleFragmentGraft,\n saveFragment,\n appendToFragment,\n prependToFragment,\n} from '../actions'\nimport { config } from '../config'\nimport {\n AllPages,\n Page,\n SaveResponse,\n FragmentPath,\n GraftResponse,\n SuperglueState,\n JSONMappable,\n AllFragments,\n} from '../types'\n\nfunction constrainPagesSize(state: AllPages) {\n const { maxPages } = config\n const allPageKeys = Object.keys(state)\n const cacheTimesRecentFirst = allPageKeys\n .map((key) => state[key].savedAt)\n .sort((a, b) => b - a)\n\n for (const key of Array.from(allPageKeys)) {\n if (state[key].savedAt <= cacheTimesRecentFirst[maxPages - 1]) {\n delete state[key]\n }\n }\n}\n\nfunction handleSaveResponse(\n state: AllPages,\n pageKey: string,\n page: SaveResponse\n): AllPages {\n state = { ...state }\n\n const nextPage: Page = {\n ...page,\n savedAt: Date.now(),\n }\n constrainPagesSize(state)\n state[pageKey] = nextPage\n\n return state\n}\n\nexport function appendReceivedFragmentsOntoPage(\n state: AllPages,\n pageKey: string,\n receivedFragments: FragmentPath[]\n): AllPages {\n if (!pageKey) {\n return state\n }\n\n if (receivedFragments.length === 0) {\n return state\n }\n\n const currentPage = state[pageKey]\n const { fragments: prevFragments = [] } = currentPage\n const nextFragments = [...prevFragments]\n const existingKeys: Record<string, boolean> = {}\n prevFragments.forEach((frag) => (existingKeys[frag.path] = true))\n\n receivedFragments.forEach((frag) => {\n if (!existingKeys[frag.path]) {\n nextFragments.push(frag)\n }\n })\n\n const nextPage = {\n ...currentPage,\n fragments: nextFragments,\n }\n\n const nextState = { ...state }\n nextState[pageKey] = nextPage\n\n return nextState\n}\n\nexport function graftNodeOntoTarget<T extends JSONMappable>(\n state: T,\n pageKey: string,\n node: JSONMappable,\n pathToNode: string\n): T {\n if (!node) {\n console.warn(\n 'There was no node returned in the response. Do you have the correct key path in your props_at?'\n )\n return state\n }\n\n if (!pathToNode || !pageKey) {\n return state\n }\n const fullPathToNode = [pageKey, pathToNode].join('.')\n return setIn(state, fullPathToNode, node)\n}\n\nfunction handleFragmentGraftResponse(\n state: AllFragments,\n key: string,\n response: GraftResponse\n): AllFragments {\n const target = state[key]\n\n if (!target) {\n const error = new Error(\n `Superglue was looking for ${key} in your fragments, but could not find it.`\n )\n throw error\n }\n const { data: receivedNode, path: pathToNode } = response\n\n return graftNodeOntoTarget(state, key, receivedNode, pathToNode)\n}\n\nfunction handleGraftResponse(\n state: AllPages,\n pageKey: string,\n page: GraftResponse\n): AllPages {\n const currentPage = state[pageKey]\n if (!currentPage) {\n const error = new Error(\n `Superglue was looking for ${pageKey} in your state, but could not find it in your mapping. Did you forget to pass in a valid pageKey to this.props.remote or this.props.visit?`\n )\n throw error\n }\n const {\n data: receivedNode,\n path: pathToNode,\n fragments: receivedFragments = [],\n } = page\n\n return [\n (nextState: AllPages) =>\n graftNodeOntoTarget(nextState, pageKey, receivedNode, pathToNode),\n (nextState: AllPages) =>\n appendReceivedFragmentsOntoPage(nextState, pageKey, receivedFragments),\n ].reduce((memo, fn) => fn(memo), state)\n}\n\nexport function pageReducer(state: AllPages = {}, action: Action): AllPages {\n if (removePage.match(action)) {\n const { pageKey } = action.payload\n const nextState = { ...state }\n delete nextState[pageKey]\n\n return nextState\n }\n\n if (copyPage.match(action)) {\n const nextState = { ...state }\n const { from, to } = action.payload\n\n nextState[urlToPageKey(to)] = JSON.parse(JSON.stringify(nextState[from]))\n\n return nextState\n }\n\n if (handleGraft.match(action)) {\n const { pageKey, page } = action.payload\n\n return handleGraftResponse(state, pageKey, page)\n }\n\n if (saveResponse.match(action)) {\n const { pageKey, page } = action.payload\n const nextState = handleSaveResponse(state, pageKey, page)\n return nextState\n }\n\n return state\n}\n\nexport function superglueReducer(\n state: SuperglueState = {\n currentPageKey: '',\n search: {},\n assets: [],\n },\n action: Action\n): SuperglueState {\n if (setCSRFToken.match(action)) {\n const { csrfToken } = action.payload\n return { ...state, csrfToken: csrfToken }\n }\n\n if (setActivePage.match(action)) {\n const { pageKey } = action.payload\n const { search } = parsePageKey(pageKey)\n\n return {\n ...state,\n search,\n currentPageKey: pageKey,\n }\n }\n\n if (historyChange.match(action)) {\n const { pageKey } = action.payload\n const { search } = parsePageKey(pageKey)\n\n return {\n ...state,\n currentPageKey: pageKey,\n search,\n }\n }\n\n if (saveResponse.match(action)) {\n const {\n page: { csrfToken, assets },\n } = action.payload\n\n return { ...state, csrfToken, assets }\n }\n\n return state\n}\n\nexport function fragmentReducer(\n state: AllFragments = {},\n action: Action\n): AllFragments {\n if (handleFragmentGraft.match(action)) {\n const { fragmentId, response } = action.payload\n return handleFragmentGraftResponse(state, fragmentId, response)\n }\n\n if (saveFragment.match(action)) {\n const { fragmentId, data } = action.payload\n\n return {\n ...state,\n [fragmentId]: data,\n }\n }\n\n if (appendToFragment.match(action)) {\n const { data, fragmentId } = action.payload\n let targetFragment = state[fragmentId]\n\n if (Array.isArray(targetFragment)) {\n targetFragment = [...targetFragment, data]\n\n return {\n ...state,\n [fragmentId]: targetFragment,\n }\n } else {\n return state\n }\n }\n\n if (prependToFragment.match(action)) {\n const { data, fragmentId } = action.payload\n let targetFragment = state[fragmentId]\n\n if (Array.isArray(targetFragment)) {\n targetFragment = [data, ...targetFragment]\n return {\n ...state,\n [fragmentId]: targetFragment,\n }\n } else {\n return state\n }\n }\n\n return state\n}\n\nexport const rootReducer = {\n superglue: superglueReducer,\n pages: pageReducer,\n fragments: fragmentReducer,\n}\n"],"mappings":"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","names":["React","useRef","useMemo","useRef","useSelector","proxy","unproxy","useSelector","useSelector","useSelector","cable","useRef","createContext","useEffect","useDispatch","useSelector","useStore","createContext","NavigationProvider","useEffect","hasWindow","useRef","useMemo","React"]}
|
package/npm/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thoughtbot/superglue",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.11",
|
|
4
4
|
"description": "Use a vanilla Rails with React and Redux",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "tsup",
|
|
6
|
+
"build": "tsup && node scripts/copy-wrappers.js",
|
|
7
7
|
"dev": "tsup --watch",
|
|
8
8
|
"clean": "rm -rf dist",
|
|
9
9
|
"lint": "run-p lint:eslint lint:types lint:prettier",
|
|
@@ -23,20 +23,27 @@
|
|
|
23
23
|
"url": "git+https://github.com/thoughtbot/superglue.git"
|
|
24
24
|
},
|
|
25
25
|
"author": "Johny Ho",
|
|
26
|
-
"main": "dist/
|
|
27
|
-
"module": "dist/superglue.mjs",
|
|
26
|
+
"main": "dist/index.js",
|
|
28
27
|
"types": "dist/superglue.d.mts",
|
|
29
28
|
"exports": {
|
|
30
29
|
"./package.json": "./package.json",
|
|
31
30
|
".": {
|
|
32
31
|
"types": "./dist/superglue.d.mts",
|
|
33
|
-
"
|
|
34
|
-
|
|
32
|
+
"production": {
|
|
33
|
+
"import": "./dist/superglue.mjs",
|
|
34
|
+
"require": "./dist/cjs/superglue.cjs"
|
|
35
|
+
},
|
|
36
|
+
"import": "./dist/superglue.development.mjs",
|
|
37
|
+
"require": "./dist/index.js"
|
|
35
38
|
},
|
|
36
39
|
"./action_creators": {
|
|
37
40
|
"types": "./dist/action_creators.d.mts",
|
|
38
|
-
"
|
|
39
|
-
|
|
41
|
+
"production": {
|
|
42
|
+
"import": "./dist/action_creators.mjs",
|
|
43
|
+
"require": "./dist/cjs/action_creators.cjs"
|
|
44
|
+
},
|
|
45
|
+
"import": "./dist/action_creators.development.mjs",
|
|
46
|
+
"require": "./dist/action_creators.js"
|
|
40
47
|
}
|
|
41
48
|
},
|
|
42
49
|
"license": "MIT",
|
|
@@ -45,6 +52,9 @@
|
|
|
45
52
|
},
|
|
46
53
|
"homepage": "https://github.com/thoughtbot/superglue#readme",
|
|
47
54
|
"devDependencies": {
|
|
55
|
+
"@deepkit/core": "^1.0.19",
|
|
56
|
+
"@deepkit/type": "^1.0.19",
|
|
57
|
+
"@deepkit/type-compiler": "^1.0.19",
|
|
48
58
|
"@testing-library/dom": "^10.4.0",
|
|
49
59
|
"@testing-library/jest-dom": "^6.5.0",
|
|
50
60
|
"@testing-library/react": "^16.0.1",
|
|
@@ -61,6 +71,7 @@
|
|
|
61
71
|
"fetch-headers": "^2.0.0",
|
|
62
72
|
"fetch-mock": "^9.11.0",
|
|
63
73
|
"jsdom": "^24.1.0",
|
|
74
|
+
"mock-socket": "^2.0.0",
|
|
64
75
|
"node-fetch": "^2.6.1",
|
|
65
76
|
"npm-run-all": "^4.1.5",
|
|
66
77
|
"prettier": "^2.3.1",
|
|
@@ -70,19 +81,33 @@
|
|
|
70
81
|
"react-redux": "^9.1.2",
|
|
71
82
|
"redux-mock-store": "^1.5.4",
|
|
72
83
|
"redux-thunk": "^3.1.0",
|
|
84
|
+
"rollup": "4.52.5",
|
|
73
85
|
"tsup": "^8.1.0",
|
|
74
86
|
"typedoc": "^0.28.10",
|
|
75
87
|
"typedoc-plugin-markdown": "^4.8.1",
|
|
76
88
|
"typedoc-plugin-missing-exports": "~4.1.0",
|
|
77
89
|
"typescript": "^5.5.3",
|
|
78
|
-
"vitest": "^2.0.2"
|
|
79
|
-
"rollup": "4.52.5"
|
|
90
|
+
"vitest": "^2.0.2"
|
|
80
91
|
},
|
|
81
92
|
"peerDependencies": {
|
|
93
|
+
"@deepkit/core": "^1.0.19",
|
|
94
|
+
"@deepkit/type": "^1.0.19",
|
|
95
|
+
"@deepkit/type-compiler": "^1.0.19",
|
|
82
96
|
"@reduxjs/toolkit": "^2.2.8",
|
|
83
97
|
"react": "^18 || ^19",
|
|
84
98
|
"react-redux": "^9 || ^8"
|
|
85
99
|
},
|
|
100
|
+
"peerDependenciesMeta": {
|
|
101
|
+
"@deepkit/core": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@deepkit/type": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@deepkit/type-compiler": {
|
|
108
|
+
"optional": true
|
|
109
|
+
}
|
|
110
|
+
},
|
|
86
111
|
"dependencies": {
|
|
87
112
|
"@rails/actioncable": "^8.0.200",
|
|
88
113
|
"@types/lodash.debounce": "^4.0.9",
|
|
@@ -90,7 +115,6 @@
|
|
|
90
115
|
"history": "^5.3.0",
|
|
91
116
|
"immer": "^10.0.3",
|
|
92
117
|
"lodash.debounce": "^4.0.8",
|
|
93
|
-
"mock-socket": "^2.0.0",
|
|
94
118
|
"uuid": "^11.1.0"
|
|
95
119
|
}
|
|
96
120
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Copies wrapper files from npm/ to dist/
|
|
9
|
+
* Similar to React's prepareNpmPackage process
|
|
10
|
+
*/
|
|
11
|
+
function copyWrappers() {
|
|
12
|
+
const npmDir = path.join(__dirname, '..', 'npm')
|
|
13
|
+
const distDir = path.join(__dirname, '..', 'dist')
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(distDir)) {
|
|
16
|
+
console.error('Error: dist/ folder does not exist. Run build first.')
|
|
17
|
+
process.exit(1)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Read all files from npm/ directory
|
|
21
|
+
const files = fs.readdirSync(npmDir)
|
|
22
|
+
|
|
23
|
+
files.forEach((file) => {
|
|
24
|
+
const srcPath = path.join(npmDir, file)
|
|
25
|
+
const destPath = path.join(distDir, file)
|
|
26
|
+
|
|
27
|
+
// Only copy files (not directories)
|
|
28
|
+
if (fs.statSync(srcPath).isFile()) {
|
|
29
|
+
fs.copyFileSync(srcPath, destPath)
|
|
30
|
+
console.log(`Copied: npm/${file} → dist/${file}`)
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
console.log('✓ Wrapper files copied successfully')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
copyWrappers()
|
|
Binary file
|
package/tsconfig.json
CHANGED
package/tsup.config.ts
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import type { Options } from 'tsup'
|
|
2
2
|
import { defineConfig } from 'tsup'
|
|
3
|
+
import { DeepkitLoader } from '@deepkit/type-compiler'
|
|
4
|
+
import { readFileSync } from 'fs'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import type { Plugin, Loader } from 'esbuild'
|
|
7
|
+
|
|
8
|
+
// Deepkit transformation plugin for tsup/esbuild
|
|
9
|
+
const deepkitLoader = new DeepkitLoader()
|
|
10
|
+
|
|
11
|
+
const deepkitPlugin: Plugin = {
|
|
12
|
+
name: 'deepkit',
|
|
13
|
+
setup(build) {
|
|
14
|
+
const loaderMap: Record<string, Loader> = {
|
|
15
|
+
'.ts': 'ts',
|
|
16
|
+
'.tsx': 'tsx',
|
|
17
|
+
'.js': 'js',
|
|
18
|
+
'.jsx': 'jsx',
|
|
19
|
+
}
|
|
20
|
+
build.onLoad({ filter: /\.(tsx?|jsx?)$/ }, async (args) => {
|
|
21
|
+
if (args.path.includes('node_modules')) {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const source = readFileSync(args.path, 'utf8')
|
|
26
|
+
|
|
27
|
+
const deepkitTransformed = deepkitLoader.transform(source, args.path)
|
|
28
|
+
|
|
29
|
+
const ext = path.extname(args.path)
|
|
30
|
+
const loader = loaderMap[ext] || 'js'
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
contents: deepkitTransformed,
|
|
34
|
+
loader,
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
},
|
|
38
|
+
}
|
|
3
39
|
|
|
4
40
|
export default defineConfig((options) => {
|
|
5
41
|
const commonOptions: Partial<Options> = {
|
|
@@ -15,15 +51,35 @@ export default defineConfig((options) => {
|
|
|
15
51
|
{
|
|
16
52
|
...commonOptions,
|
|
17
53
|
format: ['esm'],
|
|
18
|
-
outExtension: () => ({ js: '.mjs' }),
|
|
54
|
+
outExtension: () => ({ js: '.development.mjs' }),
|
|
55
|
+
dts: false,
|
|
56
|
+
esbuildPlugins: [deepkitPlugin],
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
...commonOptions,
|
|
61
|
+
format: ['esm'],
|
|
62
|
+
outExtension: () => ({ js: '.mjs' }),
|
|
19
63
|
dts: true,
|
|
20
64
|
clean: true,
|
|
65
|
+
// No deepkitPlugin - strips Deepkit transformation
|
|
21
66
|
},
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
...commonOptions,
|
|
70
|
+
format: 'cjs',
|
|
71
|
+
outDir: './dist/cjs/',
|
|
72
|
+
outExtension: () => ({ js: '.development.cjs' }),
|
|
73
|
+
dts: false,
|
|
74
|
+
esbuildPlugins: [deepkitPlugin],
|
|
75
|
+
},
|
|
76
|
+
|
|
22
77
|
{
|
|
23
78
|
...commonOptions,
|
|
24
79
|
format: 'cjs',
|
|
25
80
|
outDir: './dist/cjs/',
|
|
26
81
|
outExtension: () => ({ js: '.cjs' }),
|
|
82
|
+
dts: false,
|
|
27
83
|
},
|
|
28
84
|
]
|
|
29
85
|
})
|