@djangocfg/ui-core 2.1.441 → 2.1.443

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-core",
3
- "version": "2.1.441",
3
+ "version": "2.1.443",
4
4
  "description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
5
5
  "keywords": [
6
6
  "ui-components",
@@ -53,6 +53,16 @@
53
53
  "import": "./src/hooks/router/adapters/nextjs.tsx",
54
54
  "require": "./src/hooks/router/adapters/nextjs.tsx"
55
55
  },
56
+ "./adapters/react-router": {
57
+ "types": "./src/hooks/router/adapters/react-router.tsx",
58
+ "import": "./src/hooks/router/adapters/react-router.tsx",
59
+ "require": "./src/hooks/router/adapters/react-router.tsx"
60
+ },
61
+ "./chart": {
62
+ "types": "./src/components/data/chart/index.tsx",
63
+ "import": "./src/components/data/chart/index.tsx",
64
+ "require": "./src/components/data/chart/index.tsx"
65
+ },
56
66
  "./lib": {
57
67
  "types": "./src/lib/index.ts",
58
68
  "import": "./src/lib/index.ts",
@@ -106,7 +116,7 @@
106
116
  "check": "tsc --noEmit"
107
117
  },
108
118
  "peerDependencies": {
109
- "@djangocfg/i18n": "^2.1.441",
119
+ "@djangocfg/i18n": "^2.1.443",
110
120
  "consola": "^3.4.2",
111
121
  "lucide-react": "^0.545.0",
112
122
  "moment": "^2.30.1",
@@ -115,6 +125,7 @@
115
125
  "react-device-detect": "^2.2.3",
116
126
  "react-dom": "^19.2.4",
117
127
  "react-hook-form": "^7.69.0",
128
+ "react-router": ">=7",
118
129
  "tailwindcss": "^4.1.18",
119
130
  "zod": "^4.3.6",
120
131
  "zustand": "^5.0.0"
@@ -122,6 +133,9 @@
122
133
  "peerDependenciesMeta": {
123
134
  "next": {
124
135
  "optional": true
136
+ },
137
+ "react-router": {
138
+ "optional": true
125
139
  }
126
140
  },
127
141
  "dependencies": {
@@ -180,8 +194,8 @@
180
194
  "@chenglou/pretext": "*"
181
195
  },
182
196
  "devDependencies": {
183
- "@djangocfg/i18n": "^2.1.441",
184
- "@djangocfg/typescript-config": "^2.1.441",
197
+ "@djangocfg/i18n": "^2.1.443",
198
+ "@djangocfg/typescript-config": "^2.1.443",
185
199
  "@types/node": "^25.2.3",
186
200
  "@types/react": "^19.2.15",
187
201
  "@types/react-dom": "^19.2.3",
@@ -199,7 +199,13 @@ export type { BalancedTextProps, BalancedFont } from './data/BalancedText';
199
199
  // ─────────────────────────────────────────────────────────────────────────────
200
200
  // Chart Components
201
201
  // ─────────────────────────────────────────────────────────────────────────────
202
- export { ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle } from './data/chart';
202
+ // Charts are NOT re-exported from this main barrel ON PURPOSE: they pull in the
203
+ // heavy `recharts` dependency (which imports CJS `lodash/get`), and dragging
204
+ // that into every `import { Button } from "@djangocfg/ui-core"` both bloats the
205
+ // graph and breaks Vite dev (native-ESM) CJS-interop on consumers that never use
206
+ // charts. Import charts from the dedicated subpath instead — same pay-for-what-
207
+ // you-use pattern as `@djangocfg/ui-core/lib/dialog-service`:
208
+ // import { ChartContainer, ChartTooltip, … } from "@djangocfg/ui-core/chart";
203
209
 
204
210
  // ─────────────────────────────────────────────────────────────────────────────
205
211
  // Feedback
@@ -47,7 +47,30 @@ import { NextRouterAdapter, NextLinkProvider } from '@djangocfg/ui-core/adapters
47
47
  > Using `@djangocfg/layouts`? `BaseApp` already mounts both adapters — you don't
48
48
  > need this manual wiring.
49
49
 
50
- `next` is an **optional peer dependency** the package never imports from `next/*` from the main entry. The Next adapter lives behind the `/adapters/nextjs` sub-path entry, so non-Next consumers don't pull `next` into their bundle.
50
+ For a **React-Router v7** SPA (Vite / CRA) mount the React-Router adapter once,
51
+ **inside** the router context (e.g. in the layout-route element, not around
52
+ `<RouterProvider>`). It bridges the router hooks to `useNavigate` and `<Link>` to
53
+ React-Router's `<Link>`, so ui-core navigation drives the data router instead of
54
+ the bare-`pushState` fallback (which would desync the router):
55
+
56
+ ```tsx
57
+ // the layout-route element (rendered inside <RouterProvider>)
58
+ import { ReactRouterProvider } from '@djangocfg/ui-core/adapters/react-router';
59
+
60
+ <ReactRouterProvider>
61
+ {/* sidebar / top-bar / <Outlet/> */}
62
+ </ReactRouterProvider>
63
+ ```
64
+
65
+ `ReactRouterProvider` composes `ReactRouterAdapter` (router hooks) +
66
+ `ReactRouterLinkProvider` (`<Link>`); mount either individually if you only need
67
+ one. RR's `<Link>` has no `prefetch`-boolean / `scroll` prop, so those ui-core
68
+ `<Link>` props are ignored by this adapter (by design).
69
+
70
+ Both `next` and `react-router` are **optional peer dependencies** — the package
71
+ never imports from `next/*` or `react-router` from the main entry. Each adapter
72
+ lives behind its own sub-path (`/adapters/nextjs`, `/adapters/react-router`), so a
73
+ consumer only pulls in the framework it actually mounts.
51
74
 
52
75
  For other routers (TanStack Router, wouter, Remix, custom transports) — write a ~20-line custom adapter:
53
76
 
@@ -0,0 +1,149 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * React-Router (v7) adapter — bridges our framework-agnostic router hooks
5
+ * to `react-router` so SPA navigations flow through the data router
6
+ * (`createBrowserRouter`) instead of the bare History API fallback.
7
+ *
8
+ * USAGE:
9
+ * Mount once INSIDE the router context — i.e. inside an element that
10
+ * `RouterProvider` renders (a layout-route element / `<Outlet/>` parent),
11
+ * NOT around `<RouterProvider>` itself (that subtree has no router context,
12
+ * so `useNavigate` would throw):
13
+ *
14
+ * ```tsx
15
+ * import { ReactRouterProvider } from '@djangocfg/ui-core/adapters/react-router';
16
+ *
17
+ * function Shell() {
18
+ * return (
19
+ * <ReactRouterProvider>
20
+ * <Layout><Outlet /></Layout>
21
+ * </ReactRouterProvider>
22
+ * );
23
+ * }
24
+ * ```
25
+ *
26
+ * Without this provider, our hooks fall back to the History API adapter —
27
+ * which mutates `window.history` directly and bypasses React-Router's
28
+ * `<Outlet/>` swap, so programmatic `useNavigate` / `<Link>` clicks desync
29
+ * from the router. Mount it in any Vite / React-Router SPA.
30
+ *
31
+ * PEER DEPENDENCY:
32
+ * `react-router` is an OPTIONAL peer of @djangocfg/ui-core. The base package
33
+ * never imports from `react-router`. This sub-path entry does — so it only
34
+ * loads when the consumer explicitly imports `/adapters/react-router`.
35
+ * Next.js / non-RR consumers: don't import this file and `react-router` is
36
+ * never resolved.
37
+ */
38
+
39
+ import { forwardRef, useMemo, type ReactNode } from 'react';
40
+ import { Link as RouterLink, useNavigate } from 'react-router';
41
+
42
+ import {
43
+ RouterAdapterProvider,
44
+ type RouterAdapter,
45
+ type RouterLocation,
46
+ } from '../adapter';
47
+ import {
48
+ LinkProvider,
49
+ type LinkComponent,
50
+ type LinkComponentProps,
51
+ } from '../../../components/navigation/link';
52
+
53
+ const SSR_LOCATION: RouterLocation = Object.freeze({
54
+ pathname: '/',
55
+ search: '',
56
+ hash: '',
57
+ });
58
+
59
+ export interface ReactRouterAdapterProps {
60
+ children: ReactNode;
61
+ }
62
+
63
+ /**
64
+ * Wraps a subtree so all `@djangocfg/ui-core/hooks` router calls go through
65
+ * React-Router's data router. `back`/`forward` use the numeric-delta overload
66
+ * of `useNavigate`; `getLocation` reads `window.location` (SSR-guarded).
67
+ *
68
+ * Must be rendered inside the router context (under `RouterProvider`), since
69
+ * `useNavigate` requires it.
70
+ */
71
+ export function ReactRouterAdapter({ children }: ReactRouterAdapterProps) {
72
+ const navigate = useNavigate();
73
+
74
+ const adapter = useMemo<RouterAdapter>(
75
+ () => ({
76
+ push(url) {
77
+ navigate(url);
78
+ },
79
+ replace(url) {
80
+ navigate(url, { replace: true });
81
+ },
82
+ back() {
83
+ navigate(-1);
84
+ },
85
+ forward() {
86
+ navigate(1);
87
+ },
88
+ getLocation() {
89
+ if (typeof window === 'undefined') return SSR_LOCATION;
90
+ return {
91
+ pathname: window.location.pathname,
92
+ search: window.location.search,
93
+ hash: window.location.hash,
94
+ };
95
+ },
96
+ }),
97
+ [navigate]
98
+ );
99
+
100
+ return (
101
+ <RouterAdapterProvider value={adapter}>{children}</RouterAdapterProvider>
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Maps our agnostic Link API → react-router `<Link>` props. Lives at module
107
+ * scope so the component identity is stable (avoids tree remounts on every
108
+ * render). `href` → `to`; `replace` is forwarded; `prefetch` (a Next-shaped
109
+ * boolean) and `scroll` have no `react-router` equivalent and are dropped.
110
+ */
111
+ const ReactRouterLinkAdapter: LinkComponent = forwardRef<HTMLAnchorElement, LinkComponentProps>(
112
+ function ReactRouterLinkAdapter({ href, replace, scroll: _scroll, prefetch: _prefetch, children, ...rest }, ref) {
113
+ return (
114
+ <RouterLink to={href} replace={replace} ref={ref} {...rest}>
115
+ {children}
116
+ </RouterLink>
117
+ );
118
+ }
119
+ );
120
+
121
+ export interface ReactRouterLinkProviderProps {
122
+ children: ReactNode;
123
+ }
124
+
125
+ /**
126
+ * Wires `<Link>` from `@djangocfg/ui-core/components` to react-router's
127
+ * `<Link>`. Mount alongside `ReactRouterAdapter` (inside the router context)
128
+ * so every ui-core `<Link>` drives client-side routing.
129
+ */
130
+ export function ReactRouterLinkProvider({ children }: ReactRouterLinkProviderProps) {
131
+ return <LinkProvider value={ReactRouterLinkAdapter}>{children}</LinkProvider>;
132
+ }
133
+
134
+ export interface ReactRouterProviderProps {
135
+ children: ReactNode;
136
+ }
137
+
138
+ /**
139
+ * Convenience composition of `ReactRouterAdapter` (navigation backend) and
140
+ * `ReactRouterLinkProvider` (link component) — mount this ONE component inside
141
+ * the router context to wire ui-core's whole navigation seam to React-Router.
142
+ */
143
+ export function ReactRouterProvider({ children }: ReactRouterProviderProps) {
144
+ return (
145
+ <ReactRouterAdapter>
146
+ <ReactRouterLinkProvider>{children}</ReactRouterLinkProvider>
147
+ </ReactRouterAdapter>
148
+ );
149
+ }