### Install All Dependencies Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md Run this command in the root folder to install all project dependencies and perform other required setup steps. ```bash npm run install:all ``` -------------------------------- ### Run Development Mode Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Start the library in Rollup watch mode and run all example applications. The Next.js 15 demo is available at http://localhost:3000. ```bash pnpm run dev ``` -------------------------------- ### Install state-in-url Package Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md Install the state-in-url package using npm, yarn, or pnpm. ```sh # npm npm install --save state-in-url # yarn yarn add state-in-url # pnpm pnpm add state-in-url ``` -------------------------------- ### Run Demo Project in Watch Mode Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md Starts the demo project in watch mode for development. Ensure Playwright is installed separately. ```bash npm run dev ``` -------------------------------- ### Setup Playwright Dependencies Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Install Playwright with necessary dependencies, typically required before running end-to-end tests on a new machine. ```bash pnpm run setup ``` -------------------------------- ### Install AI Coding Agent Skills for state-in-url Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md Run this command to install skill files for AI coding agents to better understand and use the state-in-url library. ```sh npx @tanstack/intent@latest install ``` -------------------------------- ### useUrlEncode Hook Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useUrlEncode/README.md Demonstrates how to use the useUrlEncode hook to get stringify and parse functions for managing URL state. Includes examples of stringifying state to a query string and parsing a query string back into a state object. ```typescript import { useUrlEncode } from 'state-in-url/useUrlEncode'; const form = { name: '' }; const { parse, stringify } = useUrlEncode(form); // Stringify state to URL query string const queryString = stringify({ name: 'John' }, 'someExistingParamToKeep=123'); console.log(queryString); // Output: name='John'&someExistingParamToKeep=123 // Parse URL query string to state object const state = parse("name='Tom'"); console.log(state); // Output: { name: 'Tom' } ``` -------------------------------- ### Install state-in-url Package Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs15/public/llms.txt Install the state-in-url package using npm. Ensure your tsconfig.json has moduleResolution set to 'Bundler', 'Node16', or 'NodeNext'. ```bash npm install state-in-url ``` -------------------------------- ### Basic useSharedState Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useSharedState.md Demonstrates how to use useSharedState for state synchronization between components. Components referencing the same module-level state object will automatically sync. ```typescript import { useSharedState } from 'state-in-url'; // Module level const userState = { name: '', email: '', theme: 'light' }; // Component A function SettingsPanel() { const { state, setState } = useSharedState(userState); return (
setState({ name: e.target.value })} /> setState({ email: e.target.value })} />
); } // Component B - automatically synced function UserCard() { const { state } = useSharedState(userState); return (

{state.name}

{state.email}

); } // Component C - using getState function Header() { const { state, getState } = useSharedState(userState); const handleSave = async () => { const current = getState(); // No dependency needed await saveSettings(current); }; return ; } ``` -------------------------------- ### Remix v2 Setup with useUrlState Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/react-router-remix-setup/SKILL.md Integrate useUrlState in Remix v2 applications by importing from 'state-in-url/remix'. This setup allows URL state management within Remix routes. ```typescript import { useUrlState } from 'state-in-url/remix'; type FiltersState = { sort: 'name' | 'date'; page: number }; const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 }; export default function Route() { const { urlState, setUrl } = useUrlState(FILTERS_STATE); return ; } ``` -------------------------------- ### Date Value Encoding Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Demonstrates how Date values are serialized to ISO strings with the 'date' symbol prefix when encoded. ```typescript new Date('2024-01-15') → '⏲2024-01-15T00:00:00.000Z' ``` -------------------------------- ### Encoding Detection Regex Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Provides examples of using the `ENC_REG` pattern to test strings and determine if they start with an encoding symbol, indicating they are already encoded. ```typescript ENC_REG.test('⏲2024-01-15T00:00:00.000Z'); // true ENC_REG.test('∙undefined'); // true ENC_REG.test('hello'); // false ``` -------------------------------- ### Filter/Search Page Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md Demonstrates managing search query, category, sort order, and pagination using useUrlState. Handles immediate state updates and debounced URL synchronization. ```typescript import { useUrlState } from 'state-in-url/react-router'; const filterForm = { query: '', category: 'all', page: 1, sortBy: 'relevance', }; export default function SearchResults() { const { urlState, setState, setUrl, reset } = useUrlState(filterForm, { replace: true, preventScrollReset: true, }); const handleSearchChange = (query) => { // Immediate state update setState({ query, page: 1 }); // Debounced URL sync setUrl({ query, page: 1 }); }; const handleCategoryFilter = (category) => { setUrl({ category, page: 1 }); }; const handlePageChange = (page) => { setUrl({ page }, { preventScrollReset: false }); // Scroll to top }; return (
handleSearchChange(e.target.value)} placeholder="Search products..." />
Page {urlState.page}
); } ``` -------------------------------- ### Filter Form Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-next.md Demonstrates managing form state, including search queries, categories, and pagination, synchronized with the URL. It shows immediate state updates and debounced URL synchronization. ```typescript import { useUrlState } from 'state-in-url/next'; const filterState = { query: '', category: 'all', sort: 'recent', page: 1, }; type FilterState = typeof filterState; export default function SearchPage() { const { urlState, setState, setUrl, reset } = useUrlState(filterState, { replace: true, scroll: false, }); const handleQueryChange = (e) => { const query = e.target.value; // Immediate state update setState({ query, page: 1 }); // Debounced URL sync (waits 70ms for more changes) setUrl({ query, page: 1 }); }; const handleCategoryChange = (cat) => { setUrl({ category: cat, page: 1 }); }; const handleNextPage = () => { setUrl((curr) => ({ ...curr, page: curr.page + 1 })); }; return (
Showing page {urlState.page} sorted by {urlState.sort}
); } ``` -------------------------------- ### Debounce Timeout Behavior Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Illustrates the 'last update wins' semantics of the debounce mechanism, showing how rapid sequential updates result in a single URL write after a period of inactivity. ```text User types: 't' → 'te' → 'tex' → 'tex ' → 'text' Timeline (normal browser, 70ms timeout): t: [ Timer starts ▲ ] te: [ Timer cleared and restarted ▲ ] tex: [ Timer cleared and restarted ▲ ] tex : [ Timer cleared and restarted ▲ ] text: [ Timer cleared and restarted ▲ ] [ 70ms passes with no input ] [ URL written to history once ✓ ] ``` -------------------------------- ### Tabs with URL State Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md Manages the active tab state and expansion status, synchronizing it with the URL. This allows users to bookmark or share specific tab views. ```typescript const tabState = { activeTab: 'overview', expanded: false, }; export function TabComponent() { const { urlState, setUrl } = useUrlState(tabState, { preventScrollReset: true, }); return (
{['overview', 'details', 'comments'].map((tab) => ( ))}
{urlState.activeTab === 'overview' && } {urlState.activeTab === 'details' && } {urlState.activeTab === 'comments' && }
); } ``` -------------------------------- ### useUrlState Hook for Remix.js Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md Example demonstrating the usage of the useUrlState hook specifically for applications built with Remix.js. This hook integrates with Remix's routing and data loading mechanisms. ```typescript import { useUrlState } from 'state-in-url'; interface RemixState { filter: string; } const initialRemixState: RemixState = { filter: '', }; function RemixComponent() { const [state] = useUrlState(initialRemixState); return (
setUrlState({ filter: e.target.value })} placeholder="Filter items..." /> {/* Render filtered items based on state.filter */}
); } ``` -------------------------------- ### Import useUrlState for Next.js Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/README.md Quick start import for using `useUrlState` hook specifically within a Next.js application. ```typescript import { useUrlState } from 'state-in-url/next'; ``` -------------------------------- ### Example of a Large State Object within Limits Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Illustrates a state object that fits comfortably within typical browser URL length limits. This example assumes approximately 60 bytes per field, resulting in a total state size well under the estimated 5000 character safe limit. ```typescript // A state object with ~50 properties fits comfortably const largeState = { // 50 × ~60 byte fields = ~3000 bytes = ~3KB // Comfortably under 5000 char safe limit }; ``` -------------------------------- ### Browser History Integration Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md Illustrates the automatic synchronization of component state with URL changes triggered by browser history events like the back/forward buttons. ```typescript // User clicks back button // → Browser navigates to previous URL // → Hook receives popstate event // → state updates to match URL // → Component rerenders with new state ``` -------------------------------- ### isEqual Utility Function Examples Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md Shows examples of deep equality comparison using the isEqual function, which handles structural equality for objects and arrays, and type-aware comparison for primitives. ```typescript isEqual({ a: 1 }, { a: 1 }); // true isEqual([1, 2], [1, 2]); // true isEqual(new Date('2024-01-15'), new Date('2024-01-15')); // true isEqual({ a: [1, 2] }, { a: [1, 2] }); // true ``` -------------------------------- ### Decoding Example with Symbols Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Illustrates how the reviver function decodes prefixed strings back into their original types, such as Date objects and undefined values. ```typescript '⏲2024-01-15T00:00:00.000Z' → new Date('2024-01-15') '∙undefined' → undefined 'hello' → 'hello' (unchanged) ``` -------------------------------- ### setState Usage Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md Demonstrates how to use the setState function to update the state locally without immediately synchronizing it to the URL. This is useful for responsive UI updates while debouncing URL changes. ```javascript setState({ page: 2 }) // merge with current state setState((curr, initial) => ({ ...curr, sort: 'asc' })) // updater function ``` -------------------------------- ### Using routerHistory with useUrlStateBase Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/utilities.md Demonstrates how to integrate `routerHistory` with the `useUrlStateBase` hook to manage application state synchronized with the URL. This example shows updating the URL to reflect a new page number. ```typescript import { routerHistory, useUrlStateBase } from 'state-in-url'; const state = { search: '', page: 1 }; // Use routerHistory with useUrlStateBase const { updateUrl } = useUrlStateBase(state, routerHistory); updateUrl({ page: 2 }); // Uses window.history.replaceState ``` -------------------------------- ### Full State Encoding Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Demonstrates encoding a state object containing various data types, including a Date and an undefined value, using the library's encode function and type symbols. ```typescript import { SYMBOLS, encode } from 'state-in-url/encoder'; const state = { name: 'John', joined: new Date('2024-01-15'), notes: undefined, }; const encoded = encode(state); // Result: '{"name":"John","joined":"⏲2024-01-15T00:00:00.000Z","notes":"∙undefined"}' // Can be placed in URL: // https://example.com?state={"name":"John","joined":"⏲2024-01-15T00:00:00.000Z","notes":"∙undefined"} ``` -------------------------------- ### Creating a Custom useUrlState Hook Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useUrlStateBase/README.md This example demonstrates how to create a custom useUrlState hook by extending the useUrlStateBase hook. It sets up a basic router object using React.useMemo for push and replace functionalities. ```typescript import { useUrlStateBase } from 'state-in-url/useUrlStateBase'; function useUrlStateCustom(state: T) { const router = React.useMemo({ push: (url: string) => window.history.pushState(url), replace: (url: string) => window.history.replaceState(url) }, []); return useUrlState(state, router); } ``` -------------------------------- ### Basic Usage of useUrlState Hook Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/react-router6/useUrlState/README.md Demonstrates how to initialize the hook with default state, update state locally using setState, and update both state and URL using setUrl. Includes examples of functional updates and passing navigation options. ```typescript import { useUrlState } from 'state-in-url/react-router6'; const form = { name: '', age: 0 }; const { urlState, setState, setUrl } = useUrlState(form); // Update state without changing URL setState({ name: 'test' }); setState(currVal => ({ ...currVal, name: 'test' }) ); // reset state setState((_curr, initial) => initial); // Update state and URL // options from type `NavigateOptions` from 'react-router` setUrl({ name: 'test' }, { replace: false, preventScrollReset: false }); // reset state and URL setUrl((_curr, initial) => initial); ``` -------------------------------- ### Undefined Value Encoding Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/constants.md Shows how undefined values are encoded as the literal string '∙undefined'. ```typescript undefined → '∙undefined' ``` -------------------------------- ### Product Filtering Component with useUrlState Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-remix.md Demonstrates how to use useUrlState to manage filter states for a product gallery. It includes examples for updating individual filters and resetting all filters. Options like 'replace' and 'preventScrollReset' can be configured. ```typescript import { useUrlState } from 'state-in-url/remix'; const productFilters = { query: '', category: 'all', priceMin: 0, priceMax: 1000, inStock: false, page: 1, }; export function ProductGallery() { const { urlState, setState, setUrl, reset } = useUrlState( productFilters, { replace: true, preventScrollReset: true, } ); const handleSearch = (query) => { setState({ query, page: 1 }); setUrl({ query, page: 1 }); }; const handlePriceRange = (min, max) => { setUrl({ priceMin: min, priceMax: max, page: 1 }); }; const toggleStock = () => { setUrl((curr) => ({ ...curr, inStock: !curr.inStock, page: 1 })); }; return (
handleSearch(e.target.value)} placeholder="Search products..." />
setUrl({ page }, { preventScrollReset: false })} />
); } ``` -------------------------------- ### typeOf Utility Function Examples Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md Demonstrates the detailed type information returned by the typeOf function, distinguishing between various types including null, arrays, objects, dates, and primitives. ```typescript typeOf(null); // 'null' typeOf([1, 2, 3]); // 'array' typeOf({}); // 'object' typeOf(new Date()); // 'date' typeOf(42); // 'number' typeOf(undefined); // 'undefined' typeof undefined; // 'object' (difference!) ``` -------------------------------- ### useSharedState with Initialization Function Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useSharedState.md Utilize the optional initialization function to provide an initial state, for example, by loading data from localStorage. This function is called only once on the first browser mount. ```typescript const userState = { name: '', age: 0 }; function Component() { const { state, setState } = useSharedState(userState, () => { // Called once on first browser mount // Return initial state (e.g., from localStorage) const saved = localStorage.getItem('user'); return saved ? JSON.JSON.parse(saved) : userState; }); } ``` -------------------------------- ### Using useUrlState Hook in Remix Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/remix/useUrlState/README.md Demonstrates how to use the useUrlState hook to manage local component state synchronized with URL search parameters. Includes examples for updating state locally and updating both state and URL. ```typescript import { useUrlState } from 'state-in-url/remix'; const form = { name: '', age: 0 }; const { urlState, setState, setUrl } = useUrlState(form); // Update state without changing URL setState({ name: 'test' }); setState(currVal => ({ ...currVal, name: 'test' }) ); // reset state setState((_curr, initial) => initial); // Update state and URL // options from type `NavigateOptions` from 'react-router` setUrl({ name: 'test' }, { replace: false, preventScrollReset: false }); // reset state and URL setUrl((_curr, initial) => initial); ``` -------------------------------- ### Using useUrlState in Layout with Middleware Workaround Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md This example demonstrates a workaround for accessing search parameters in Next.js App Router layouts using middleware to set headers. This allows the layout component to access and decode state from the URL. ```typescript // add to appropriate `layout.tsc` export const runtime = 'edge'; // middleware.ts import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; export function middleware(request: NextRequest) { const url = request.url?.includes('_next') ? null : request.url; const sp = url?.split?.('?')?.[1] || ''; const response = NextResponse.next(); if (url !== null) { response.headers.set('searchParams', sp); } return response; } // Target layout component import { headers } from 'next/headers'; import { decodeState } from 'state-in-url/encodeState'; export default async function Layout({ children, }: { children: React.ReactNode; }) { const sp = headers().get('searchParams') || ''; return (
{children}
); } ``` -------------------------------- ### React Router v7 Setup with useUrlState Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/react-router-remix-setup/SKILL.md Import and use the useUrlState hook from 'state-in-url/react-router' for React Router v7. Define your state type and initial state, then use the hook to access and update URL-bound state. ```typescript import { useUrlState } from 'state-in-url/react-router'; type FiltersState = { sort: 'name' | 'date'; page: number }; const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 }; export function FiltersBar() { const { urlState, setUrl } = useUrlState(FILTERS_STATE); return ; } ``` -------------------------------- ### Using useUrlState in Remix Client Components Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-remix.md Explains how to use useUrlState within Remix applications, emphasizing that hooks can only be used in Client Components. This example shows a common pattern where a Server Component renders a Client Component that utilizes the hook. ```typescript // routes/search.tsx export default function SearchPage() { // This is a Server Component // useUrlState cannot be used here return ; } // routes/search.client.tsx or wrap in import { useUrlState } from 'state-in-url/remix'; const searchForm = { query: '', page: 1 }; function SearchClient() { // This must be a Client Component to use hooks const { urlState, setUrl } = useUrlState(searchForm); return ( setUrl({ query: e.target.value, page: 1 })} /> ); } ``` -------------------------------- ### Using URL State Hook with History Enabled (Default) Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/nextjs-ssr/SKILL.md This example shows the correct usage of the `useUrlState` hook with default history enabled. This is suitable for most cases where URL changes should update the browser history and avoid unnecessary server round-trips. ```typescript useUrlState(FORM_STATE, { searchParams }); ``` -------------------------------- ### Cleanup and Reinstall Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Remove build artifacts and node_modules directories, then reinstall dependencies. ```bash pnpm run cleanup ``` ```bash pnpm run reinstall ``` -------------------------------- ### useUrlState Hook with Server-Side Rendering Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md Example of using the useUrlState hook in a server-side rendering context, likely within a Next.js application. Ensure proper setup for SSR compatibility. ```typescript import { useUrlState } from 'state-in-url'; interface State { userId: string; } const initialState: State = { userId: '', }; // Assume this is a Server Component or a component within Next.js SSR context function UserProfile() { const [state] = useUrlState(initialState); return (

User Profile

User ID: {state.userId}

{/* Other profile details */}
); } ``` -------------------------------- ### Server-Side Initialization with useUrlStateBase Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlStateBase.md Shows how to initialize state from the server using useUrlStateBase. It returns default values on the server and parses the URL on the client. ```typescript const { state, updateUrl, } = useUrlStateBase( defaultForm, router, ({ parse }) => { // Called on first render in browser if (typeof window === 'undefined') { return defaultForm; // SSR } // Load from current URL or localStorage const fromUrl = parse(window.location.search.slice(1)); return fromUrl; }, ); ``` -------------------------------- ### decodePrimitive(str) Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/encoder.md Restores type information from sentinel-prefixed strings. It decodes strings starting with '∙undefined' to undefined and strings starting with '⏲' to Date objects. ```APIDOC ## decodePrimitive(str) ### Description Restores type information from sentinel-prefixed strings. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Not Applicable (Function Call) ### Endpoint Not Applicable (Function Call) ### Parameters - **str** (string) - Required - String to decode. ### Behavior - Strings starting with `∙undefined` return `undefined` - Strings starting with `⏲` are parsed as ISO date strings into Date objects - All other strings are returned unchanged ### Example ```typescript decodePrimitive('∙undefined'); // undefined decodePrimitive('⏲2024-01-15T00:00:00.000Z'); // Date object decodePrimitive('hello'); // 'hello' ``` ### Source `packages/urlstate/encoder/encoder.ts:107-112` ``` -------------------------------- ### Build Library Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Build the library using Rollup, generating ESM, CJS, and .d.ts files in the dist/ directory. ```bash pnpm run build ``` -------------------------------- ### useUrlState Hook for React-Router Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/README.md An example showcasing the use of the useUrlState hook within an application managed by React-Router. This allows URL state synchronization with React Router's navigation. ```typescript import { useUrlState } from 'state-in-url'; import { useLocation, useNavigate } from 'react-router-dom'; interface RouterState { page: number; } const initialRouterState: RouterState = { page: 1, }; function PaginationComponent() { const location = useLocation(); const navigate = useNavigate(); // Pass location and navigate to useUrlState for React-Router integration const [state] = useUrlState(initialRouterState, { location, navigate, }); return (

Current Page: {state.page}

); } ``` -------------------------------- ### Using useUrlState Hook Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/react-router/useUrlState/README.md Demonstrates how to initialize the useUrlState hook with default form values and how to use setState and setUrl to manage state and URL synchronization. ```typescript import { useUrlState } from 'state-in-url/react-router'; const form = { name: '', age: 0 }; const { urlState, setState, setUrl } = useUrlState(form); // Update state without changing URL setState({ name: 'test' }); setState(currVal => ({ ...currVal, name: 'test' }) ); // reset state setState((_curr, initial) => initial); // Update state and URL // options from type `NavigateOptions` from 'react-router` setUrl({ name: 'test' }, { replace: false, preventScrollReset: false }); // reset state and URL setUrl((_curr, initial) => initial); ``` -------------------------------- ### Valid and Invalid JSONCompatible Examples Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md Illustrates valid and invalid examples of the JSONCompatible type. Valid states include basic types, Dates, nested objects, and arrays. Invalid states contain functions, non-JSON types, or symbols. ```typescript // ✅ Valid JSONCompatible const validState = { name: 'John', age: 30, joined: new Date('2024-01-15'), tags: ['react', 'typescript'], settings: { theme: 'dark', notifications: true, }, inactive: undefined, }; // ❌ Invalid (not JSONCompatible) const invalidState = { callback: () => {}, regex: /pattern/, symbol: Symbol('id'), }; ``` -------------------------------- ### Run Full Test Suite Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Execute the complete test suite, including type checking, unit tests, build, and integration tests. This is the command used in CI. ```bash pnpm run test ``` -------------------------------- ### Discrete Control with Direct setUrl Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/input-handling/SKILL.md Demonstrates using setUrl directly for discrete controls like buttons, as they typically fire infrequently. ```typescript ``` -------------------------------- ### Framework Wrapper Pattern Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/architecture.md This pattern shows how a framework-specific hook adapts the router and options, then combines state, history synchronization, and debouncing using `useSharedState`, `useUrlEncode`, and a history listener. ```text Framework-specific hook ↓ adapts router and options useUrlStateBase ↓ combines state + history sync + debounce ├─ useSharedState (cross-component sync) ├─ useUrlEncode (encode/decode functions) └─ history listener (popstate handling) ``` -------------------------------- ### getSearch() Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/utilities.md Gets the current window location search string. Returns the browser's `window.location.search` or an empty string on the server. ```APIDOC ## `getSearch()` ### Description Gets current window location search string. ### Returns - Browser: `window.location.search` (e.g., `'?name=John&age=30'`) - Server: Empty string `''` ### Example ```typescript import { getSearch } from 'state-in-url'; getSearch(); // Browser: '?name=John&age=30' getSearch(); // Server: '' ``` ``` -------------------------------- ### Basic Usage of useUrlEncode Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlEncode.md Demonstrates how to use the stringify and parse functions returned by useUrlEncode to convert state to a query string and back. Note that default values are omitted during stringification. ```typescript import { useUrlEncode } from 'state-in-url'; const form = { name: '', age: 0, tags: [], joinedAt: new Date(), }; function SearchComponent() { const { stringify, parse } = useUrlEncode(form); // Encode state to query string const query = stringify({ name: 'Alice', age: 28, tags: [], // omitted if matches default joinedAt: new Date('2024-01-15'), }); console.log(query); // Output: 'name=Alice&age=28&joinedAt=⏲2024-01-15T00:00:00.000Z' // Decode query string back to state const state = parse(query); console.log(state); // Output: { // name: 'Alice', // age: 28, // tags: [], // joinedAt: Date(2024-01-15) // } } ``` -------------------------------- ### Import All Main Utilities Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/README.md Imports all primary hooks and utilities from the `state-in-url` package, including `useUrlState`, `useSharedState`, and various encoding functions. ```typescript import { useUrlState, useSharedState, encode, decode, encodeState, decodeState, typeOf, isSSR, } from 'state-in-url'; ``` -------------------------------- ### URL Parameter Handling Utilities Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/MANIFEST.md Functions for handling URL parameters, including getting parameters from a URL and filtering unknown parameters. ```typescript import { getParams, filterUnknownParams, filterUnknownParamsClient } from "state-in-url/utils"; // Example usage: const url = new URL("http://example.com?a=1&b=2&c=3"); const params = getParams(url); console.log(params); // { a: "1", b: "2", c: "3" } const allowedParams = { a: "1" }; const filtered = filterUnknownParams(params, allowedParams); console.log(filtered); // { a: "1" } // filterUnknownParamsClient is similar but may have client-specific logic. ``` -------------------------------- ### SSR Initial State Hydration Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/shared-state-no-url/SKILL.md Provide a function as the second argument to `useSharedState` to hydrate the initial state on the server, for example, by reading from a cookie. ```typescript const { state } = useSharedState(CART_STATE, () => readFromCookie()); ``` -------------------------------- ### Run Integration Tests Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md Executes the integration tests. Requires the demo project to be running (`npm run dev`). ```bash npm run test:int ``` -------------------------------- ### Imperative State Access Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useSharedState.md Shows how to get the current state value imperatively without triggering a re-render. Useful for reading state before an asynchronous operation. ```typescript const { getState } = useSharedState(userState); const handleAsync = async () => { const current = getState(); const result = await fetchData(current.id); // Use current without race condition }; ``` -------------------------------- ### Run All Tests Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CONTRIBUTING.md Executes all unit and end-to-end tests for the project. ```bash npm run test ``` -------------------------------- ### setState Usage Example Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-next.md Demonstrates how to update the component's state without immediately syncing it to the URL, useful for debouncing URL updates during form input. ```typescript // merge with current state setState({ name: 'John' }) // updater function with access to current and initial state setState((curr, initial) => ({ ...curr, age: 30 })) ``` -------------------------------- ### Test LLM Content with Curl Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs14/README-llms-txt.md Use curl to test how the application responds to different Accept headers. The first command requests markdown, while the second requests HTML. ```bash curl -H "Accept: text/markdown" http://localhost:3000 # Should return markdown content curl -H "Accept: text/html" http://localhost:3000 # Should return HTML ``` -------------------------------- ### Use useUrlState Hook in Next.js App Router Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Example of using the `useUrlState` hook for Next.js App Router. It handles SSR and defaults to window.history navigation. ```typescript import { useUrlState } from "state-in-url/next"; // Example usage in a Next.js App Router component function MyComponent() { const [value, setValue] = useUrlState("myKey", "defaultValue"); return (

Current value: {value}

); } ``` -------------------------------- ### URLSearchParams Initialization Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/types.md Illustrates how to initialize URLSearchParams with either a query string or an array of key-value pairs. ```typescript new URLSearchParams('name=John&age=30'); new URLSearchParams([['name', 'John'], ['age', '30']]); ``` -------------------------------- ### state-in-url (default export) Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/entry-points.md The main package provides a complete library with framework-agnostic utilities and a Next.js hook. It exports hooks like `useUrlState` and `useSharedState`, encoding functions such as `encode` and `decode`, and utility functions like `typeOf`. ```APIDOC ## state-in-url (default export) ### Description Provides a comprehensive library with framework-agnostic utilities and a Next.js hook. Suitable for Next.js users, utility consumers, and most applications. ### Exports - **Hooks:** `useUrlState`, `useSharedState`, `useUrlEncode`, `useUrlStateBase` - **Encoding functions:** `encode`, `decode`, `encodeState`, `decodeState` - **Utilities:** `typeOf`, `isSSR` - **Types:** `JSONCompatible`, `Type` ``` -------------------------------- ### React Router v6 Setup with useUrlState Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/skills/react-router-remix-setup/SKILL.md Use the useUrlState hook from 'state-in-url/react-router6' for React Router v6 projects. This import path is specific to v6 and later versions of state-in-url. ```typescript // Note the /react-router6 subpath import { useUrlState } from 'state-in-url/react-router6'; type FiltersState = { sort: 'name' | 'date'; page: number }; const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 }; export function FiltersBar() { const { urlState, setUrl } = useUrlState(FILTERS_STATE); return ; } ``` -------------------------------- ### Detect Value Type with typeOf Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/utilities.md Use `typeOf` to get detailed type information beyond JavaScript's native `typeof`. Useful for custom serialization or type-based routing. ```typescript import { typeOf } from 'state-in-url'; typeOf(null); // 'null' typeOf([1, 2, 3]); // 'array' typeOf({}); // 'object' typeOf(new Date()); // 'date' typeOf(42); // 'number' typeOf('hello'); // 'string' typeOf(true); // 'boolean' typeOf(undefined); // 'undefined' typeOf(() => {}); // 'function' typeOf(Symbol('id')); // 'symbol' typeOf(1n); // 'bigint' // Differences from typeof typeof null; // 'object' typeOf(null); // 'null' typeof [1, 2]; // 'object' typeOf([1, 2]); // 'array' typeof new Date(); // 'object' typeOf(new Date()); // 'date' ``` -------------------------------- ### Basic useUrlState Hook Usage Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs15/public/llms.txt Demonstrates the basic usage of the `useUrlState` hook, including state retrieval, synchronous internal state updates, and URL updates. ```typescript const { urlState, setState, setUrl, reset } = useUrlState(DEFAULT_STATE, options?); ``` -------------------------------- ### Using useSharedState Hook Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useSharedState/README.md Demonstrates how to initialize and use the useSharedState hook to manage shared form state. Shows how to update the state using direct object assignment or a functional update, and how to retrieve the current state. ```typescript import { useSharedState } from 'state-in-url/useSharedState'; const form = { name: '', age: 0 }; const { state, getState, setState } = useSharedState(form); // Update state setState({ name: 'test' }); // Or update state using a function setState(curr => ({ ...curr, name: 'test' })); // Get current state const currentState = getState(); ``` -------------------------------- ### Main Package Exports Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/entry-points.md Imports all utilities, hooks, and types from the main 'state-in-url' package. Recommended for Next.js users, utility consumers, and most applications. ```typescript import { // Hooks useUrlState, // Next.js hook useSharedState, // Cross-component state useUrlEncode, // Low-level encode/decode useUrlStateBase, // Generic hook base // Encoding functions encode, // Value → URL string decode, // URL string → value encodeState, // State → query string decodeState, // Query string → state // Utilities typeOf, // Enhanced typeof isSSR, // Server environment detection // Types JSONCompatible, Type, } from 'state-in-url'; ``` -------------------------------- ### Run Unit Tests Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/CLAUDE.md Execute Vitest unit tests. This command runs in watch mode by default and enables coverage. ```bash pnpm run test:unit ``` -------------------------------- ### Conditional URL State Updates Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-remix.md Implement logic for conditional updates to the URL state based on user interactions. This example shows how to toggle sort order or set a new sort field. ```typescript const { setUrl, urlState } = useUrlState(form); const handleSort = (sortBy) => { if (urlState.sort === sortBy) { setUrl({ sortAsc: !urlState.sortAsc }); } else { setUrl({ sort: sortBy, sortAsc: true }); } }; ``` -------------------------------- ### useUrlState Options Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/example-nextjs15/public/llms.txt Explains the `options` object that can be passed to `useUrlState` for controlling URL update behavior like `replace` and `scroll`, and for SSR correctness in Next.js. ```typescript // options (per-call or as hook-level defaults): // - replace?: boolean — router.replace (default true) vs router.push. // - scroll?: boolean — Next.js scroll behavior (default false). // React Router / Remix: any NavigateOptions (e.g. preventScrollReset). // Hook-level options (second arg to useUrlState): // - searchParams — pass searchParams from a Next.js server component or useSearchParams() from a client component. Required for SSR correctness in Next.js App Router. // - useHistory?: boolean — Next.js only. Default true. Uses window.history.pushState to avoid _rsc server round-trips on URL changes. Flip to false only when server data must refetch on URL change. ``` -------------------------------- ### Basic Usage of useUrlState Hook Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/next/useUrlState/README.md Demonstrates how to initialize the hook with default form values and use setState to update state locally without affecting the URL. Also shows how to use setUrl to update both state and URL, including options for replace and scroll behavior. ```typescript import { useUrlState } from 'state-in-url/next'; const form = { name: '', age: 0 }; const { urlState, setState, setUrl } = useUrlState(form); // Update state without changing URL setState({ name: 'test' }); // API same as React.useState setState(currVal => ({ ...currVal, name: 'test' }) ); // reset state setState((_curr, initial) => initial); // Update state and URL setUrl({ name: 'test' }, { replace: false, scroll: true }); // reset state and URL setUrl((_curr, initial) => initial); ``` -------------------------------- ### setUrl with Navigate Function Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-react-router.md Shows how the setUrl function, when useHistory is false (default), calls React Router's navigate function to update both the state and the URL. Includes example options for navigation. ```typescript setUrl({ page: 2 }, { replace: true, preventScrollReset: true }); // Calls: navigate('?page=2', { replace: true, preventScrollReset: true }) ``` -------------------------------- ### useUrlStateBase Hook Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/packages/urlstate/useUrlStateBase/README.md A custom React hook to create custom `useUrlState` hooks. It requires a default state, a router object with push and replace methods, and optionally a function to get the initial state. ```APIDOC ## `useUrlStateBase` hook A custom React hook to create custom `useUrlState` hooks. ### Parameters: - `defaultState` (object) - An object representing the default state values. - `router` (object) - Router object with `push` and `replace` methods - `getInitialState?` (function) - Optional function that return initial state. ### Returns: An object containing: - `state` (object) - The current state. - `getState` (Function) - Function to get state. - `updateState` (Function) - Function to update the state without updating the URL. - `updateUrl` (Function) - Function to update both the state and the URL. - `reset` (Function) - Function to reset state and url to default values ``` -------------------------------- ### setUrl Behavior: Window History vs Next.js Router Source: https://github.com/asmyshlyaev177/state-in-url/blob/master/_autodocs/api-reference/useUrlState-next.md Illustrates the difference in URL updating behavior between using the default `window.history` and explicitly disabling it to use the Next.js router. ```typescript // useHistory: true (default) setUrl({ page: 2 }); // → window.history.replaceState(null, '', '?page=2') // → No server revalidation, no _rsc param // useHistory: false setUrl({ page: 2 }); // → router.push('?page=2') // → May trigger RSC revalidation ```