@fanee/react 0.6.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 ADDED
@@ -0,0 +1,79 @@
1
+ # @fanee/react
2
+
3
+ React bindings for Fanee.
4
+
5
+ Provides a Context-based provider and hooks to consume a `FaneeRuntime` from `@fanee/core` inside a React component tree.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @fanee/core @fanee/react
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```tsx
16
+ import { FaneeRuntime } from "@fanee/core";
17
+ import { FaneeProvider, useT, useLocale, useSetLocale } from "@fanee/react";
18
+
19
+ const runtime = new FaneeRuntime().config({
20
+ defaultLocale: "en",
21
+ currentLocale: "en",
22
+ resources: {
23
+ "": {
24
+ en: { hello: "Hello, {name}!" },
25
+ fr: { hello: "Bonjour, {name}!" },
26
+ },
27
+ },
28
+ });
29
+
30
+ function App() {
31
+ return (
32
+ <FaneeProvider runtime={runtime}>
33
+ <Greeting />
34
+ </FaneeProvider>
35
+ );
36
+ }
37
+
38
+ function Greeting() {
39
+ const t = useT();
40
+ const locale = useLocale();
41
+ const setLocale = useSetLocale();
42
+
43
+ return (
44
+ <div>
45
+ <p>{t("hello", { name: "World" })}</p>
46
+ <p>Current locale: {locale}</p>
47
+ <button onClick={() => setLocale(locale === "en" ? "fr" : "en")}>
48
+ Switch locale
49
+ </button>
50
+ </div>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ## API
56
+
57
+ ### `FaneeProvider`
58
+
59
+ Wraps your app and exposes a `FaneeRuntime` instance to descendant hooks.
60
+
61
+ ### `useT(context?)`
62
+
63
+ Returns a bound translate function. Re-renders when the locale, namespace, or resources change.
64
+
65
+ ### `useLocale()`
66
+
67
+ Returns the active locale.
68
+
69
+ ### `useSetLocale()`
70
+
71
+ Returns a function to update the active locale.
72
+
73
+ ### `useFanee()`
74
+
75
+ Returns `{ runtime, locale }` for direct access to the runtime instance.
76
+
77
+ ## License
78
+
79
+ MIT
@@ -0,0 +1,76 @@
1
+ import { ReactNode } from "react";
2
+ import { FaneeRuntime, Locale, TranslateContext, TranslateFunction } from "@fanee/core";
3
+
4
+ //#region src/provider.d.ts
5
+ interface FaneeProviderProps {
6
+ /** FaneeRuntime instance to expose to the React tree. */
7
+ runtime: FaneeRuntime;
8
+ /** React children. */
9
+ children: ReactNode;
10
+ }
11
+ /**
12
+ * Provides a FaneeRuntime instance to descendant components.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const runtime = new FaneeRuntime().config({ currentLocale: "en" });
17
+ *
18
+ * <FaneeProvider runtime={runtime}>
19
+ * <App />
20
+ * </FaneeProvider>
21
+ * ```
22
+ */
23
+ declare function FaneeProvider({
24
+ runtime,
25
+ children
26
+ }: FaneeProviderProps): import("react").JSX.Element;
27
+ /** @internal */
28
+ declare function useRuntime(): FaneeRuntime;
29
+ //#endregion
30
+ //#region src/hooks.d.ts
31
+ /**
32
+ * Subscribe to the Fanee runtime and access it alongside the current locale.
33
+ *
34
+ * @returns An object with the runtime and the active locale.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * const { runtime, locale } = useFanee();
39
+ * ```
40
+ */
41
+ declare function useFanee(): {
42
+ runtime: ReturnType<typeof useRuntime>;
43
+ locale: Locale;
44
+ };
45
+ /**
46
+ * Return a translation function bound to the current runtime state and
47
+ * an optional namespace/locale context.
48
+ *
49
+ * The returned function is recreated whenever the active locale, namespace,
50
+ * or underlying resources change, so it remains reactive to runtime updates.
51
+ *
52
+ * @param context - Optional locale/namespace overrides.
53
+ * @returns A `(key, vars?) => string` translate function.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * const t = useT({ namespace: "errors" });
58
+ * return <p>{t("not_found")}</p>;
59
+ * ```
60
+ */
61
+ declare function useT(context?: Partial<TranslateContext>): TranslateFunction;
62
+ /**
63
+ * Read the currently active locale from the runtime.
64
+ *
65
+ * @returns The BCP-47 locale tag.
66
+ */
67
+ declare function useLocale(): Locale;
68
+ /**
69
+ * Return a setter for the runtime locale.
70
+ *
71
+ * @returns A function that updates the active locale.
72
+ */
73
+ declare function useSetLocale(): (locale: Locale) => void;
74
+ //#endregion
75
+ export { FaneeProvider, type FaneeProviderProps, useFanee, useLocale, useSetLocale, useT };
76
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/provider.tsx","../src/hooks.ts"],"mappings":";;;;UAKiB,kBAAA;;EAEhB,OAAA,EAAS,YAAA;EAFyB;EAIlC,QAAA,EAAU,SAAS;AAAA;;;;;;AAAA;AAepB;;;;;;iBAAgB,aAAA;EAAgB,OAAA;EAAS;AAAA,GAAY,kBAAA,mBAAkB,GAAA,CAAA,OAAA;;iBAKvD,UAAA,IAAc,YAAY;;;;;AAxB1C;;;;;;;;iBCsBgB,QAAA;EAAc,OAAA,EAAS,UAAA,QAAkB,UAAA;EAAa,MAAA,EAAQ,MAAA;AAAA;;;;;;;;;;;;;;;ADHP;AAKvE;iBCoBgB,IAAA,CAAK,OAAA,GAAU,OAAA,CAAQ,gBAAA,IAAoB,iBAAA;;;ADpBjB;;;iBCyC1B,SAAA,IAAa,MAAM;AA3CnC;;;;;AAAA,iBAsDgB,YAAA,KAAiB,MAAc,EAAN,MAAM"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{createContext as e,useCallback as t,useContext as n,useEffect as r,useMemo as i,useReducer as a}from"react";import{jsx as o}from"react/jsx-runtime";const s=e(null);function c({runtime:e,children:t}){return o(s.Provider,{value:e,children:t})}function l(){let e=n(s);if(!e)throw Error(`[fanee] Fanee hooks must be used within a FaneeProvider`);return e}function u(){let e=l(),[t,n]=a(e=>e+1,0);return r(()=>e.subscribe(()=>{n()}),[e]),t}function d(){let e=l(),t=p();return i(()=>({runtime:e,locale:t}),[e,t])}function f(e){let n=l(),r=u(),i=e?.locale,a=e?.namespace;return t((e,t)=>n.getT({locale:i,namespace:a})(e,t),[n,i,a,r])}function p(){let e=l();return u(),e.getLocale()}function m(){let e=l();return t(t=>e.setLocale(t),[e])}export{c as FaneeProvider,d as useFanee,p as useLocale,m as useSetLocale,f as useT};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\nimport type { FaneeRuntime } from \"@fanee/core\";\n\nconst FaneeContext = createContext<FaneeRuntime | null>(null);\n\nexport interface FaneeProviderProps {\n\t/** FaneeRuntime instance to expose to the React tree. */\n\truntime: FaneeRuntime;\n\t/** React children. */\n\tchildren: ReactNode;\n}\n\n/**\n * Provides a FaneeRuntime instance to descendant components.\n *\n * @example\n * ```tsx\n * const runtime = new FaneeRuntime().config({ currentLocale: \"en\" });\n *\n * <FaneeProvider runtime={runtime}>\n * <App />\n * </FaneeProvider>\n * ```\n */\nexport function FaneeProvider({ runtime, children }: FaneeProviderProps) {\n\treturn <FaneeContext.Provider value={runtime}>{children}</FaneeContext.Provider>;\n}\n\n/** @internal */\nexport function useRuntime(): FaneeRuntime {\n\tconst runtime = useContext(FaneeContext);\n\tif (!runtime) {\n\t\tthrow new Error(\"[fanee] Fanee hooks must be used within a FaneeProvider\");\n\t}\n\treturn runtime;\n}\n","import { useCallback, useEffect, useReducer, useMemo } from \"react\";\nimport type { Locale, MessageKey, TranslateContext, TranslateFunction } from \"@fanee/core\";\nimport { useRuntime } from \"./provider\";\n\nfunction useRuntimeVersion(): number {\n\tconst runtime = useRuntime();\n\tconst [version, bump] = useReducer((v: number) => v + 1, 0);\n\n\tuseEffect(() => {\n\t\treturn runtime.subscribe(() => {\n\t\t\tbump();\n\t\t});\n\t}, [runtime]);\n\n\treturn version;\n}\n\n/**\n * Subscribe to the Fanee runtime and access it alongside the current locale.\n *\n * @returns An object with the runtime and the active locale.\n *\n * @example\n * ```tsx\n * const { runtime, locale } = useFanee();\n * ```\n */\nexport function useFanee(): { runtime: ReturnType<typeof useRuntime>; locale: Locale } {\n\tconst runtime = useRuntime();\n\tconst locale = useLocale();\n\treturn useMemo(() => ({ runtime, locale }), [runtime, locale]);\n}\n\n/**\n * Return a translation function bound to the current runtime state and\n * an optional namespace/locale context.\n *\n * The returned function is recreated whenever the active locale, namespace,\n * or underlying resources change, so it remains reactive to runtime updates.\n *\n * @param context - Optional locale/namespace overrides.\n * @returns A `(key, vars?) => string` translate function.\n *\n * @example\n * ```tsx\n * const t = useT({ namespace: \"errors\" });\n * return <p>{t(\"not_found\")}</p>;\n * ```\n */\nexport function useT(context?: Partial<TranslateContext>): TranslateFunction {\n\tconst runtime = useRuntime();\n\tconst version = useRuntimeVersion();\n\tconst locale = context?.locale;\n\tconst namespace = context?.namespace;\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: version forces update on resource changes\n\treturn useCallback(\n\t\t(key: MessageKey, vars?: Record<string, unknown>) => {\n\t\t\tconst result = runtime.getT({ locale, namespace })(key, vars);\n\t\t\treturn result;\n\t\t},\n\t\t[runtime, locale, namespace, version]\n\t);\n}\n\n/**\n * Read the currently active locale from the runtime.\n *\n * @returns The BCP-47 locale tag.\n */\nexport function useLocale(): Locale {\n\tconst runtime = useRuntime();\n\tuseRuntimeVersion();\n\treturn runtime.getLocale();\n}\n\n/**\n * Return a setter for the runtime locale.\n *\n * @returns A function that updates the active locale.\n */\nexport function useSetLocale(): (locale: Locale) => void {\n\tconst runtime = useRuntime();\n\treturn useCallback((locale: Locale) => runtime.setLocale(locale), [runtime]);\n}\n"],"mappings":"2JAGA,MAAM,EAAe,EAAmC,IAAI,EAqB5D,SAAgB,EAAc,CAAE,UAAS,YAAgC,CACxE,OAAO,EAAC,EAAa,SAAd,CAAuB,MAAO,EAAU,UAAgC,CAAA,CAChF,CAGA,SAAgB,GAA2B,CAC1C,IAAM,EAAU,EAAW,CAAY,EACvC,GAAI,CAAC,EACJ,MAAU,MAAM,yDAAyD,EAE1E,OAAO,CACR,CC/BA,SAAS,GAA4B,CACpC,IAAM,EAAU,EAAW,EACrB,CAAC,EAAS,GAAQ,EAAY,GAAc,EAAI,EAAG,CAAC,EAQ1D,OANA,MACQ,EAAQ,cAAgB,CAC9B,EAAK,CACN,CAAC,EACC,CAAC,CAAO,CAAC,EAEL,CACR,CAYA,SAAgB,GAAuE,CACtF,IAAM,EAAU,EAAW,EACrB,EAAS,EAAU,EACzB,OAAO,OAAe,CAAE,UAAS,QAAO,GAAI,CAAC,EAAS,CAAM,CAAC,CAC9D,CAkBA,SAAgB,EAAK,EAAwD,CAC5E,IAAM,EAAU,EAAW,EACrB,EAAU,EAAkB,EAC5B,EAAS,GAAS,OAClB,EAAY,GAAS,UAG3B,OAAO,GACL,EAAiB,IACF,EAAQ,KAAK,CAAE,SAAQ,WAAU,CAAC,CAAC,CAAC,EAAK,CAC5C,EAEb,CAAC,EAAS,EAAQ,EAAW,CAAO,CACrC,CACD,CAOA,SAAgB,GAAoB,CACnC,IAAM,EAAU,EAAW,EAE3B,OADA,EAAkB,EACX,EAAQ,UAAU,CAC1B,CAOA,SAAgB,GAAyC,CACxD,IAAM,EAAU,EAAW,EAC3B,OAAO,EAAa,GAAmB,EAAQ,UAAU,CAAM,EAAG,CAAC,CAAO,CAAC,CAC5E"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@fanee/react",
3
+ "main": "dist/index.js",
4
+ "module": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "version": "0.6.0",
7
+ "type": "module",
8
+ "private": false,
9
+ "license": "MIT",
10
+ "repository": {
11
+ "url": "https://github.com/project-cvsa/fanee"
12
+ },
13
+ "scripts": {
14
+ "build": "bunx --bun tsdown",
15
+ "lint": "bunx --bun biome lint",
16
+ "test": "bun test --preload ./tests/setup.ts",
17
+ "test:coverage": "bun test --preload ./tests/setup.ts --coverage",
18
+ "typecheck": "bunx --bun tsgo --noEmit"
19
+ },
20
+ "peerDependencies": {
21
+ "react": ">=18"
22
+ },
23
+ "dependencies": {
24
+ "@fanee/core": "workspace:*"
25
+ },
26
+ "devDependencies": {
27
+ "@testing-library/react": "^16.0.0",
28
+ "@types/bun": "latest",
29
+ "@types/react": "^19.2.14",
30
+ "happy-dom": "^17.0.0",
31
+ "react": "^19.2.6",
32
+ "react-dom": "^19.2.7",
33
+ "tsdown": "^0.22.2"
34
+ },
35
+ "files": [
36
+ "dist/"
37
+ ]
38
+ }