@ekanos/ui 0.1.0 → 0.1.1

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
@@ -119,6 +119,5 @@ pnpm --filter @ekanos/ui pack:test # clean-room publish gate (see scripts/pack-
119
119
  into a temp project outside the workspace and typechecks
120
120
  (`skipLibCheck: false`) + esbuild-bundles a consumer importing every subpath.
121
121
 
122
- The package is `private: true` until the owner flips it for the first publish;
123
- `prepack` runs the build so a publish can never ship a stale or missing
122
+ `prepack` runs the build, so a publish can never ship a stale or missing
124
123
  `dist/`.
package/dist/trans.d.ts CHANGED
@@ -25,14 +25,52 @@ type TransProps = ComponentProps<typeof Trans$1>;
25
25
  *
26
26
  * Verified against react-i18next 16.5.4: when no instance is passed via the
27
27
  * `i18n` prop and none has been registered globally, the component logs a
28
- * one-time `NO_I18NEXT_INSTANCE` console warning and returns its children
29
- * unmodified. It does not throw.
30
- *
31
- * Note the sharp edge this implies: the fallback is **children**, not
32
- * `defaults`. `<Trans i18nKey="a.b" defaults="Continue" />` has no children, so
33
- * with no instance available it renders nothing at all. Supply children when a
34
- * string must survive an unconfigured host:
35
- * `<Trans i18nKey="a.b" defaults="Continue">Continue</Trans>`.
28
+ * one-time `NO_I18NEXT_INSTANCE` console warning and returns its **children**
29
+ * unmodified not `defaults`. Every SDK call site passes `i18nKey` +
30
+ * `defaults` and no children, so unpatched that renders nothing at all in any
31
+ * host without i18next (a partner's Storybook, a bare unit test). Inside Fusion
32
+ * and the harness it never shows, which is how it reached 0.1.0.
33
+ *
34
+ * We therefore detect that fall-through and render `defaults` ourselves.
35
+ *
36
+ * ### How the no-instance case is detected
37
+ *
38
+ * Not by asking `getI18n()`, because from here we cannot. It is not exported
39
+ * from `react-i18next/TransWithoutContext`, and react-i18next's `exports` map
40
+ * lists only `.`, `./TransWithoutContext`, `./initReactI18next`, `./icu.macro`
41
+ * and `./package.json`, so a deep import is refused. Reaching it through the
42
+ * main entry would drag in `context.js`, which calls `createContext()` at
43
+ * module scope — and under the `react-server` condition React 19 exports
44
+ * `createContext: undefined`, which would cost this module the
45
+ * RSC-renderability that is its whole reason for using this entry point.
46
+ *
47
+ * What is available is the library's own signal: with no instance it returns
48
+ * the `children` prop BY REFERENCE, and with an instance it returns
49
+ * `renderNodes(...)`, which never is that reference. Reusing react-i18next's
50
+ * own guard rather than reimplementing its condition means the two cannot
51
+ * drift apart across upgrades, and its module-level warn-once still owns the
52
+ * warning, so nothing warns twice.
53
+ *
54
+ * ### Why not simply pass `defaults` as children
55
+ *
56
+ * Because it has a measurable regression in the no-instance branch: children
57
+ * are exactly what react-i18next returns there, so injected `defaults` would
58
+ * override children a caller actually supplied. There is a test for that.
59
+ *
60
+ * The reason usually given for avoiding it — that children flip
61
+ * `interpolationOverride` (react-i18next rewrites the interpolation delimiters
62
+ * to `#$?…?$#` when `values` and `count` are absent but children are present)
63
+ * and also feed `getValuesFromChildren` — is real in the source but, measured,
64
+ * is NOT observable: `renderNodes` re-interpolates afterwards, and injecting
65
+ * `defaults` as children produced byte-identical output across `values`,
66
+ * `tOptions`, `components`, plural-via-`count`, and
67
+ * missing-key-falls-back-to-`defaults`. That argument should not be repeated
68
+ * as fact.
69
+ *
70
+ * The approach below sidesteps the question entirely: it forwards the caller's
71
+ * props untouched and injects nothing, so the with-instance path is identical
72
+ * by construction rather than identical across whichever cases someone
73
+ * happened to try.
36
74
  */
37
75
  declare function Trans(props: TransProps): React.JSX.Element;
38
76
 
package/dist/trans.js CHANGED
@@ -1,8 +1,14 @@
1
1
  // src/_impl/trans.tsx
2
2
  import { Trans as I18nTrans } from "react-i18next/TransWithoutContext";
3
- import { jsx } from "react/jsx-runtime";
3
+ import { Fragment, jsx } from "react/jsx-runtime";
4
+ var renderI18nTrans = I18nTrans;
4
5
  function Trans(props) {
5
- return /* @__PURE__ */ jsx(I18nTrans, { ...props });
6
+ const rendered = renderI18nTrans(props);
7
+ const fellThroughToChildren = rendered === props.children && props.children == null;
8
+ if (fellThroughToChildren && typeof props.defaults === "string") {
9
+ return /* @__PURE__ */ jsx(Fragment, { children: props.defaults });
10
+ }
11
+ return /* @__PURE__ */ jsx(Fragment, { children: rendered });
6
12
  }
7
13
  export {
8
14
  Trans
package/package.json CHANGED
@@ -1,17 +1,11 @@
1
1
  {
2
2
  "name": "@ekanos/ui",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "Fusion-styled UI primitives for building Ekanos integrations outside the monorepo. A curated, published slice of the internal @kit/ui library.",
6
6
  "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/companydotcom/fusion.git",
10
- "directory": "packages/ekanos-ui"
11
- },
12
- "homepage": "https://github.com/companydotcom/fusion/tree/dev/packages/ekanos-ui#readme",
13
7
  "bugs": {
14
- "url": "https://github.com/companydotcom/fusion/issues"
8
+ "email": "npm@govastly.com"
15
9
  },
16
10
  "sideEffects": false,
17
11
  "files": [
@@ -102,6 +96,7 @@
102
96
  },
103
97
  "dependencies": {
104
98
  "@base-ui/react": "1.6.0",
99
+ "@types/json-schema": "^7.0.15",
105
100
  "ai": "^6.0.197",
106
101
  "class-variance-authority": "^0.7.1",
107
102
  "clsx": "^2.1.1",
@@ -126,10 +121,11 @@
126
121
  "react-hook-form": "^7.68.0",
127
122
  "tsup": "8.5.1",
128
123
  "typescript": "^5.9.3",
129
- "@kit/eslint-config": "0.2.0",
130
- "@kit/ui": "0.1.0",
124
+ "vitest": "4.1.10",
131
125
  "@kit/prettier-config": "0.1.0",
132
- "@kit/tsconfig": "0.1.0"
126
+ "@kit/tsconfig": "0.1.0",
127
+ "@kit/ui": "0.1.0",
128
+ "@kit/eslint-config": "0.2.0"
133
129
  },
134
130
  "prettier": "@kit/prettier-config",
135
131
  "typesVersions": {
@@ -145,6 +141,7 @@
145
141
  "format": "prettier --check \"**/*.{ts,tsx,mjs}\"",
146
142
  "lint": "eslint .",
147
143
  "typecheck": "tsc --noEmit",
144
+ "test": "vitest run --config vitest.config.ts",
148
145
  "pack:test": "node scripts/pack-test.mjs"
149
146
  }
150
147
  }