@shane_donnelly/dsi-internal-react-utils 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,31 +32,15 @@ Wrapper de simplification pour `keycloak-js`. `KeycloakProvider` singleton à la
32
32
 
33
33
  ---
34
34
 
35
- ## Exemple complet avec React Router
35
+ ## Exemple complet avec React Router v7 (framework mode)
36
36
 
37
- ```tsx
38
- // main.tsx
39
- import React from 'react';
40
- import ReactDOM from 'react-dom/client';
41
- import { BrowserRouter } from 'react-router-dom';
42
- import '@shane_donnelly/dsi-internal-react-utils/style.css';
43
- import App from './App';
44
-
45
- ReactDOM.createRoot(document.getElementById('root')!).render(
46
- <React.StrictMode>
47
- <BrowserRouter>
48
- <App />
49
- </BrowserRouter>
50
- </React.StrictMode>,
51
- );
52
- ```
37
+ React Router v7 framework mode utilise `app/root.tsx` comme layout racine — c'est là que le `KeycloakProvider` doit être placé.
53
38
 
54
39
  ```tsx
55
- // App.tsx
56
- import { Routes, Route } from 'react-router-dom';
40
+ // app/root.tsx
41
+ import { Outlet } from 'react-router';
57
42
  import { KeycloakProvider } from '@shane_donnelly/dsi-internal-react-utils';
58
- import PublicPage from './pages/PublicPage';
59
- import Dashboard from './pages/Dashboard';
43
+ import '@shane_donnelly/dsi-internal-react-utils/style.css';
60
44
 
61
45
  const keycloakConfig = {
62
46
  url: 'https://keycloak.example.com',
@@ -64,27 +48,22 @@ const keycloakConfig = {
64
48
  clientId: 'my-frontend',
65
49
  };
66
50
 
67
- export default function App() {
51
+ export default function Root() {
68
52
  return (
69
53
  <KeycloakProvider config={keycloakConfig} idpHint="oidc" refreshInterval={300}>
70
- <Routes>
71
- <Route path="/" element={<PublicPage />} />
72
- <Route path="/dashboard" element={<Dashboard />} />
73
- </Routes>
54
+ <Outlet />
74
55
  </KeycloakProvider>
75
56
  );
76
57
  }
77
58
  ```
78
59
 
79
60
  ```tsx
80
- // pages/Dashboard.tsx
61
+ // app/routes/profile.tsx
81
62
  import { useEffect } from 'react';
82
- import { useNavigate } from 'react-router-dom';
83
63
  import { useKeycloakAuth } from '@shane_donnelly/dsi-internal-react-utils';
84
64
 
85
- export default function Dashboard() {
86
- const { isAuthenticated, status, user, login, logout } = useKeycloakAuth();
87
- const navigate = useNavigate();
65
+ export default function Profile() {
66
+ const { status, user, login, logout } = useKeycloakAuth();
88
67
 
89
68
  useEffect(() => {
90
69
  if (status === 'unauthenticated') {
@@ -99,7 +78,6 @@ export default function Dashboard() {
99
78
  <div>
100
79
  <h1>Bienvenue {user?.name}</h1>
101
80
  <p>Email : {user?.email}</p>
102
- {/* Déconnexion avec redirection KC vers l'accueil */}
103
81
  <button onClick={() => logout({ redirectUri: window.location.origin })}>
104
82
  Se déconnecter
105
83
  </button>
@@ -4,68 +4,70 @@ import { jsx as c } from "react/jsx-runtime";
4
4
  //#region lib/keycloak/react/KeycloakProvider/index.tsx
5
5
  var l = r(null);
6
6
  function u({ config: r, children: u, idpHint: d, refreshInterval: f = 300, minTokenValidity: p = 30, onAuthError: m }) {
7
- let [h, g] = s("loading"), [_, v] = s(null), [y, b] = s(null), x = o(null), S = o(!1), C = i((e) => {
7
+ let [h, g] = s("loading"), [_, v] = s(null), [y, b] = s(null), x = o(null), S = o(!1), C = o(d), w = i((e) => {
8
8
  e.authenticated && e.token ? (v(e.token), b(n(e)), g("authenticated")) : (v(null), b(null), g("unauthenticated"));
9
- }, []), w = i(async (e) => {
10
- m === "login" ? await x.current?.login({ idpHint: d }) : m === "logout" ? await x.current?.logout({ redirectUri: window.location.origin }) : typeof m == "function" && m(e);
11
- }, [m, d]), T = i(async () => {
9
+ }, []), T = i(async (e) => {
10
+ m === "logout" ? await x.current?.logout({ redirectUri: window.location.origin }) : typeof m == "function" ? m(e) : await x.current?.login({ idpHint: C.current });
11
+ }, [m, d]), E = i(async () => {
12
12
  let e = x.current;
13
13
  if (!e) return !1;
14
14
  try {
15
- return await e.updateToken(p) && C(e), !0;
15
+ return await e.updateToken(p) && w(e), !0;
16
16
  } catch (e) {
17
- return console.warn("[dsi-keycloak] Token refresh failed:", e), await w(e), !1;
17
+ return console.warn("[dsi-keycloak] Token refresh failed:", e), await T(e), !1;
18
18
  }
19
19
  }, [
20
20
  p,
21
- C,
22
- w
21
+ w,
22
+ T
23
23
  ]);
24
24
  a(() => {
25
25
  if (S.current) return;
26
26
  S.current = !0;
27
27
  let n = e(r);
28
28
  x.current = n, t(n).then((e) => {
29
- C(n), e || g("unauthenticated");
29
+ w(n), e || g("unauthenticated");
30
30
  }).catch((e) => {
31
31
  console.error("[dsi-keycloak] Init error:", e), g("error");
32
32
  });
33
33
  }, []), a(() => {
34
34
  if (h !== "authenticated") return;
35
35
  let e = window.setInterval(() => {
36
- T();
36
+ E();
37
37
  }, f * 1e3), t = () => {
38
- document.visibilityState === "visible" && T();
39
- };
40
- return document.addEventListener("visibilitychange", t), () => {
41
- clearInterval(e), document.removeEventListener("visibilitychange", t);
38
+ document.visibilityState === "visible" && E();
39
+ }, n = () => E(), r = () => E();
40
+ return document.addEventListener("visibilitychange", t), window.addEventListener("focus", n), window.addEventListener("online", r), () => {
41
+ clearInterval(e), document.removeEventListener("visibilitychange", t), window.removeEventListener("focus", n), window.removeEventListener("online", r);
42
42
  };
43
43
  }, [
44
44
  h,
45
45
  f,
46
- T
46
+ E
47
47
  ]);
48
- let E = i(async (e) => {
48
+ let D = i(async (e) => {
49
49
  let t = x.current;
50
- t && await t.login({
51
- idpHint: e?.idpHint ?? d,
50
+ if (!t) return;
51
+ let n = e?.idpHint ?? d;
52
+ C.current = n, await t.login({
53
+ idpHint: n,
52
54
  redirectUri: e?.redirectUri
53
55
  });
54
- }, [d]), D = i(async (e) => {
56
+ }, [d]), O = i(async (e) => {
55
57
  let t = x.current;
56
58
  t && await t.logout({ redirectUri: e?.redirectUri ?? window.location.origin });
57
- }, []), O = {
59
+ }, []), k = {
58
60
  status: h,
59
61
  token: _,
60
62
  user: y,
61
63
  isAuthenticated: h === "authenticated",
62
64
  keycloak: x.current,
63
- login: E,
64
- logout: D,
65
- refreshToken: T
65
+ login: D,
66
+ logout: O,
67
+ refreshToken: E
66
68
  };
67
69
  return /* @__PURE__ */ c(l.Provider, {
68
- value: O,
70
+ value: k,
69
71
  children: u
70
72
  });
71
73
  }
@@ -25,14 +25,13 @@ import { AuthContextValue } from '../../core/types';
25
25
  * }
26
26
  * ```
27
27
  *
28
- * @example Déconnexion avec navigation React Router
28
+ * @example Déconnexion
29
29
  * ```tsx
30
30
  * function LogoutButton() {
31
31
  * const { logout } = useKeycloakAuth();
32
- * const navigate = useNavigate();
33
32
  *
34
33
  * return (
35
- * <button onClick={() => logout({ onSuccess: () => navigate('/') })}>
34
+ * <button onClick={() => logout()}>
36
35
  * Se déconnecter
37
36
  * </button>
38
37
  * );
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shane_donnelly/dsi-internal-react-utils",
3
3
  "private": false,
4
- "version": "0.1.4",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",