state-in-url 6.5.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.es.md +70 -5
  2. package/README.fr.md +70 -5
  3. package/README.ja.md +68 -3
  4. package/README.ko.md +68 -3
  5. package/README.md +69 -4
  6. package/README.pt-BR.md +70 -5
  7. package/README.ru.md +70 -5
  8. package/README.vi.md +70 -5
  9. package/README.zh-CN.md +70 -5
  10. package/dist/astro/index.js +1 -1
  11. package/dist/astro/index.mjs +1 -1
  12. package/dist/astro/useUrlState/index.js +1 -1
  13. package/dist/astro/useUrlState/index.mjs +1 -1
  14. package/dist/astro/useUrlState/useUrlState.d.ts +1 -85
  15. package/dist/index.d.ts +1 -2
  16. package/dist/index.js +1 -1
  17. package/dist/index.mjs +1 -1
  18. package/dist/next/useUrlState/useUrlState.mjs +1 -1
  19. package/dist/package.json +6 -1
  20. package/dist/react/index.d.ts +1 -0
  21. package/dist/react/index.js +1 -0
  22. package/dist/react/index.mjs +1 -0
  23. package/dist/react/useUrlState/index.d.ts +1 -0
  24. package/dist/react/useUrlState/index.js +1 -0
  25. package/dist/react/useUrlState/index.mjs +1 -0
  26. package/dist/react/useUrlState/useUrlState.d.ts +86 -0
  27. package/package.json +6 -1
  28. package/skills/astro-setup/SKILL.md +1 -1
  29. package/skills/feature-state-hook/SKILL.md +1 -1
  30. package/skills/form-library-integration/SKILL.md +1 -1
  31. package/skills/input-handling/SKILL.md +1 -1
  32. package/skills/nextjs-ssr/SKILL.md +1 -1
  33. package/skills/react-no-router/SKILL.md +215 -0
  34. package/skills/react-router-remix-setup/SKILL.md +1 -1
  35. package/skills/shared-state-no-url/SKILL.md +1 -1
  36. /package/dist/{astro → react}/useUrlState/useUrlState.js +0 -0
  37. /package/dist/{astro → react}/useUrlState/useUrlState.mjs +0 -0
package/README.es.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- i18n:start -->
2
2
  [English](./README.md) · [简体中文](./README.zh-CN.md) · [日本語](./README.ja.md) · [한국어](./README.ko.md) · [Русский](./README.ru.md) · Español · [Português (BR)](./README.pt-BR.md) · [Français](./README.fr.md) · [Tiếng Việt](./README.vi.md)
3
- <!-- i18n:meta locale=es source=README.md source-blob=4d98ba970e6aab8f29987fbcba29fb6c61c2fc67 status=translated -->
3
+ <!-- i18n:meta locale=es source=README.md source-blob=ad78fdbbee096115a953813ed9a462e3393c5736 status=translated -->
4
4
  <!-- i18n:end -->
5
5
 
6
6
  <div align="center">
@@ -150,14 +150,16 @@ La comparación completa — la misma feature en ambas, otras alternativas (TanS
150
150
  - [Ejemplo](#ejemplo)
151
151
  - [Hook useUrlState para React-Router](#hook-useurlstate-para-react-router)
152
152
  - [Ejemplo](#ejemplo-1)
153
- - [Hook useUrlState para Astro](#hook-useurlstate-para-astro)
153
+ - [Hook useUrlState para React (sin router)](#hook-useurlstate-para-react-sin-router)
154
154
  - [Ejemplo](#ejemplo-2)
155
+ - [Hook useUrlState para Astro](#hook-useurlstate-para-astro)
156
+ - [Ejemplo](#ejemplo-3)
155
157
  - [Recetas](#recetas)
156
158
  - [Hook personalizado para trabajar cómodamente con una porción del estado](#hook-personalizado-para-trabajar-cómodamente-con-una-porción-del-estado)
157
159
  - [Con una forma de estado compleja](#con-una-forma-de-estado-compleja)
158
160
  - [Actualizar solo el estado y sincronizarlo manualmente con la URL](#actualizar-solo-el-estado-y-sincronizarlo-manualmente-con-la-url)
159
161
  - [Otros hooks y helpers](#otros-hooks-y-helpers)
160
- - [Hook `useUrlStateBase` para otros routers](#hook-useurlstatebase-para-otros-routers)
162
+ - [Hook `useUrlStateBase` para otro router](#hook-useurlstatebase-para-otro-router)
161
163
  - [Hook `useSharedState` para React.js](#hook-usesharedstate-para-reactjs)
162
164
  - [Hook `useLinkProps` para React.js](#hook-uselinkprops-para-reactjs)
163
165
  - [Hook `useUrlEncode` para React.js](#hook-useurlencode-para-reactjs)
@@ -540,6 +542,39 @@ const tags = [
540
542
 
541
543
  [Ejemplo de código](packages/example-react-router6/src/Form-for-test.tsx)
542
544
 
545
+ ### Hook useUrlState para React (sin router)
546
+
547
+ Para una aplicación React sin router: Vite, Create React App, o un widget que se monta en una página que no controlas. El hook escribe la URL con `window.history` y la vuelve a leer al navegar atrás y adelante y ante cualquier otro `pushState`/`replaceState`. Todos los componentes que usan el mismo objeto de estado lo comparten, sin nada que envolver y sin nada que pasar por props.
548
+
549
+ [Documentación de la API](packages/urlstate/react/useUrlState)
550
+
551
+ #### Ejemplo
552
+
553
+ ```typescript
554
+ // useFilters.ts
555
+ import { useUrlState } from 'state-in-url/react';
556
+
557
+ type FiltersState = { sort: 'name' | 'date'; page: number };
558
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
559
+
560
+ export function useFilters() {
561
+ return useUrlState(FILTERS_STATE);
562
+ }
563
+ ```
564
+
565
+ ```typescript
566
+ // FiltersBar.tsx
567
+ import { useFilters } from './useFilters';
568
+
569
+ export function FiltersBar() {
570
+ const { urlState, setUrl } = useFilters();
571
+
572
+ return <button onClick={() => setUrl({ page: urlState.page + 1 })}>Page {urlState.page}</button>;
573
+ }
574
+ ```
575
+
576
+ `state-in-url/astro` es este mismo hook; se documenta aparte más abajo porque las islands además reciben `searchParams` como prop.
577
+
543
578
  ### Hook useUrlState para Astro
544
579
 
545
580
  Para islas de React. Astro no tiene router del lado del cliente por defecto, así que el hook escribe la URL con `window.history` y la vuelve a leer al navegar atrás/adelante y en cualquier otro `pushState`/`replaceState`, incluido el propio `<ClientRouter />` de Astro. Las islas de una página comparten el estado, sin nada que las envuelva.
@@ -818,9 +853,39 @@ Sincronizar el estado en `onBlur` estará más alineado con el uso en el mundo r
818
853
 
819
854
  ## Otros hooks y helpers
820
855
 
821
- ### Hook `useUrlStateBase` para otros routers
856
+ ### Hook `useUrlStateBase` para otro router
857
+
858
+ Úsalo para construir tu propio `useUrlState` para un router del que este paquete no publica un punto de entrada, por ejemplo TanStack Router. Pasa cualquier objeto memoizado con `push(url)` y `replace(url)`.
859
+
860
+ Si **no hay router alguno** no lo necesitas: usa [`state-in-url/react`](#hook-useurlstate-para-react-sin-router), que es este mismo hook ya conectado a `window.history`.
861
+
862
+ ```typescript
863
+ import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
864
+
865
+ type FiltersState = { sort: 'name' | 'date'; page: number };
866
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
867
+
868
+ export function useFilters() {
869
+ const router = useYourRouter();
870
+ const nav = React.useMemo(
871
+ () => ({
872
+ push: (url: string) => router.navigate(url),
873
+ replace: (url: string) => router.navigate(url, { replace: true }),
874
+ }),
875
+ [router],
876
+ );
877
+
878
+ return useUrlStateBase(FILTERS_STATE, nav, ({ parse }) => parse(window.location.search));
879
+ }
880
+ ```
881
+
882
+ Dos diferencias respecto a `useUrlState`:
883
+
884
+ - Devuelve `state`, `updateUrl` y `updateState`, no `urlState`, `setUrl` ni `setState`; además `updateUrl` hace push por defecto, mientras que `setUrl` hace replace.
885
+ - El tercer argumento define el state inicial. Si lo omites, el hook ignora la cadena de consulta con la que se cargó la página, así que un enlace compartido se abre con los valores por defecto.
822
886
 
823
- Hooks para crear tus propios hooks `useUrlState` con otros routers, p. ej. react-router o tanstack router.
887
+ > [!NOTE]
888
+ > `useUrlState` ya no se exporta desde la raíz del paquete: cada uno está atado a un framework, así que cada uno vive en su propio punto de entrada (`state-in-url/next`, `/react`, `/react-router`, `/react-router6`, `/remix`, `/astro`). La raíz solo conserva lo que es independiente del framework: `useSharedState`, `useUrlEncode`, `useUrlStateBase`, `useLinkProps`, `encode`/`decode` y `encodeState`/`decodeState`.
824
889
 
825
890
  [Documentación de la API](packages/urlstate/useUrlStateBase)
826
891
 
package/README.fr.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- i18n:start -->
2
2
  [English](./README.md) · [简体中文](./README.zh-CN.md) · [日本語](./README.ja.md) · [한국어](./README.ko.md) · [Русский](./README.ru.md) · [Español](./README.es.md) · [Português (BR)](./README.pt-BR.md) · Français · [Tiếng Việt](./README.vi.md)
3
- <!-- i18n:meta locale=fr source=README.md source-blob=4d98ba970e6aab8f29987fbcba29fb6c61c2fc67 status=translated -->
3
+ <!-- i18n:meta locale=fr source=README.md source-blob=ad78fdbbee096115a953813ed9a462e3393c5736 status=translated -->
4
4
  <!-- i18n:end -->
5
5
 
6
6
  <div align="center">
@@ -150,14 +150,16 @@ La comparaison complète — la même fonctionnalité dans les deux, d’autres
150
150
  - [Exemple](#exemple)
151
151
  - [Hook useUrlState pour React-Router](#hook-useurlstate-pour-react-router)
152
152
  - [Exemple](#exemple-1)
153
- - [Hook useUrlState pour Astro](#hook-useurlstate-pour-astro)
153
+ - [Hook useUrlState pour React (sans routeur)](#hook-useurlstate-pour-react-sans-routeur)
154
154
  - [Exemple](#exemple-2)
155
+ - [Hook useUrlState pour Astro](#hook-useurlstate-pour-astro)
156
+ - [Exemple](#exemple-3)
155
157
  - [Recettes](#recettes)
156
158
  - [Hook personnalisé pour travailler confortablement avec une tranche d'état](#hook-personnalisé-pour-travailler-confortablement-avec-une-tranche-détat)
157
159
  - [Avec une forme d'état complexe](#avec-une-forme-détat-complexe)
158
160
  - [Mettre à jour l'état seul et le synchroniser manuellement avec l'URL](#mettre-à-jour-létat-seul-et-le-synchroniser-manuellement-avec-lurl)
159
161
  - [Autres hooks et helpers](#autres-hooks-et-helpers)
160
- - [Hook `useUrlStateBase` pour d'autres routeurs](#hook-useurlstatebase-pour-dautres-routeurs)
162
+ - [Hook `useUrlStateBase` pour un autre routeur](#hook-useurlstatebase-pour-un-autre-routeur)
161
163
  - [Hook `useSharedState` pour React.js](#hook-usesharedstate-pour-reactjs)
162
164
  - [Hook `useLinkProps` pour React.js](#hook-uselinkprops-pour-reactjs)
163
165
  - [Hook `useUrlEncode` pour React.js](#hook-useurlencode-pour-reactjs)
@@ -540,6 +542,39 @@ const tags = [
540
542
 
541
543
  [Exemple de code](packages/example-react-router6/src/Form-for-test.tsx)
542
544
 
545
+ ### Hook useUrlState pour React (sans routeur)
546
+
547
+ Pour une application React sans routeur : Vite, Create React App, ou un widget monté dans une page que vous ne contrôlez pas. Le hook écrit l'URL via `window.history` et la relit lors des retours et avances dans l'historique ainsi qu'à chaque autre `pushState`/`replaceState`. Tous les composants qui utilisent le même objet d'état le partagent, sans rien à englober ni rien à faire transiter par les props.
548
+
549
+ [Documentation de l'API](packages/urlstate/react/useUrlState)
550
+
551
+ #### Exemple
552
+
553
+ ```typescript
554
+ // useFilters.ts
555
+ import { useUrlState } from 'state-in-url/react';
556
+
557
+ type FiltersState = { sort: 'name' | 'date'; page: number };
558
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
559
+
560
+ export function useFilters() {
561
+ return useUrlState(FILTERS_STATE);
562
+ }
563
+ ```
564
+
565
+ ```typescript
566
+ // FiltersBar.tsx
567
+ import { useFilters } from './useFilters';
568
+
569
+ export function FiltersBar() {
570
+ const { urlState, setUrl } = useFilters();
571
+
572
+ return <button onClick={() => setUrl({ page: urlState.page + 1 })}>Page {urlState.page}</button>;
573
+ }
574
+ ```
575
+
576
+ `state-in-url/astro` est ce même hook ; il est documenté séparément plus bas parce que les îlots reçoivent en plus `searchParams` sous forme de prop.
577
+
543
578
  ### Hook useUrlState pour Astro
544
579
 
545
580
  Pour les îlots React. Astro n'a pas de routeur côté client par défaut, donc le hook écrit l'URL avec `window.history` et la relit lors des navigations précédent/suivant et lors de tout autre `pushState`/`replaceState`, y compris le `<ClientRouter />` d'Astro. Les îlots d'une page partagent l'état, sans avoir à les envelopper dans quoi que ce soit.
@@ -818,9 +853,39 @@ Synchroniser l'état sur `onBlur` sera plus conforme à l'usage réel.
818
853
 
819
854
  ## Autres hooks et helpers
820
855
 
821
- ### Hook `useUrlStateBase` pour d'autres routeurs
856
+ ### Hook `useUrlStateBase` pour un autre routeur
857
+
858
+ Utilisez-le pour construire votre propre `useUrlState` destiné à un routeur pour lequel ce paquet ne publie pas de point d'entrée, par exemple TanStack Router. Passez n'importe quel objet mémoïsé possédant `push(url)` et `replace(url)`.
859
+
860
+ S'il n'y a **aucun routeur**, vous n'en avez pas besoin : utilisez [`state-in-url/react`](#hook-useurlstate-pour-react-sans-routeur), qui est ce même hook déjà relié à `window.history`.
861
+
862
+ ```typescript
863
+ import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
864
+
865
+ type FiltersState = { sort: 'name' | 'date'; page: number };
866
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
867
+
868
+ export function useFilters() {
869
+ const router = useYourRouter();
870
+ const nav = React.useMemo(
871
+ () => ({
872
+ push: (url: string) => router.navigate(url),
873
+ replace: (url: string) => router.navigate(url, { replace: true }),
874
+ }),
875
+ [router],
876
+ );
877
+
878
+ return useUrlStateBase(FILTERS_STATE, nav, ({ parse }) => parse(window.location.search));
879
+ }
880
+ ```
881
+
882
+ Deux différences avec `useUrlState` :
883
+
884
+ - Il renvoie `state`, `updateUrl`, `updateState`, et non `urlState`, `setUrl`, `setState` ; de plus `updateUrl` fait un push par défaut, là où `setUrl` fait un replace.
885
+ - Le troisième argument fournit le state initial. Si vous l'omettez, le hook ignore la chaîne de requête avec laquelle la page a été chargée, et un lien partagé s'ouvre donc sur les valeurs par défaut.
822
886
 
823
- Hooks pour créer vos propres hooks `useUrlState` avec d'autres routeurs, par exemple react-router ou tanstack router.
887
+ > [!NOTE]
888
+ > `useUrlState` n'est plus exporté depuis la racine du paquet : chacun est lié à un framework, et chacun vit donc derrière son propre point d'entrée (`state-in-url/next`, `/react`, `/react-router`, `/react-router6`, `/remix`, `/astro`). La racine ne conserve que ce qui est indépendant du framework : `useSharedState`, `useUrlEncode`, `useUrlStateBase`, `useLinkProps`, `encode`/`decode` et `encodeState`/`decodeState`.
824
889
 
825
890
  [Documentation de l'API](packages/urlstate/useUrlStateBase)
826
891
 
package/README.ja.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- i18n:start -->
2
2
  [English](./README.md) · [简体中文](./README.zh-CN.md) · 日本語 · [한국어](./README.ko.md) · [Русский](./README.ru.md) · [Español](./README.es.md) · [Português (BR)](./README.pt-BR.md) · [Français](./README.fr.md) · [Tiếng Việt](./README.vi.md)
3
- <!-- i18n:meta locale=ja source=README.md source-blob=4d98ba970e6aab8f29987fbcba29fb6c61c2fc67 status=translated -->
3
+ <!-- i18n:meta locale=ja source=README.md source-blob=ad78fdbbee096115a953813ed9a462e3393c5736 status=translated -->
4
4
  <!-- i18n:end -->
5
5
 
6
6
  <div align="center">
@@ -150,8 +150,10 @@ nuqs も優れたライブラリです。値ごとに読みやすいクエリパ
150
150
  - [例](#例)
151
151
  - [React-Router 向け useUrlState フック](#react-router-向け-useurlstate-フック)
152
152
  - [例](#例-1)
153
- - [Astro 向け useUrlState フック](#astro-向け-useurlstate-フック)
153
+ - [React 向け useUrlState フック(ルーターなし)](#react-向け-useurlstate-フックルーターなし)
154
154
  - [例](#例-2)
155
+ - [Astro 向け useUrlState フック](#astro-向け-useurlstate-フック)
156
+ - [例](#例-3)
155
157
  - [レシピ](#レシピ)
156
158
  - [状態の一部を便利に扱うカスタムフック](#状態の一部を便利に扱うカスタムフック)
157
159
  - [複雑な状態の形を使用](#複雑な状態の形を使用)
@@ -540,6 +542,39 @@ const tags = [
540
542
 
541
543
  [サンプルコード](packages/example-react-router6/src/Form-for-test.tsx)
542
544
 
545
+ ### React 向け useUrlState フック(ルーターなし)
546
+
547
+ ルーターを持たない React アプリ向けです。Vite、Create React App、あるいは自分では管理できないページに埋め込むウィジェットなどが対象です。このフックは `window.history` で URL を書き込み、戻る/進むや他の `pushState`/`replaceState` のたびに読み戻します。同じ state オブジェクトを使うコンポーネントはすべて状態を共有するため、ラップするものも props で渡すものもありません。
548
+
549
+ [API ドキュメント](packages/urlstate/react/useUrlState)
550
+
551
+ #### 例
552
+
553
+ ```typescript
554
+ // useFilters.ts
555
+ import { useUrlState } from 'state-in-url/react';
556
+
557
+ type FiltersState = { sort: 'name' | 'date'; page: number };
558
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
559
+
560
+ export function useFilters() {
561
+ return useUrlState(FILTERS_STATE);
562
+ }
563
+ ```
564
+
565
+ ```typescript
566
+ // FiltersBar.tsx
567
+ import { useFilters } from './useFilters';
568
+
569
+ export function FiltersBar() {
570
+ const { urlState, setUrl } = useFilters();
571
+
572
+ return <button onClick={() => setUrl({ page: urlState.page + 1 })}>Page {urlState.page}</button>;
573
+ }
574
+ ```
575
+
576
+ `state-in-url/astro` は同じフックです。islands では `searchParams` を prop として受け取るため、下で別に説明しています。
577
+
543
578
  ### Astro 向け useUrlState フック
544
579
 
545
580
  React アイランド向けです。Astro にはデフォルトでクライアントサイドルーターがないため、このフックは `window.history` で URL を書き込み、戻る/進む操作時およびその他あらゆる `pushState`/`replaceState` の際(Astro 自身の `<ClientRouter />` を含む)に URL を読み戻します。ページ上のアイランドは状態を共有し、それらをラップするものは何も必要ありません。
@@ -820,7 +855,37 @@ const tags = [
820
855
 
821
856
  ### 他のルーター向け `useUrlStateBase` フック
822
857
 
823
- react-router や tanstack router など、他のルーターで独自の `useUrlState` フックを作成するためのフックです。
858
+ 本パッケージがエントリーポイントを用意していないルーター(例: TanStack Router)向けに、自前の `useUrlState` を作るために使います。`push(url)` と `replace(url)` を持つメモ化されたオブジェクトを渡してください。
859
+
860
+ ルーターが**まったくない**場合は不要です。[`state-in-url/react`](#react-向け-useurlstate-フックルーターなし) を使ってください。こちらは同じフックを `window.history` に接続済みのものです。
861
+
862
+ ```typescript
863
+ import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
864
+
865
+ type FiltersState = { sort: 'name' | 'date'; page: number };
866
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
867
+
868
+ export function useFilters() {
869
+ const router = useYourRouter();
870
+ const nav = React.useMemo(
871
+ () => ({
872
+ push: (url: string) => router.navigate(url),
873
+ replace: (url: string) => router.navigate(url, { replace: true }),
874
+ }),
875
+ [router],
876
+ );
877
+
878
+ return useUrlStateBase(FILTERS_STATE, nav, ({ parse }) => parse(window.location.search));
879
+ }
880
+ ```
881
+
882
+ `useUrlState` との違いは 2 点です:
883
+
884
+ - 返すのは `urlState`、`setUrl`、`setState` ではなく `state`、`updateUrl`、`updateState` です。また `updateUrl` の既定は push で、`setUrl` の既定は replace です。
885
+ - 第 3 引数が初期 state を決めます。省略するとフックは読み込み時のクエリ文字列を無視するため、共有されたリンクを開いても既定値が表示されます。
886
+
887
+ > [!NOTE]
888
+ > `useUrlState` はパッケージのルートからはエクスポートされません。どの `useUrlState` もフレームワークに結び付いているため、それぞれ専用のエントリーポイント(`state-in-url/next`、`/react`、`/react-router`、`/react-router6`、`/remix`、`/astro`)にあります。ルートエントリーにはフレームワークに依存しないものだけが残ります: `useSharedState`、`useUrlEncode`、`useUrlStateBase`、`useLinkProps`、`encode`/`decode`、`encodeState`/`decodeState`。
824
889
 
825
890
  [API ドキュメント](packages/urlstate/useUrlStateBase)
826
891
 
package/README.ko.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- i18n:start -->
2
2
  [English](./README.md) · [简体中文](./README.zh-CN.md) · [日本語](./README.ja.md) · 한국어 · [Русский](./README.ru.md) · [Español](./README.es.md) · [Português (BR)](./README.pt-BR.md) · [Français](./README.fr.md) · [Tiếng Việt](./README.vi.md)
3
- <!-- i18n:meta locale=ko source=README.md source-blob=4d98ba970e6aab8f29987fbcba29fb6c61c2fc67 status=translated -->
3
+ <!-- i18n:meta locale=ko source=README.md source-blob=ad78fdbbee096115a953813ed9a462e3393c5736 status=translated -->
4
4
  <!-- i18n:end -->
5
5
 
6
6
  <div align="center">
@@ -150,8 +150,10 @@ nuqs도 훌륭한 라이브러리입니다. 값마다 읽기 쉬운 쿼리 파
150
150
  - [예제](#예제)
151
151
  - [React-Router용 useUrlState 훅](#react-router용-useurlstate-훅)
152
152
  - [예제](#예제-1)
153
- - [Astro용 useUrlState 훅](#astro용-useurlstate-훅)
153
+ - [React용 useUrlState 훅 (라우터 없음)](#react용-useurlstate-훅-라우터-없음)
154
154
  - [예제](#예제-2)
155
+ - [Astro용 useUrlState 훅](#astro용-useurlstate-훅)
156
+ - [예제](#예제-3)
155
157
  - [레시피](#레시피)
156
158
  - [상태의 일부를 편리하게 다루기 위한 커스텀 훅](#상태의-일부를-편리하게-다루기-위한-커스텀-훅)
157
159
  - [복잡한 상태 구조 사용](#복잡한-상태-구조-사용)
@@ -536,6 +538,39 @@ const tags = [
536
538
 
537
539
  [예제 코드](packages/example-react-router6/src/Form-for-test.tsx)
538
540
 
541
+ ### React용 useUrlState 훅 (라우터 없음)
542
+
543
+ 라우터가 없는 React 앱을 위한 것입니다. Vite, Create React App, 또는 직접 제어할 수 없는 페이지에 끼워 넣는 위젯이 여기에 해당합니다. 이 훅은 `window.history` 로 URL 을 쓰고, 뒤로/앞으로 이동할 때와 다른 코드가 `pushState`/`replaceState` 를 호출할 때 다시 읽어 옵니다. 같은 state 객체를 쓰는 모든 컴포넌트가 상태를 공유하므로, 감쌀 것도 props 로 넘길 것도 없습니다.
544
+
545
+ [API 문서](packages/urlstate/react/useUrlState)
546
+
547
+ #### 예제
548
+
549
+ ```typescript
550
+ // useFilters.ts
551
+ import { useUrlState } from 'state-in-url/react';
552
+
553
+ type FiltersState = { sort: 'name' | 'date'; page: number };
554
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
555
+
556
+ export function useFilters() {
557
+ return useUrlState(FILTERS_STATE);
558
+ }
559
+ ```
560
+
561
+ ```typescript
562
+ // FiltersBar.tsx
563
+ import { useFilters } from './useFilters';
564
+
565
+ export function FiltersBar() {
566
+ const { urlState, setUrl } = useFilters();
567
+
568
+ return <button onClick={() => setUrl({ page: urlState.page + 1 })}>Page {urlState.page}</button>;
569
+ }
570
+ ```
571
+
572
+ `state-in-url/astro` 는 바로 이 훅입니다. islands 는 `searchParams` 를 prop 으로도 받기 때문에 아래에서 따로 설명합니다.
573
+
539
574
  ### Astro용 useUrlState 훅
540
575
 
541
576
  React 아일랜드용입니다. Astro에는 기본적으로 클라이언트 측 라우터가 없으므로, 이 훅은 `window.history`로 URL을 쓰고, 뒤로/앞으로 이동과 그 외 모든 `pushState`/`replaceState` 시점에 (Astro 자체의 `<ClientRouter />` 포함) URL을 다시 읽어 옵니다. 한 페이지의 아일랜드들은 감싸는 것 없이 상태를 공유합니다.
@@ -816,7 +851,37 @@ const tags = [
816
851
 
817
852
  ### 다른 라우터용 `useUrlStateBase` 훅
818
853
 
819
- 다른 라우터(예: react-router 또는 tanstack router)와 함께 자체 `useUrlState` 훅을 만들기 위한 훅입니다.
854
+ 이 패키지가 진입점을 제공하지 않는 라우터(예: TanStack Router)를 위해 직접 `useUrlState` 를 만들 때 사용합니다. `push(url)` 과 `replace(url)` 을 가진 메모이즈된 객체를 넘기면 됩니다.
855
+
856
+ 라우터가 **전혀 없다면** 이것은 필요 없습니다. 이미 `window.history` 에 연결된 같은 훅인 [`state-in-url/react`](#react용-useurlstate-훅-라우터-없음) 를 쓰세요.
857
+
858
+ ```typescript
859
+ import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
860
+
861
+ type FiltersState = { sort: 'name' | 'date'; page: number };
862
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
863
+
864
+ export function useFilters() {
865
+ const router = useYourRouter();
866
+ const nav = React.useMemo(
867
+ () => ({
868
+ push: (url: string) => router.navigate(url),
869
+ replace: (url: string) => router.navigate(url, { replace: true }),
870
+ }),
871
+ [router],
872
+ );
873
+
874
+ return useUrlStateBase(FILTERS_STATE, nav, ({ parse }) => parse(window.location.search));
875
+ }
876
+ ```
877
+
878
+ `useUrlState` 와 다른 점은 두 가지입니다:
879
+
880
+ - `urlState`, `setUrl`, `setState` 가 아니라 `state`, `updateUrl`, `updateState` 를 반환하며, `updateUrl` 의 기본값은 push, `setUrl` 의 기본값은 replace 입니다.
881
+ - 세 번째 인자가 초기 state 를 채웁니다. 이를 생략하면 훅이 페이지가 로드된 시점의 쿼리 문자열을 무시하므로, 공유된 링크를 열어도 기본값만 보입니다.
882
+
883
+ > [!NOTE]
884
+ > `useUrlState` 는 패키지 루트에서 내보내지 않습니다. 모든 `useUrlState` 가 특정 프레임워크에 묶여 있어 각자 자신의 진입점(`state-in-url/next`, `/react`, `/react-router`, `/react-router6`, `/remix`, `/astro`)에 있습니다. 루트 진입점에는 프레임워크와 무관한 것만 남습니다: `useSharedState`, `useUrlEncode`, `useUrlStateBase`, `useLinkProps`, `encode`/`decode`, `encodeState`/`decodeState`.
820
885
 
821
886
  [API 문서](packages/urlstate/useUrlStateBase)
822
887
 
package/README.md CHANGED
@@ -149,14 +149,16 @@ The full comparison — the same feature built in both, other alternatives (TanS
149
149
  - [Example](#example)
150
150
  - [useUrlState hook for React-Router](#useurlstate-hook-for-react-router)
151
151
  - [Example](#example-1)
152
- - [useUrlState hook for Astro](#useurlstate-hook-for-astro)
152
+ - [useUrlState hook for React (no router)](#useurlstate-hook-for-react-no-router)
153
153
  - [Example](#example-2)
154
+ - [useUrlState hook for Astro](#useurlstate-hook-for-astro)
155
+ - [Example](#example-3)
154
156
  - [Recipes](#recipes)
155
157
  - [Custom hook to work with slice of state conveniently](#custom-hook-to-work-with-slice-of-state-conveniently)
156
158
  - [With complex state shape](#with-complex-state-shape)
157
159
  - [Update state only and sync to URL manually](#update-state-only-and-sync-to-url-manually)
158
160
  - [Other hooks and helpers](#other-hooks-and-helpers)
159
- - [`useUrlStateBase` hook for others routers](#useurlstatebase-hook-for-others-routers)
161
+ - [`useUrlStateBase` hook for another router](#useurlstatebase-hook-for-another-router)
160
162
  - [`useSharedState` hook for React.js](#usesharedstate-hook-for-reactjs)
161
163
  - [`useLinkProps` hook for React.js](#uselinkprops-hook-for-reactjs)
162
164
  - [`useUrlEncode` hook for React.js](#useurlencode-hook-for-reactjs)
@@ -539,6 +541,39 @@ const tags = [
539
541
 
540
542
  [Example code](packages/example-react-router6/src/Form-for-test.tsx)
541
543
 
544
+ ### useUrlState hook for React (no router)
545
+
546
+ For a React app with no router — Vite, Create React App, a widget mounted into a page you do not control. The hook writes the URL with `window.history` and reads it back on back/forward and on any other `pushState`/`replaceState`. Every component using the same state object shares it, with nothing to wrap them in and nothing to pass through props.
547
+
548
+ [API Docs](packages/urlstate/react/useUrlState)
549
+
550
+ #### Example
551
+
552
+ ```typescript
553
+ // useFilters.ts
554
+ import { useUrlState } from 'state-in-url/react';
555
+
556
+ type FiltersState = { sort: 'name' | 'date'; page: number };
557
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
558
+
559
+ export function useFilters() {
560
+ return useUrlState(FILTERS_STATE);
561
+ }
562
+ ```
563
+
564
+ ```typescript
565
+ // FiltersBar.tsx
566
+ import { useFilters } from './useFilters';
567
+
568
+ export function FiltersBar() {
569
+ const { urlState, setUrl } = useFilters();
570
+
571
+ return <button onClick={() => setUrl({ page: urlState.page + 1 })}>Page {urlState.page}</button>;
572
+ }
573
+ ```
574
+
575
+ `state-in-url/astro` is this same hook; it is documented separately below because islands also take `searchParams` as a prop.
576
+
542
577
  ### useUrlState hook for Astro
543
578
 
544
579
  For React islands. Astro has no client-side router by default, so the hook writes the URL with `window.history` and reads it back on back/forward and on any other `pushState`/`replaceState`, Astro's own `<ClientRouter />` included. Islands on a page share the state, with nothing to wrap them in.
@@ -817,9 +852,39 @@ Syncing state `onBlur` will be more aligned with real world usage.
817
852
 
818
853
  ## Other hooks and helpers
819
854
 
820
- ### `useUrlStateBase` hook for others routers
855
+ ### `useUrlStateBase` hook for another router
856
+
857
+ Use this to build your own `useUrlState` for a router this package ships no entry point for, e.g. TanStack Router. Pass any memoized object with `push(url)` and `replace(url)`.
858
+
859
+ With **no router at all**, you do not need this — use [`state-in-url/react`](#useurlstate-hook-for-react-no-router), which is this hook already wired to `window.history`.
860
+
861
+ ```typescript
862
+ import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
863
+
864
+ type FiltersState = { sort: 'name' | 'date'; page: number };
865
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
866
+
867
+ export function useFilters() {
868
+ const router = useYourRouter();
869
+ const nav = React.useMemo(
870
+ () => ({
871
+ push: (url: string) => router.navigate(url),
872
+ replace: (url: string) => router.navigate(url, { replace: true }),
873
+ }),
874
+ [router],
875
+ );
876
+
877
+ return useUrlStateBase(FILTERS_STATE, nav, ({ parse }) => parse(window.location.search));
878
+ }
879
+ ```
880
+
881
+ Two differences from `useUrlState`:
882
+
883
+ - It returns `state`, `updateUrl`, `updateState` — not `urlState`, `setUrl`, `setState` — and `updateUrl` defaults to push, where `setUrl` defaults to replace.
884
+ - The third argument seeds the initial state. Leave it out and the hook ignores the query string it loaded with, so a shared link opens with defaults.
821
885
 
822
- Hooks to create your own `useUrlState` hooks with other routers, e.g. react-router or tanstack router.
886
+ > [!NOTE]
887
+ > `useUrlState` is not exported from the package root — every one of them is tied to a framework, so each lives behind its own entry point (`state-in-url/next`, `/react`, `/react-router`, `/react-router6`, `/remix`, `/astro`). The root entry carries only what is framework-agnostic: `useSharedState`, `useUrlEncode`, `useUrlStateBase`, `useLinkProps`, `encode`/`decode` and `encodeState`/`decodeState`.
823
888
 
824
889
  [API Docs](packages/urlstate/useUrlStateBase)
825
890
 
package/README.pt-BR.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- i18n:start -->
2
2
  [English](./README.md) · [简体中文](./README.zh-CN.md) · [日本語](./README.ja.md) · [한국어](./README.ko.md) · [Русский](./README.ru.md) · [Español](./README.es.md) · Português (BR) · [Français](./README.fr.md) · [Tiếng Việt](./README.vi.md)
3
- <!-- i18n:meta locale=pt-BR source=README.md source-blob=4d98ba970e6aab8f29987fbcba29fb6c61c2fc67 status=translated -->
3
+ <!-- i18n:meta locale=pt-BR source=README.md source-blob=ad78fdbbee096115a953813ed9a462e3393c5736 status=translated -->
4
4
  <!-- i18n:end -->
5
5
 
6
6
  <div align="center">
@@ -150,14 +150,16 @@ A comparação completa — a mesma feature nas duas, outras alternativas (TanSt
150
150
  - [Exemplo](#exemplo)
151
151
  - [Hook useUrlState para React-Router](#hook-useurlstate-para-react-router)
152
152
  - [Exemplo](#exemplo-1)
153
- - [Hook useUrlState para Astro](#hook-useurlstate-para-astro)
153
+ - [Hook useUrlState para React (sem router)](#hook-useurlstate-para-react-sem-router)
154
154
  - [Exemplo](#exemplo-2)
155
+ - [Hook useUrlState para Astro](#hook-useurlstate-para-astro)
156
+ - [Exemplo](#exemplo-3)
155
157
  - [Receitas](#receitas)
156
158
  - [Hook personalizado para trabalhar convenientemente com uma fatia do estado](#hook-personalizado-para-trabalhar-convenientemente-com-uma-fatia-do-estado)
157
159
  - [Com forma de estado complexa](#com-forma-de-estado-complexa)
158
160
  - [Atualizar apenas o estado e sincronizar com a URL manualmente](#atualizar-apenas-o-estado-e-sincronizar-com-a-url-manualmente)
159
161
  - [Outros hooks e helpers](#outros-hooks-e-helpers)
160
- - [Hook `useUrlStateBase` para outros routers](#hook-useurlstatebase-para-outros-routers)
162
+ - [Hook `useUrlStateBase` para outro router](#hook-useurlstatebase-para-outro-router)
161
163
  - [Hook `useSharedState` para React.js](#hook-usesharedstate-para-reactjs)
162
164
  - [Hook `useLinkProps` para React.js](#hook-uselinkprops-para-reactjs)
163
165
  - [Hook `useUrlEncode` para React.js](#hook-useurlencode-para-reactjs)
@@ -540,6 +542,39 @@ const tags = [
540
542
 
541
543
  [Exemplo de código](packages/example-react-router6/src/Form-for-test.tsx)
542
544
 
545
+ ### Hook useUrlState para React (sem router)
546
+
547
+ Para uma aplicação React sem router: Vite, Create React App, ou um widget montado em uma página que você não controla. O hook escreve a URL com `window.history` e a lê de volta ao navegar para trás e para frente e a cada outro `pushState`/`replaceState`. Todos os componentes que usam o mesmo objeto de estado o compartilham, sem nada para envolver e sem nada para passar por props.
548
+
549
+ [Documentação da API](packages/urlstate/react/useUrlState)
550
+
551
+ #### Exemplo
552
+
553
+ ```typescript
554
+ // useFilters.ts
555
+ import { useUrlState } from 'state-in-url/react';
556
+
557
+ type FiltersState = { sort: 'name' | 'date'; page: number };
558
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
559
+
560
+ export function useFilters() {
561
+ return useUrlState(FILTERS_STATE);
562
+ }
563
+ ```
564
+
565
+ ```typescript
566
+ // FiltersBar.tsx
567
+ import { useFilters } from './useFilters';
568
+
569
+ export function FiltersBar() {
570
+ const { urlState, setUrl } = useFilters();
571
+
572
+ return <button onClick={() => setUrl({ page: urlState.page + 1 })}>Page {urlState.page}</button>;
573
+ }
574
+ ```
575
+
576
+ `state-in-url/astro` é este mesmo hook; ele é documentado à parte abaixo porque as islands também recebem `searchParams` como prop.
577
+
543
578
  ### Hook useUrlState para Astro
544
579
 
545
580
  Para ilhas React. O Astro não tem um router no lado do cliente por padrão, então o hook escreve a URL com `window.history` e a lê de volta ao navegar para trás/para frente e em qualquer outro `pushState`/`replaceState`, incluindo o próprio `<ClientRouter />` do Astro. As ilhas de uma página compartilham o estado, sem precisar envolvê-las em nada.
@@ -818,9 +853,39 @@ Sincronizar o estado em `onBlur` estará mais alinhado com o uso no mundo real.
818
853
 
819
854
  ## Outros hooks e helpers
820
855
 
821
- ### Hook `useUrlStateBase` para outros routers
856
+ ### Hook `useUrlStateBase` para outro router
857
+
858
+ Use-o para construir seu próprio `useUrlState` para um router do qual este pacote não publica um ponto de entrada, por exemplo TanStack Router. Passe qualquer objeto memoizado com `push(url)` e `replace(url)`.
859
+
860
+ Se **não houver router algum**, você não precisa disso — use [`state-in-url/react`](#hook-useurlstate-para-react-sem-router), que é este mesmo hook já ligado ao `window.history`.
861
+
862
+ ```typescript
863
+ import { useUrlStateBase } from 'state-in-url/useUrlStateBase';
864
+
865
+ type FiltersState = { sort: 'name' | 'date'; page: number };
866
+ const FILTERS_STATE: FiltersState = { sort: 'name', page: 1 };
867
+
868
+ export function useFilters() {
869
+ const router = useYourRouter();
870
+ const nav = React.useMemo(
871
+ () => ({
872
+ push: (url: string) => router.navigate(url),
873
+ replace: (url: string) => router.navigate(url, { replace: true }),
874
+ }),
875
+ [router],
876
+ );
877
+
878
+ return useUrlStateBase(FILTERS_STATE, nav, ({ parse }) => parse(window.location.search));
879
+ }
880
+ ```
881
+
882
+ Duas diferenças em relação ao `useUrlState`:
883
+
884
+ - Ele retorna `state`, `updateUrl` e `updateState`, e não `urlState`, `setUrl` e `setState`; além disso `updateUrl` faz push por padrão, enquanto `setUrl` faz replace.
885
+ - O terceiro argumento define o state inicial. Se você omiti-lo, o hook ignora a query string com que a página foi carregada, então um link compartilhado abre com os valores padrão.
822
886
 
823
- Hooks para criar seus próprios hooks `useUrlState` com outros routers, por exemplo react-router ou tanstack router.
887
+ > [!NOTE]
888
+ > `useUrlState` não é mais exportado da raiz do pacote: cada um está preso a um framework, então cada um fica em seu próprio ponto de entrada (`state-in-url/next`, `/react`, `/react-router`, `/react-router6`, `/remix`, `/astro`). A raiz mantém apenas o que independe de framework: `useSharedState`, `useUrlEncode`, `useUrlStateBase`, `useLinkProps`, `encode`/`decode` e `encodeState`/`decodeState`.
824
889
 
825
890
  [Documentação da API](packages/urlstate/useUrlStateBase)
826
891