kotori 0.0.1 → 0.0.5
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 +24 -11
- package/dist/index.cjs +51 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +50 -1
- package/package.json +65 -65
package/README.md
CHANGED
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
Strongly-typed, modular i18n for React. Variables are inferred directly from your strings — no codegen, no JSON, no schema files.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
const
|
|
6
|
+
const { dict } = kotori({
|
|
7
|
+
primaryLanguageTag: 'en',
|
|
8
|
+
secondaryLanguageTags: ['zh', 'ja', 'ms'],
|
|
9
|
+
})
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
// ❌ compile error: missing japanese translation
|
|
12
|
+
const intro = dict({
|
|
13
|
+
en: 'Hello {{name}}, is it {{time}} now?', // base string drives the type contract
|
|
14
|
+
zh: '你好,现在是 {{time}} 吗?', // ❌ compile error: missing key 'nam'
|
|
15
|
+
ms: 'Hai {{nam}}, adakah pukul {{time}} sekarang?' // ❌ compile error: unknown key 'nam'
|
|
16
|
+
})<{name: string; time: `${number}:${number}`}> // optional: type your arguments, by default it's `Record<'name'|'time', string>` in this example
|
|
17
|
+
|
|
18
|
+
t('intro', { name: 'John', time: '12:25' }) // ✅
|
|
19
|
+
t('intro', { time: '12:25' }) // ❌ compile error: missing { name }
|
|
20
|
+
t('intro', { nama: 'John', time: '12:25' }) // ❌ compile error: unknown key 'nama'
|
|
21
|
+
t('intro', { name: 'John', time: '12-00' }) // ❌ compile error: invalid format for 'time'
|
|
11
22
|
```
|
|
12
23
|
|
|
13
24
|
- No codegen
|
|
14
25
|
- No JSON
|
|
15
26
|
- No dependencies
|
|
16
|
-
- 0.
|
|
27
|
+
- 0.39kb gzipped
|
|
17
28
|
- Modular and tree-shakeable
|
|
18
29
|
- Language change in one page rerenders all pages
|
|
19
30
|
- Variables typed and inferred from string literals
|
|
@@ -55,7 +66,7 @@ const time = dict({
|
|
|
55
66
|
zh: '时间 {{time}}',
|
|
56
67
|
ja: '時間 {{time}}',
|
|
57
68
|
ms: 'waktu {{time}}',
|
|
58
|
-
// type your arguments, by default it's `Record<string, string>`
|
|
69
|
+
// optional: type your arguments, by default it's `Record<string, string>`
|
|
59
70
|
})<{ time: `${number}:${number}:${number}` }>
|
|
60
71
|
|
|
61
72
|
const { useTranslations } = createTranslations({
|
|
@@ -143,7 +154,7 @@ export const Page2 = () => {
|
|
|
143
154
|
|
|
144
155
|
`kotori` holds the language state. All `createTranslations` calls share that state — changing the language anywhere rerenders everywhere.
|
|
145
156
|
|
|
146
|
-
### One `createTranslations` per page/feature
|
|
157
|
+
### One `createTranslations` per page/component/feature
|
|
147
158
|
|
|
148
159
|
Translations are colocated with the component that uses them. Bundlers naturally code-split them, so each page only loads what it needs.
|
|
149
160
|
|
|
@@ -179,16 +190,18 @@ const time = dict({ en: '{{hour}}:{{minute}}' })<{
|
|
|
179
190
|
Creates a scoped i18n instance.
|
|
180
191
|
|
|
181
192
|
| option | type | description |
|
|
182
|
-
|
|
193
|
+
| --- | --- | --- |
|
|
183
194
|
| `primaryLanguageTag` | `AllTags` | The source language. Drives variable inference. |
|
|
184
195
|
| `secondaryLanguageTags` | `AllTags[]` | Additional supported languages. |
|
|
185
196
|
|
|
186
197
|
Returns `{ dict, createTranslations }`.
|
|
187
198
|
|
|
188
|
-
### `dict(translations)
|
|
199
|
+
### `dict(translations)<argsType?>`
|
|
189
200
|
|
|
190
201
|
Defines a translation unit. Takes one string per language. Optionally takes a generic to type the interpolated variables.
|
|
191
202
|
|
|
203
|
+
Returns `() => { translations: Record<string, string> }`.
|
|
204
|
+
|
|
192
205
|
### `createTranslations(dicts)`
|
|
193
206
|
|
|
194
207
|
Registers a set of dicts and returns `{ useTranslations }`. Call once per page or feature module.
|
|
@@ -198,7 +211,7 @@ Registers a set of dicts and returns `{ useTranslations }`. Call once per page o
|
|
|
198
211
|
React hook. Returns `{ t, getLanguage, setLanguage }`.
|
|
199
212
|
|
|
200
213
|
| return | description |
|
|
201
|
-
|
|
214
|
+
| --- | --- |
|
|
202
215
|
| `t(key, args?)` | Returns the translated string for the current language. `args` is required if the string has variables, omitted if it doesn't. |
|
|
203
216
|
| `getLanguage()` | Returns the current language tag. |
|
|
204
217
|
| `setLanguage(tag)` | Updates the language and rerenders all active `useTranslations` consumers. |
|
|
@@ -211,4 +224,4 @@ kotori uses [BCP 47](https://www.iana.org/assignments/language-subtag-registry/l
|
|
|
211
224
|
|
|
212
225
|
There are already a lot of i18n libraries, and the good names are mostly taken. The original plan was *kotoba* (言葉), the Japanese word for "words" — also taken. Claude suggested *kotori* as an alternative, and it stuck.
|
|
213
226
|
|
|
214
|
-
*Kotori* (小鳥) means "small bird" in Japanese. No deeper relevance to the library — it just sounds nice.
|
|
227
|
+
*Kotori* (小鳥) means "small bird" in Japanese. No deeper relevance to the library — it just sounds nice.
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1,51 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let react = require("react");
|
|
3
|
+
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
const kotori = (props) => {
|
|
6
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7
|
+
let languageTag = props.primaryLanguageTag;
|
|
8
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
9
|
+
const languageTagMethod = {
|
|
10
|
+
getLanguage: () => languageTag,
|
|
11
|
+
setLanguage: (tag) => {
|
|
12
|
+
languageTag = tag;
|
|
13
|
+
snapshots.forEach((snapshot, key) => {
|
|
14
|
+
snapshots.set(key, { ...snapshot });
|
|
15
|
+
});
|
|
16
|
+
listeners.forEach((listener) => {
|
|
17
|
+
listener();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
dict: (translation) => () => ({ translation }),
|
|
23
|
+
createTranslations: (dictCallbacks) => {
|
|
24
|
+
const s = Symbol();
|
|
25
|
+
let refCount = 0;
|
|
26
|
+
const snapshot = {
|
|
27
|
+
...languageTagMethod,
|
|
28
|
+
t: (key, ...args) => {
|
|
29
|
+
let locale = dictCallbacks[key]?.().translation[languageTag];
|
|
30
|
+
if (!locale) return;
|
|
31
|
+
for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
|
|
32
|
+
return locale;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
snapshots.set(s, snapshot);
|
|
36
|
+
return { useTranslations: () => (0, react.useSyncExternalStore)((listener) => {
|
|
37
|
+
if (refCount === 0) snapshots.set(s, snapshot);
|
|
38
|
+
refCount++;
|
|
39
|
+
listeners.add(listener);
|
|
40
|
+
return () => {
|
|
41
|
+
refCount--;
|
|
42
|
+
if (refCount === 0) snapshots.delete(s);
|
|
43
|
+
listeners.delete(listener);
|
|
44
|
+
};
|
|
45
|
+
}, () => snapshots.get(s)) };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
exports.kotori = kotori;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region node_modules/bcp47-language-tags/dist/zh.d.ts
|
|
2
2
|
type BCP47LanguageTagName = "zh-CN" | "zh-TW" | "zh-HK" | "zh-MO" | "zh-SG" | "zh-CHS" | "zh-CHT" | "en-US" | "en-GB" | "en-CA" | "en-AU" | "en-IN" | "en-ZA" | "en-NZ" | "en-IE" | "en-PH" | "en-ZW" | "en-BZ" | "en-CB" | "en-JM" | "en-TT" | "hi-IN" | "es-ES" | "es-MX" | "es-AR" | "es-CO" | "es-PE" | "es-VE" | "es-CL" | "es-EC" | "es-GT" | "es-CU" | "es-BO" | "es-DO" | "es-HN" | "es-PY" | "es-SV" | "es-NI" | "es-PR" | "es-UY" | "es-PA" | "es-CR" | "ar-EG" | "ar-SA" | "ar-DZ" | "ar-MA" | "ar-IQ" | "ar-SD" | "ar-YE" | "ar-SY" | "ar-TN" | "ar-LY" | "ar-JO" | "ar-LB" | "ar-KW" | "ar-AE" | "ar-BH" | "ar-QA" | "ar-OM" | "pt-BR" | "pt-PT" | "ru-RU" | "ja-JP" | "de-DE" | "de-AT" | "de-CH" | "fr-FR" | "fr-CA" | "fr-BE" | "fr-CH" | "fr-LU" | "fr-MC" | "ko-KR" | "it-IT" | "it-CH" | "tr-TR" | "th-TH" | "el-GR" | "cs-CZ" | "sv-SE" | "sv-FI" | "hu-HU" | "fi-FI" | "da-DK" | "nb-NO" | "nn-NO" | "he-IL" | "id-ID" | "ms-MY" | "ms-BN" | "ro-RO" | "bg-BG" | "uk-UA" | "sk-SK" | "sl-SI" | "hr-HR" | "ca-ES" | "lt-LT" | "lv-LV" | "et-EE" | "sq-AL" | "mk-MK" | "be-BY" | "is-IS" | "gl-ES" | "eu-ES" | "af-ZA" | "sw-KE" | "ta-IN" | "te-IN" | "kn-IN" | "mr-IN" | "gu-IN" | "pa-IN" | "kok-IN" | "sa-IN" | "ur-PK" | "fa-IR" | "syr-SY" | "div-MV" | "ka-GE";
|
|
3
3
|
//#endregion
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/index.d.ts
|
|
5
5
|
type Tags = BCP47LanguageTagName;
|
|
6
6
|
type SubTags = BCP47LanguageTagName extends `${infer SubTag}-${string}` ? SubTag : never;
|
|
7
7
|
type AllTags = Tags | SubTags;
|
|
@@ -21,11 +21,11 @@ declare const kotori: <const PrimaryTag extends AllTags, const SecondaryTags ext
|
|
|
21
21
|
[_args]?: Record<string, string | number>;
|
|
22
22
|
}>>>(dictCallbacks: DictCallbacks) => {
|
|
23
23
|
useTranslations: () => {
|
|
24
|
+
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
24
25
|
getLanguage: () => PrimaryTag | SecondaryTags;
|
|
25
26
|
setLanguage: (tag: PrimaryTag | SecondaryTags) => void;
|
|
26
|
-
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
//#endregion
|
|
31
|
-
export { AllTags,
|
|
31
|
+
export { AllTags, SubTags, Tags, kotori };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region node_modules/bcp47-language-tags/dist/zh.d.ts
|
|
2
2
|
type BCP47LanguageTagName = "zh-CN" | "zh-TW" | "zh-HK" | "zh-MO" | "zh-SG" | "zh-CHS" | "zh-CHT" | "en-US" | "en-GB" | "en-CA" | "en-AU" | "en-IN" | "en-ZA" | "en-NZ" | "en-IE" | "en-PH" | "en-ZW" | "en-BZ" | "en-CB" | "en-JM" | "en-TT" | "hi-IN" | "es-ES" | "es-MX" | "es-AR" | "es-CO" | "es-PE" | "es-VE" | "es-CL" | "es-EC" | "es-GT" | "es-CU" | "es-BO" | "es-DO" | "es-HN" | "es-PY" | "es-SV" | "es-NI" | "es-PR" | "es-UY" | "es-PA" | "es-CR" | "ar-EG" | "ar-SA" | "ar-DZ" | "ar-MA" | "ar-IQ" | "ar-SD" | "ar-YE" | "ar-SY" | "ar-TN" | "ar-LY" | "ar-JO" | "ar-LB" | "ar-KW" | "ar-AE" | "ar-BH" | "ar-QA" | "ar-OM" | "pt-BR" | "pt-PT" | "ru-RU" | "ja-JP" | "de-DE" | "de-AT" | "de-CH" | "fr-FR" | "fr-CA" | "fr-BE" | "fr-CH" | "fr-LU" | "fr-MC" | "ko-KR" | "it-IT" | "it-CH" | "tr-TR" | "th-TH" | "el-GR" | "cs-CZ" | "sv-SE" | "sv-FI" | "hu-HU" | "fi-FI" | "da-DK" | "nb-NO" | "nn-NO" | "he-IL" | "id-ID" | "ms-MY" | "ms-BN" | "ro-RO" | "bg-BG" | "uk-UA" | "sk-SK" | "sl-SI" | "hr-HR" | "ca-ES" | "lt-LT" | "lv-LV" | "et-EE" | "sq-AL" | "mk-MK" | "be-BY" | "is-IS" | "gl-ES" | "eu-ES" | "af-ZA" | "sw-KE" | "ta-IN" | "te-IN" | "kn-IN" | "mr-IN" | "gu-IN" | "pa-IN" | "kok-IN" | "sa-IN" | "ur-PK" | "fa-IR" | "syr-SY" | "div-MV" | "ka-GE";
|
|
3
3
|
//#endregion
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/index.d.ts
|
|
5
5
|
type Tags = BCP47LanguageTagName;
|
|
6
6
|
type SubTags = BCP47LanguageTagName extends `${infer SubTag}-${string}` ? SubTag : never;
|
|
7
7
|
type AllTags = Tags | SubTags;
|
|
@@ -21,11 +21,11 @@ declare const kotori: <const PrimaryTag extends AllTags, const SecondaryTags ext
|
|
|
21
21
|
[_args]?: Record<string, string | number>;
|
|
22
22
|
}>>>(dictCallbacks: DictCallbacks) => {
|
|
23
23
|
useTranslations: () => {
|
|
24
|
+
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
24
25
|
getLanguage: () => PrimaryTag | SecondaryTags;
|
|
25
26
|
setLanguage: (tag: PrimaryTag | SecondaryTags) => void;
|
|
26
|
-
t: <Key extends keyof DictCallbacks>(key: Key, ...args: keyof NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]> extends never ? [] : [NonNullable<ReturnType<DictCallbacks[Key]>[typeof _args]>]) => Record<PrimaryTag | SecondaryTags, string>[PrimaryTag | SecondaryTags] | undefined;
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
//#endregion
|
|
31
|
-
export { AllTags,
|
|
31
|
+
export { AllTags, SubTags, Tags, kotori };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1,50 @@
|
|
|
1
|
-
import{useSyncExternalStore
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
const kotori = (props) => {
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
let languageTag = props.primaryLanguageTag;
|
|
7
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
8
|
+
const languageTagMethod = {
|
|
9
|
+
getLanguage: () => languageTag,
|
|
10
|
+
setLanguage: (tag) => {
|
|
11
|
+
languageTag = tag;
|
|
12
|
+
snapshots.forEach((snapshot, key) => {
|
|
13
|
+
snapshots.set(key, { ...snapshot });
|
|
14
|
+
});
|
|
15
|
+
listeners.forEach((listener) => {
|
|
16
|
+
listener();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
dict: (translation) => () => ({ translation }),
|
|
22
|
+
createTranslations: (dictCallbacks) => {
|
|
23
|
+
const s = Symbol();
|
|
24
|
+
let refCount = 0;
|
|
25
|
+
const snapshot = {
|
|
26
|
+
...languageTagMethod,
|
|
27
|
+
t: (key, ...args) => {
|
|
28
|
+
let locale = dictCallbacks[key]?.().translation[languageTag];
|
|
29
|
+
if (!locale) return;
|
|
30
|
+
for (const objKey in args[0]) locale = locale.replace(new RegExp(`\\{\\{\\s*${objKey}\\s*\\}\\}`, "g"), () => String(args[0]?.[objKey]));
|
|
31
|
+
return locale;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
snapshots.set(s, snapshot);
|
|
35
|
+
return { useTranslations: () => useSyncExternalStore((listener) => {
|
|
36
|
+
if (refCount === 0) snapshots.set(s, snapshot);
|
|
37
|
+
refCount++;
|
|
38
|
+
listeners.add(listener);
|
|
39
|
+
return () => {
|
|
40
|
+
refCount--;
|
|
41
|
+
if (refCount === 0) snapshots.delete(s);
|
|
42
|
+
listeners.delete(listener);
|
|
43
|
+
};
|
|
44
|
+
}, () => snapshots.get(s)) };
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
export { kotori };
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "kotori",
|
|
3
|
-
"description": "Strongly-typed and composable internationalization library for React",
|
|
4
|
-
"version": "0.0.
|
|
5
|
-
"scripts": {
|
|
6
|
-
"setup": "rm -rf node_modules && npm i && git init && husky",
|
|
7
|
-
"prepublishOnly": "npm run build",
|
|
8
|
-
"build": "tsdown",
|
|
9
|
-
"test": "vitest",
|
|
10
|
-
"lint": "npx @biomejs/biome check --write",
|
|
11
|
-
"dev": "vite --host"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"dist"
|
|
15
|
-
],
|
|
16
|
-
"lint-staged": {
|
|
17
|
-
"*": [
|
|
18
|
-
"npm run lint"
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
"type": "module",
|
|
22
|
-
"main": "./dist/index.cjs",
|
|
23
|
-
"types": "./dist/index.d.cts",
|
|
24
|
-
"exports": {
|
|
25
|
-
".": {
|
|
26
|
-
"require": {
|
|
27
|
-
"types": "./dist/index.d.cts",
|
|
28
|
-
"default": "./dist/index.cjs"
|
|
29
|
-
},
|
|
30
|
-
"import": {
|
|
31
|
-
"types": "./dist/index.d.mts",
|
|
32
|
-
"default": "./dist/index.mjs"
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"@biomejs/biome": "^2.4.12",
|
|
38
|
-
"@types/node": "^25.6.0",
|
|
39
|
-
"@types/react": "^19.2.14",
|
|
40
|
-
"@types/react-dom": "^19.2.3",
|
|
41
|
-
"@vitejs/plugin-react": "^6.0.1",
|
|
42
|
-
"@vitest/coverage-v8": "^4.1.5",
|
|
43
|
-
"bcp47-language-tags": "^1.1.0",
|
|
44
|
-
"husky": "^9.1.7",
|
|
45
|
-
"lint-staged": "^16.4.0",
|
|
46
|
-
"react": "^19.2.5",
|
|
47
|
-
"react-dom": "^19.2.5",
|
|
48
|
-
"tsdown": "^0.21.10",
|
|
49
|
-
"tsx": "^4.21.0",
|
|
50
|
-
"typescript": "^6.0.3",
|
|
51
|
-
"vitest": "^4.1.5"
|
|
52
|
-
},
|
|
53
|
-
"repository": {
|
|
54
|
-
"type": "git",
|
|
55
|
-
"url": "git+https://github.com/tylim88/kotori.git"
|
|
56
|
-
},
|
|
57
|
-
"bugs": {
|
|
58
|
-
"url": "https://github.com/tylim88/kotori/issues"
|
|
59
|
-
},
|
|
60
|
-
"author": "tylim88",
|
|
61
|
-
"license": "MIT",
|
|
62
|
-
"peerDependencies": {
|
|
63
|
-
"react": ">=19.2.5"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "kotori",
|
|
3
|
+
"description": "Strongly-typed and composable internationalization library for React",
|
|
4
|
+
"version": "0.0.5",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"setup": "rm -rf node_modules && npm i && git init && husky",
|
|
7
|
+
"prepublishOnly": "npm run build",
|
|
8
|
+
"build": "tsdown",
|
|
9
|
+
"test": "vitest",
|
|
10
|
+
"lint": "npx @biomejs/biome check --write",
|
|
11
|
+
"dev": "vite --host"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"lint-staged": {
|
|
17
|
+
"*": [
|
|
18
|
+
"npm run lint"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.cjs",
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/index.d.cts",
|
|
28
|
+
"default": "./dist/index.cjs"
|
|
29
|
+
},
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./dist/index.d.mts",
|
|
32
|
+
"default": "./dist/index.mjs"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@biomejs/biome": "^2.4.12",
|
|
38
|
+
"@types/node": "^25.6.0",
|
|
39
|
+
"@types/react": "^19.2.14",
|
|
40
|
+
"@types/react-dom": "^19.2.3",
|
|
41
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
42
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
43
|
+
"bcp47-language-tags": "^1.1.0",
|
|
44
|
+
"husky": "^9.1.7",
|
|
45
|
+
"lint-staged": "^16.4.0",
|
|
46
|
+
"react": "^19.2.5",
|
|
47
|
+
"react-dom": "^19.2.5",
|
|
48
|
+
"tsdown": "^0.21.10",
|
|
49
|
+
"tsx": "^4.21.0",
|
|
50
|
+
"typescript": "^6.0.3",
|
|
51
|
+
"vitest": "^4.1.5"
|
|
52
|
+
},
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "git+https://github.com/tylim88/kotori.git"
|
|
56
|
+
},
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/tylim88/kotori/issues"
|
|
59
|
+
},
|
|
60
|
+
"author": "tylim88",
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"react": ">=19.2.5"
|
|
64
|
+
}
|
|
65
|
+
}
|