@verbaly/react 0.2.0 → 0.4.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,53 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/AronSoto/verbaly/develop/assets/logo-light.png" alt="Verbaly" width="300" />
3
+ </p>
4
+
5
+ <p align="center"><em>React bindings for Verbaly — hooks over the reactive core.</em></p>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@verbaly/react"><img src="https://img.shields.io/npm/v/@verbaly/react?logo=npm&color=cb3837" alt="npm version" /></a>
9
+ <a href="https://github.com/AronSoto/verbaly/blob/develop/LICENSE"><img src="https://img.shields.io/npm/l/@verbaly/react?color=blue" alt="Apache-2.0" /></a>
10
+ </p>
11
+
12
+ ---
13
+
14
+ React hooks for [Verbaly](https://github.com/AronSoto/verbaly) — a thin layer (React 18/19) over the reactive core via `useSyncExternalStore`.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pnpm add verbaly @verbaly/react
20
+ ```
21
+
22
+ ```tsx
23
+ import { VerbalyProvider, useT, useLocale } from '@verbaly/react';
24
+ import { verbaly } from 'virtual:verbaly';
25
+
26
+ <VerbalyProvider instance={verbaly}>
27
+ <App />
28
+ </VerbalyProvider>;
29
+
30
+ function Inbox() {
31
+ const t = useT();
32
+ return <p>{t('inbox', { count: 3 })}</p>;
33
+ }
34
+ ```
35
+
36
+ ### Rich text — `<Trans>`
37
+
38
+ Interpolate elements with named tags in the message:
39
+
40
+ ```tsx
41
+ import { Trans } from '@verbaly/react';
42
+
43
+ // message: Read the <terms>terms</terms> first
44
+ <Trans id="agree" components={{ terms: <a href="/terms" /> }} />;
45
+ ```
46
+
47
+ 📖 Docs: **https://verbaly-web.vercel.app/docs/frameworks**
48
+
49
+ > ⚠️ Early development (`0.x`) — API not stable yet.
50
+
51
+ ## License
52
+
53
+ [Apache-2.0](https://github.com/AronSoto/verbaly/blob/develop/LICENSE) © Aron Soto
package/dist/index.cjs CHANGED
@@ -28,6 +28,7 @@ __export(index_exports, {
28
28
  });
29
29
  module.exports = __toCommonJS(index_exports);
30
30
  var import_react = require("react");
31
+ var import_verbaly = require("verbaly");
31
32
  var VerbalyContext = (0, import_react.createContext)(null);
32
33
  function VerbalyProvider(props) {
33
34
  return (0, import_react.createElement)(
@@ -63,37 +64,15 @@ function useVersion(instance) {
63
64
  function Trans(props) {
64
65
  const t = useT();
65
66
  const text = t(props.id, props.values);
66
- return (0, import_react.createElement)(import_react.Fragment, null, ...renderTags(text, props.components ?? {}));
67
+ return (0, import_react.createElement)(import_react.Fragment, null, ...toNodes((0, import_verbaly.parseTags)(text), props.components ?? {}));
67
68
  }
68
- var TAG = /<(\/?)([a-zA-Z][\w-]*)(\/?)>/g;
69
- function renderTags(text, components) {
70
- const tag = new RegExp(TAG.source, "g");
71
- let pos = 0;
72
- let key = 0;
73
- const walk = (stop) => {
74
- const out = [];
75
- let m;
76
- while ((m = tag.exec(text)) !== null) {
77
- const [full, closing, name, selfClose] = m;
78
- if (m.index > pos) out.push(text.slice(pos, m.index));
79
- pos = m.index + full.length;
80
- if (closing) {
81
- if (name === stop) return out;
82
- out.push(full);
83
- } else if (selfClose) {
84
- const el = components[name];
85
- out.push(el ? (0, import_react.cloneElement)(el, { key: key++ }) : full);
86
- } else {
87
- const children = walk(name);
88
- const el = components[name];
89
- if (el) out.push((0, import_react.cloneElement)(el, { key: key++ }, ...children));
90
- else out.push(...children);
91
- }
92
- }
93
- if (pos < text.length) out.push(text.slice(pos));
94
- return out;
95
- };
96
- return walk(null);
69
+ function toNodes(nodes, components) {
70
+ return nodes.map((node, i) => {
71
+ if (typeof node === "string") return node;
72
+ const children = toNodes(node.children, components);
73
+ const el = components[node.name];
74
+ return el ? (0, import_react.cloneElement)(el, { key: i }, ...children) : (0, import_react.createElement)(import_react.Fragment, { key: i }, ...children);
75
+ });
97
76
  }
98
77
  // Annotate the CommonJS export names for ESM import in node:
99
78
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\r\n cloneElement,\r\n createContext,\r\n createElement,\r\n Fragment,\r\n useContext,\r\n useSyncExternalStore,\r\n type ReactElement,\r\n type ReactNode,\r\n} from 'react';\r\nimport type { DictionaryInput, Params, TFunction, Verbaly } from 'verbaly';\r\n\r\nconst VerbalyContext = createContext<Verbaly | null>(null);\r\n\r\nexport interface VerbalyProviderProps<D extends DictionaryInput> {\r\n instance: Verbaly<D>;\r\n children?: ReactNode;\r\n}\r\n\r\nexport function VerbalyProvider<D extends DictionaryInput>(\r\n props: VerbalyProviderProps<D>,\r\n): ReactElement {\r\n return createElement(\r\n VerbalyContext.Provider,\r\n { value: props.instance as unknown as Verbaly },\r\n props.children,\r\n );\r\n}\r\n\r\nexport function useVerbaly<D extends DictionaryInput = DictionaryInput>(): Verbaly<D> {\r\n const instance = useContext(VerbalyContext);\r\n if (!instance) {\r\n throw new Error('[verbaly] useVerbaly requires a <VerbalyProvider>');\r\n }\r\n return instance as unknown as Verbaly<D>;\r\n}\r\n\r\nexport function useT<D extends DictionaryInput = DictionaryInput>(): TFunction<D> {\r\n const instance = useVerbaly<D>();\r\n useVersion(instance);\r\n return instance.t;\r\n}\r\n\r\nexport function useLocale(): [string, (locale: string) => void] {\r\n const instance = useVerbaly();\r\n useVersion(instance);\r\n return [instance.locale, instance.setLocale];\r\n}\r\n\r\nfunction useVersion<D extends DictionaryInput>(instance: Verbaly<D>): void {\r\n useSyncExternalStore(\r\n instance.subscribe,\r\n () => instance.version,\r\n () => instance.version,\r\n );\r\n}\r\n\r\nexport interface TransProps {\r\n id: string;\r\n values?: Params;\r\n components?: Record<string, ReactElement>;\r\n}\r\n\r\n// translated message + element interpolation\r\nexport function Trans(props: TransProps): ReactElement {\r\n const t = useT();\r\n const text = (t as unknown as (id: string, values?: Params) => string)(props.id, props.values);\r\n return createElement(Fragment, null, ...renderTags(text, props.components ?? {}));\r\n}\r\n\r\nconst TAG = /<(\\/?)([a-zA-Z][\\w-]*)(\\/?)>/g;\r\n\r\nfunction renderTags(text: string, components: Record<string, ReactElement>): ReactNode[] {\r\n const tag = new RegExp(TAG.source, 'g');\r\n let pos = 0;\r\n let key = 0;\r\n\r\n const walk = (stop: string | null): ReactNode[] => {\r\n const out: ReactNode[] = [];\r\n let m: RegExpExecArray | null;\r\n while ((m = tag.exec(text)) !== null) {\r\n const [full, closing, name, selfClose] = m;\r\n if (m.index > pos) out.push(text.slice(pos, m.index));\r\n pos = m.index + full.length;\r\n if (closing) {\r\n if (name === stop) return out;\r\n out.push(full); // stray close → literal\r\n } else if (selfClose) {\r\n const el = components[name!];\r\n out.push(el ? cloneElement(el, { key: key++ }) : full);\r\n } else {\r\n const children = walk(name!);\r\n const el = components[name!];\r\n if (el) out.push(cloneElement(el, { key: key++ }, ...children));\r\n else out.push(...children); // unknown tag → text\r\n }\r\n }\r\n if (pos < text.length) out.push(text.slice(pos));\r\n return out;\r\n };\r\n return walk(null);\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBASO;AAGP,IAAM,qBAAiB,4BAA8B,IAAI;AAOlD,SAAS,gBACd,OACc;AACd,aAAO;AAAA,IACL,eAAe;AAAA,IACf,EAAE,OAAO,MAAM,SAA+B;AAAA,IAC9C,MAAM;AAAA,EACR;AACF;AAEO,SAAS,aAAsE;AACpF,QAAM,eAAW,yBAAW,cAAc;AAC1C,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO;AACT;AAEO,SAAS,OAAkE;AAChF,QAAM,WAAW,WAAc;AAC/B,aAAW,QAAQ;AACnB,SAAO,SAAS;AAClB;AAEO,SAAS,YAAgD;AAC9D,QAAM,WAAW,WAAW;AAC5B,aAAW,QAAQ;AACnB,SAAO,CAAC,SAAS,QAAQ,SAAS,SAAS;AAC7C;AAEA,SAAS,WAAsC,UAA4B;AACzE;AAAA,IACE,SAAS;AAAA,IACT,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,EACjB;AACF;AASO,SAAS,MAAM,OAAiC;AACrD,QAAM,IAAI,KAAK;AACf,QAAM,OAAQ,EAAyD,MAAM,IAAI,MAAM,MAAM;AAC7F,aAAO,4BAAc,uBAAU,MAAM,GAAG,WAAW,MAAM,MAAM,cAAc,CAAC,CAAC,CAAC;AAClF;AAEA,IAAM,MAAM;AAEZ,SAAS,WAAW,MAAc,YAAuD;AACvF,QAAM,MAAM,IAAI,OAAO,IAAI,QAAQ,GAAG;AACtC,MAAI,MAAM;AACV,MAAI,MAAM;AAEV,QAAM,OAAO,CAAC,SAAqC;AACjD,UAAM,MAAmB,CAAC;AAC1B,QAAI;AACJ,YAAQ,IAAI,IAAI,KAAK,IAAI,OAAO,MAAM;AACpC,YAAM,CAAC,MAAM,SAAS,MAAM,SAAS,IAAI;AACzC,UAAI,EAAE,QAAQ,IAAK,KAAI,KAAK,KAAK,MAAM,KAAK,EAAE,KAAK,CAAC;AACpD,YAAM,EAAE,QAAQ,KAAK;AACrB,UAAI,SAAS;AACX,YAAI,SAAS,KAAM,QAAO;AAC1B,YAAI,KAAK,IAAI;AAAA,MACf,WAAW,WAAW;AACpB,cAAM,KAAK,WAAW,IAAK;AAC3B,YAAI,KAAK,SAAK,2BAAa,IAAI,EAAE,KAAK,MAAM,CAAC,IAAI,IAAI;AAAA,MACvD,OAAO;AACL,cAAM,WAAW,KAAK,IAAK;AAC3B,cAAM,KAAK,WAAW,IAAK;AAC3B,YAAI,GAAI,KAAI,SAAK,2BAAa,IAAI,EAAE,KAAK,MAAM,GAAG,GAAG,QAAQ,CAAC;AAAA,YACzD,KAAI,KAAK,GAAG,QAAQ;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,MAAM,KAAK,OAAQ,KAAI,KAAK,KAAK,MAAM,GAAG,CAAC;AAC/C,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI;AAClB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n cloneElement,\n createContext,\n createElement,\n Fragment,\n useContext,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n parseTags,\n type DictionaryInput,\n type Params,\n type TagNode,\n type TFunction,\n type Verbaly,\n} from 'verbaly';\n\nconst VerbalyContext = createContext<Verbaly | null>(null);\n\nexport interface VerbalyProviderProps<D extends DictionaryInput> {\n instance: Verbaly<D>;\n children?: ReactNode;\n}\n\nexport function VerbalyProvider<D extends DictionaryInput>(\n props: VerbalyProviderProps<D>,\n): ReactElement {\n return createElement(\n VerbalyContext.Provider,\n { value: props.instance as unknown as Verbaly },\n props.children,\n );\n}\n\nexport function useVerbaly<D extends DictionaryInput = DictionaryInput>(): Verbaly<D> {\n const instance = useContext(VerbalyContext);\n if (!instance) {\n throw new Error('[verbaly] useVerbaly requires a <VerbalyProvider>');\n }\n return instance as unknown as Verbaly<D>;\n}\n\nexport function useT<D extends DictionaryInput = DictionaryInput>(): TFunction<D> {\n const instance = useVerbaly<D>();\n useVersion(instance);\n return instance.t;\n}\n\nexport function useLocale(): [string, (locale: string) => void] {\n const instance = useVerbaly();\n useVersion(instance);\n return [instance.locale, instance.setLocale];\n}\n\nfunction useVersion<D extends DictionaryInput>(instance: Verbaly<D>): void {\n useSyncExternalStore(\n instance.subscribe,\n () => instance.version,\n () => instance.version,\n );\n}\n\nexport interface TransProps {\n id: string;\n values?: Params;\n components?: Record<string, ReactElement>;\n}\n\n// translated message + element interpolation\nexport function Trans(props: TransProps): ReactElement {\n const t = useT();\n const text = (t as unknown as (id: string, values?: Params) => string)(props.id, props.values);\n return createElement(Fragment, null, ...toNodes(parseTags(text), props.components ?? {}));\n}\n\nfunction toNodes(nodes: TagNode[], components: Record<string, ReactElement>): ReactNode[] {\n return nodes.map((node, i) => {\n if (typeof node === 'string') return node;\n const children = toNodes(node.children, components);\n const el = components[node.name];\n return el\n ? cloneElement(el, { key: i }, ...children)\n : createElement(Fragment, { key: i }, ...children);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBASO;AACP,qBAOO;AAEP,IAAM,qBAAiB,4BAA8B,IAAI;AAOlD,SAAS,gBACd,OACc;AACd,aAAO;AAAA,IACL,eAAe;AAAA,IACf,EAAE,OAAO,MAAM,SAA+B;AAAA,IAC9C,MAAM;AAAA,EACR;AACF;AAEO,SAAS,aAAsE;AACpF,QAAM,eAAW,yBAAW,cAAc;AAC1C,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO;AACT;AAEO,SAAS,OAAkE;AAChF,QAAM,WAAW,WAAc;AAC/B,aAAW,QAAQ;AACnB,SAAO,SAAS;AAClB;AAEO,SAAS,YAAgD;AAC9D,QAAM,WAAW,WAAW;AAC5B,aAAW,QAAQ;AACnB,SAAO,CAAC,SAAS,QAAQ,SAAS,SAAS;AAC7C;AAEA,SAAS,WAAsC,UAA4B;AACzE;AAAA,IACE,SAAS;AAAA,IACT,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,EACjB;AACF;AASO,SAAS,MAAM,OAAiC;AACrD,QAAM,IAAI,KAAK;AACf,QAAM,OAAQ,EAAyD,MAAM,IAAI,MAAM,MAAM;AAC7F,aAAO,4BAAc,uBAAU,MAAM,GAAG,YAAQ,0BAAU,IAAI,GAAG,MAAM,cAAc,CAAC,CAAC,CAAC;AAC1F;AAEA,SAAS,QAAQ,OAAkB,YAAuD;AACxF,SAAO,MAAM,IAAI,CAAC,MAAM,MAAM;AAC5B,QAAI,OAAO,SAAS,SAAU,QAAO;AACrC,UAAM,WAAW,QAAQ,KAAK,UAAU,UAAU;AAClD,UAAM,KAAK,WAAW,KAAK,IAAI;AAC/B,WAAO,SACH,2BAAa,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,QAAQ,QACxC,4BAAc,uBAAU,EAAE,KAAK,EAAE,GAAG,GAAG,QAAQ;AAAA,EACrD,CAAC;AACH;","names":[]}
package/dist/index.js CHANGED
@@ -7,6 +7,9 @@ import {
7
7
  useContext,
8
8
  useSyncExternalStore
9
9
  } from "react";
10
+ import {
11
+ parseTags
12
+ } from "verbaly";
10
13
  var VerbalyContext = createContext(null);
11
14
  function VerbalyProvider(props) {
12
15
  return createElement(
@@ -42,37 +45,15 @@ function useVersion(instance) {
42
45
  function Trans(props) {
43
46
  const t = useT();
44
47
  const text = t(props.id, props.values);
45
- return createElement(Fragment, null, ...renderTags(text, props.components ?? {}));
48
+ return createElement(Fragment, null, ...toNodes(parseTags(text), props.components ?? {}));
46
49
  }
47
- var TAG = /<(\/?)([a-zA-Z][\w-]*)(\/?)>/g;
48
- function renderTags(text, components) {
49
- const tag = new RegExp(TAG.source, "g");
50
- let pos = 0;
51
- let key = 0;
52
- const walk = (stop) => {
53
- const out = [];
54
- let m;
55
- while ((m = tag.exec(text)) !== null) {
56
- const [full, closing, name, selfClose] = m;
57
- if (m.index > pos) out.push(text.slice(pos, m.index));
58
- pos = m.index + full.length;
59
- if (closing) {
60
- if (name === stop) return out;
61
- out.push(full);
62
- } else if (selfClose) {
63
- const el = components[name];
64
- out.push(el ? cloneElement(el, { key: key++ }) : full);
65
- } else {
66
- const children = walk(name);
67
- const el = components[name];
68
- if (el) out.push(cloneElement(el, { key: key++ }, ...children));
69
- else out.push(...children);
70
- }
71
- }
72
- if (pos < text.length) out.push(text.slice(pos));
73
- return out;
74
- };
75
- return walk(null);
50
+ function toNodes(nodes, components) {
51
+ return nodes.map((node, i) => {
52
+ if (typeof node === "string") return node;
53
+ const children = toNodes(node.children, components);
54
+ const el = components[node.name];
55
+ return el ? cloneElement(el, { key: i }, ...children) : createElement(Fragment, { key: i }, ...children);
56
+ });
76
57
  }
77
58
  export {
78
59
  Trans,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\r\n cloneElement,\r\n createContext,\r\n createElement,\r\n Fragment,\r\n useContext,\r\n useSyncExternalStore,\r\n type ReactElement,\r\n type ReactNode,\r\n} from 'react';\r\nimport type { DictionaryInput, Params, TFunction, Verbaly } from 'verbaly';\r\n\r\nconst VerbalyContext = createContext<Verbaly | null>(null);\r\n\r\nexport interface VerbalyProviderProps<D extends DictionaryInput> {\r\n instance: Verbaly<D>;\r\n children?: ReactNode;\r\n}\r\n\r\nexport function VerbalyProvider<D extends DictionaryInput>(\r\n props: VerbalyProviderProps<D>,\r\n): ReactElement {\r\n return createElement(\r\n VerbalyContext.Provider,\r\n { value: props.instance as unknown as Verbaly },\r\n props.children,\r\n );\r\n}\r\n\r\nexport function useVerbaly<D extends DictionaryInput = DictionaryInput>(): Verbaly<D> {\r\n const instance = useContext(VerbalyContext);\r\n if (!instance) {\r\n throw new Error('[verbaly] useVerbaly requires a <VerbalyProvider>');\r\n }\r\n return instance as unknown as Verbaly<D>;\r\n}\r\n\r\nexport function useT<D extends DictionaryInput = DictionaryInput>(): TFunction<D> {\r\n const instance = useVerbaly<D>();\r\n useVersion(instance);\r\n return instance.t;\r\n}\r\n\r\nexport function useLocale(): [string, (locale: string) => void] {\r\n const instance = useVerbaly();\r\n useVersion(instance);\r\n return [instance.locale, instance.setLocale];\r\n}\r\n\r\nfunction useVersion<D extends DictionaryInput>(instance: Verbaly<D>): void {\r\n useSyncExternalStore(\r\n instance.subscribe,\r\n () => instance.version,\r\n () => instance.version,\r\n );\r\n}\r\n\r\nexport interface TransProps {\r\n id: string;\r\n values?: Params;\r\n components?: Record<string, ReactElement>;\r\n}\r\n\r\n// translated message + element interpolation\r\nexport function Trans(props: TransProps): ReactElement {\r\n const t = useT();\r\n const text = (t as unknown as (id: string, values?: Params) => string)(props.id, props.values);\r\n return createElement(Fragment, null, ...renderTags(text, props.components ?? {}));\r\n}\r\n\r\nconst TAG = /<(\\/?)([a-zA-Z][\\w-]*)(\\/?)>/g;\r\n\r\nfunction renderTags(text: string, components: Record<string, ReactElement>): ReactNode[] {\r\n const tag = new RegExp(TAG.source, 'g');\r\n let pos = 0;\r\n let key = 0;\r\n\r\n const walk = (stop: string | null): ReactNode[] => {\r\n const out: ReactNode[] = [];\r\n let m: RegExpExecArray | null;\r\n while ((m = tag.exec(text)) !== null) {\r\n const [full, closing, name, selfClose] = m;\r\n if (m.index > pos) out.push(text.slice(pos, m.index));\r\n pos = m.index + full.length;\r\n if (closing) {\r\n if (name === stop) return out;\r\n out.push(full); // stray close → literal\r\n } else if (selfClose) {\r\n const el = components[name!];\r\n out.push(el ? cloneElement(el, { key: key++ }) : full);\r\n } else {\r\n const children = walk(name!);\r\n const el = components[name!];\r\n if (el) out.push(cloneElement(el, { key: key++ }, ...children));\r\n else out.push(...children); // unknown tag → text\r\n }\r\n }\r\n if (pos < text.length) out.push(text.slice(pos));\r\n return out;\r\n };\r\n return walk(null);\r\n}\r\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAGP,IAAM,iBAAiB,cAA8B,IAAI;AAOlD,SAAS,gBACd,OACc;AACd,SAAO;AAAA,IACL,eAAe;AAAA,IACf,EAAE,OAAO,MAAM,SAA+B;AAAA,IAC9C,MAAM;AAAA,EACR;AACF;AAEO,SAAS,aAAsE;AACpF,QAAM,WAAW,WAAW,cAAc;AAC1C,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO;AACT;AAEO,SAAS,OAAkE;AAChF,QAAM,WAAW,WAAc;AAC/B,aAAW,QAAQ;AACnB,SAAO,SAAS;AAClB;AAEO,SAAS,YAAgD;AAC9D,QAAM,WAAW,WAAW;AAC5B,aAAW,QAAQ;AACnB,SAAO,CAAC,SAAS,QAAQ,SAAS,SAAS;AAC7C;AAEA,SAAS,WAAsC,UAA4B;AACzE;AAAA,IACE,SAAS;AAAA,IACT,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,EACjB;AACF;AASO,SAAS,MAAM,OAAiC;AACrD,QAAM,IAAI,KAAK;AACf,QAAM,OAAQ,EAAyD,MAAM,IAAI,MAAM,MAAM;AAC7F,SAAO,cAAc,UAAU,MAAM,GAAG,WAAW,MAAM,MAAM,cAAc,CAAC,CAAC,CAAC;AAClF;AAEA,IAAM,MAAM;AAEZ,SAAS,WAAW,MAAc,YAAuD;AACvF,QAAM,MAAM,IAAI,OAAO,IAAI,QAAQ,GAAG;AACtC,MAAI,MAAM;AACV,MAAI,MAAM;AAEV,QAAM,OAAO,CAAC,SAAqC;AACjD,UAAM,MAAmB,CAAC;AAC1B,QAAI;AACJ,YAAQ,IAAI,IAAI,KAAK,IAAI,OAAO,MAAM;AACpC,YAAM,CAAC,MAAM,SAAS,MAAM,SAAS,IAAI;AACzC,UAAI,EAAE,QAAQ,IAAK,KAAI,KAAK,KAAK,MAAM,KAAK,EAAE,KAAK,CAAC;AACpD,YAAM,EAAE,QAAQ,KAAK;AACrB,UAAI,SAAS;AACX,YAAI,SAAS,KAAM,QAAO;AAC1B,YAAI,KAAK,IAAI;AAAA,MACf,WAAW,WAAW;AACpB,cAAM,KAAK,WAAW,IAAK;AAC3B,YAAI,KAAK,KAAK,aAAa,IAAI,EAAE,KAAK,MAAM,CAAC,IAAI,IAAI;AAAA,MACvD,OAAO;AACL,cAAM,WAAW,KAAK,IAAK;AAC3B,cAAM,KAAK,WAAW,IAAK;AAC3B,YAAI,GAAI,KAAI,KAAK,aAAa,IAAI,EAAE,KAAK,MAAM,GAAG,GAAG,QAAQ,CAAC;AAAA,YACzD,KAAI,KAAK,GAAG,QAAQ;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,MAAM,KAAK,OAAQ,KAAI,KAAK,KAAK,MAAM,GAAG,CAAC;AAC/C,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI;AAClB;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n cloneElement,\n createContext,\n createElement,\n Fragment,\n useContext,\n useSyncExternalStore,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n parseTags,\n type DictionaryInput,\n type Params,\n type TagNode,\n type TFunction,\n type Verbaly,\n} from 'verbaly';\n\nconst VerbalyContext = createContext<Verbaly | null>(null);\n\nexport interface VerbalyProviderProps<D extends DictionaryInput> {\n instance: Verbaly<D>;\n children?: ReactNode;\n}\n\nexport function VerbalyProvider<D extends DictionaryInput>(\n props: VerbalyProviderProps<D>,\n): ReactElement {\n return createElement(\n VerbalyContext.Provider,\n { value: props.instance as unknown as Verbaly },\n props.children,\n );\n}\n\nexport function useVerbaly<D extends DictionaryInput = DictionaryInput>(): Verbaly<D> {\n const instance = useContext(VerbalyContext);\n if (!instance) {\n throw new Error('[verbaly] useVerbaly requires a <VerbalyProvider>');\n }\n return instance as unknown as Verbaly<D>;\n}\n\nexport function useT<D extends DictionaryInput = DictionaryInput>(): TFunction<D> {\n const instance = useVerbaly<D>();\n useVersion(instance);\n return instance.t;\n}\n\nexport function useLocale(): [string, (locale: string) => void] {\n const instance = useVerbaly();\n useVersion(instance);\n return [instance.locale, instance.setLocale];\n}\n\nfunction useVersion<D extends DictionaryInput>(instance: Verbaly<D>): void {\n useSyncExternalStore(\n instance.subscribe,\n () => instance.version,\n () => instance.version,\n );\n}\n\nexport interface TransProps {\n id: string;\n values?: Params;\n components?: Record<string, ReactElement>;\n}\n\n// translated message + element interpolation\nexport function Trans(props: TransProps): ReactElement {\n const t = useT();\n const text = (t as unknown as (id: string, values?: Params) => string)(props.id, props.values);\n return createElement(Fragment, null, ...toNodes(parseTags(text), props.components ?? {}));\n}\n\nfunction toNodes(nodes: TagNode[], components: Record<string, ReactElement>): ReactNode[] {\n return nodes.map((node, i) => {\n if (typeof node === 'string') return node;\n const children = toNodes(node.children, components);\n const el = components[node.name];\n return el\n ? cloneElement(el, { key: i }, ...children)\n : createElement(Fragment, { key: i }, ...children);\n });\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,OAMK;AAEP,IAAM,iBAAiB,cAA8B,IAAI;AAOlD,SAAS,gBACd,OACc;AACd,SAAO;AAAA,IACL,eAAe;AAAA,IACf,EAAE,OAAO,MAAM,SAA+B;AAAA,IAC9C,MAAM;AAAA,EACR;AACF;AAEO,SAAS,aAAsE;AACpF,QAAM,WAAW,WAAW,cAAc;AAC1C,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,SAAO;AACT;AAEO,SAAS,OAAkE;AAChF,QAAM,WAAW,WAAc;AAC/B,aAAW,QAAQ;AACnB,SAAO,SAAS;AAClB;AAEO,SAAS,YAAgD;AAC9D,QAAM,WAAW,WAAW;AAC5B,aAAW,QAAQ;AACnB,SAAO,CAAC,SAAS,QAAQ,SAAS,SAAS;AAC7C;AAEA,SAAS,WAAsC,UAA4B;AACzE;AAAA,IACE,SAAS;AAAA,IACT,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,EACjB;AACF;AASO,SAAS,MAAM,OAAiC;AACrD,QAAM,IAAI,KAAK;AACf,QAAM,OAAQ,EAAyD,MAAM,IAAI,MAAM,MAAM;AAC7F,SAAO,cAAc,UAAU,MAAM,GAAG,QAAQ,UAAU,IAAI,GAAG,MAAM,cAAc,CAAC,CAAC,CAAC;AAC1F;AAEA,SAAS,QAAQ,OAAkB,YAAuD;AACxF,SAAO,MAAM,IAAI,CAAC,MAAM,MAAM;AAC5B,QAAI,OAAO,SAAS,SAAU,QAAO;AACrC,UAAM,WAAW,QAAQ,KAAK,UAAU,UAAU;AAClD,UAAM,KAAK,WAAW,KAAK,IAAI;AAC/B,WAAO,KACH,aAAa,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,QAAQ,IACxC,cAAc,UAAU,EAAE,KAAK,EAAE,GAAG,GAAG,QAAQ;AAAA,EACrD,CAAC;AACH;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verbaly/react",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "React bindings for Verbaly — hooks over the reactive core.",
5
5
  "keywords": [
6
6
  "i18n",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "peerDependencies": {
45
45
  "react": "^18.0.0 || ^19.0.0",
46
- "verbaly": "^0.2.0"
46
+ "verbaly": "^0.4.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/react": "^19.2.17",
@@ -51,7 +51,7 @@
51
51
  "happy-dom": "^20.10.6",
52
52
  "react": "^19.2.7",
53
53
  "react-dom": "^19.2.7",
54
- "verbaly": "0.2.0"
54
+ "verbaly": "0.4.0"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup",