@evanion/react-feature 0.1.0 β†’ 0.1.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,48 @@
1
+ ## 0.1.2 (2026-11-07)
2
+
3
+ ### πŸš€ Features
4
+
5
+ - ⚠️ **react-feature:** re-export the 0.2 condition types ([ac261cfa](https://github.com/Evanion/libraries/commit/ac261cfa))
6
+
7
+ ### ⚠️ Breaking Changes
8
+
9
+ - **react-feature:** re-export the 0.2 condition types ([ac261cfa](https://github.com/Evanion/libraries/commit/ac261cfa))
10
+ the re-exported `Condition` gains the `exists` and
11
+ `not-exists` ops, so an exhaustive switch over `Condition['op']` stops
12
+ compiling, and `AttributeCondition` and `SerializedAttributeCondition`
13
+ are unions, so code reading `value` narrows on `op` first.
14
+ `ContextSchema.fields` keys are paths, and `RuleOutcome.failed.value` is
15
+ optional.
16
+
17
+ ### 🧱 Updated Dependencies
18
+
19
+ - Updated @evanion/feature to 0.2.0
20
+
21
+ ### ❀️ Thank You
22
+
23
+ - Mikael Pettersson @Evanion
24
+
25
+ ## 0.1.1 (2026-11-05)
26
+
27
+ ### πŸš€ Features
28
+
29
+ - **docs:** show a short sample from its own tested region ([68fa945c](https://github.com/Evanion/libraries/commit/68fa945c))
30
+
31
+ ### πŸ“– Documentation
32
+
33
+ - **react-feature:** open on the flags living in your repo ([46ee7f90](https://github.com/Evanion/libraries/commit/46ee7f90))
34
+ - **repo:** link the documentation at libs.evanion.com/docs ([dc18dbb2](https://github.com/Evanion/libraries/commit/dc18dbb2))
35
+ - **react-feature:** open the readme on its family's promise ([66d2eefd](https://github.com/Evanion/libraries/commit/66d2eefd))
36
+ - **react-feature:** give the readme gemma's npm landing-page shape ([c7872824](https://github.com/Evanion/libraries/commit/c7872824))
37
+
38
+ ### 🧱 Updated Dependencies
39
+
40
+ - Updated @evanion/feature to 0.1.1
41
+
42
+ ### ❀️ Thank You
43
+
44
+ - Mikael Pettersson @Evanion
45
+
1
46
  ## 0.1.0 (2026-10-17)
2
47
 
3
48
  ### πŸš€ Features
package/README.md CHANGED
@@ -1,31 +1,8 @@
1
1
  # @evanion/react-feature
2
2
 
3
- **Feature decisions for your React component tree, resolved once and read anywhere.**
3
+ **Feature flags that live in your repo. Your own code decides if a feature is onβ€”in your API, your build, and the browserβ€”with no network call per check.**
4
4
 
5
- To switch a single banner in a complex UI, you often have to prop-drill a flags object through ten layers of components. `@evanion/react-feature` solves this by publishing the decisions `@evanion/feature` has already resolved. Any component in the tree can ask "is this on, and which variant am I in?" without needing to know where the store or the evaluation context lives.
6
-
7
- ## The Problem: The "Flags Prop-Drill"
8
-
9
- When a server resolves flags for a request, the component that actually needs a specific flag is often buried deep in the hierarchy. This creates two primary frictions:
10
-
11
- 1. **Prop-Drilling**: Components that do not use any flags are forced to carry the flags object simply because a distant child requires it.
12
- 2. **Two Answers Per Request**: If a component resolves a flag for itself, it reads its own clock. This means two components in a single render could land on opposite sides of a time window, causing the page to contradict itself.
13
-
14
- ## The Solution: One Resolution, Published
15
-
16
- `@evanion/feature` resolves every configured feature in one call, and `features.snapshot` states that result as a `DecisionSet` containing the instant of resolution, one decision per key, and the config version wherever the store was built from a document that carries one.
17
-
18
- `FeatureProvider` publishes that set to the React tree, allowing `useFeature`, `useFeatureEnabled`, `useVariant`, and `useFeatures` to read it. Because the decisions are already made, no hook evaluates anything during the render.
19
-
20
- ### Core Concept: The Server Resolves, The Tree Reads
21
-
22
- To avoid duplicating complex logic in the UI, `@evanion/react-feature` separates the act of deciding which feature to show from the act of reading that decision.
23
-
24
- Consider a game shop that splits shoppers between two different shelf-sorting methods. Instead of the UI calculating the split, the server resolves it for a specific shopper via `features.snapshot`, and `FeatureProvider` publishes that set. The `Shelf` component then simply reads its assigned variant. If Sam buckets into `popular` and Mika into `newest`, neither component has to perform the resolution logic themselves.
25
-
26
- To ensure consistency, the provider takes the shopper's targeting context alongside the set. It publishes the shipped decisions either way, and it re-resolves them against that context to check them; consequently, a provider handed no `targetingKey` reports every weighted assignment as one it cannot reproduce. The context the server resolved with is the context the provider needs.
27
-
28
- The following block runs in the package's test suite, where each `// ->` comment denotes the expression's value.
5
+ `@evanion/react-feature` is the React adapter for this ecosystem. It allows you to publish the decisions `@evanion/feature` has already resolved to your component tree, enabling any component to ask "is this on, and which variant am I in?" without prop-drilling a flags object through multiple layers of UI.
29
6
 
30
7
  <!-- #region server-render -->
31
8
 
@@ -118,16 +95,16 @@ shelfFor('mika'); // -> '<p>Newest first</p>'
118
95
 
119
96
  <!-- #endregion server-render -->
120
97
 
121
- ## Key Features
98
+ ## Capabilities
122
99
 
123
100
  `@evanion/react-feature` provides the following capabilities:
124
101
 
125
- - 🧩 **Zero Prop-Drilling**: Components name the key they care about and read the decision from the provider above them.
126
- - πŸ•“ **One Instant Per Render**: A set a render resolved states the instant it was created. The provider reads that instant as the default for anything it resolves itself, ensuring no two components in one tree straddle a time window.
127
- - ⚑ **Local Reads**: Hooks read decisions already held by the provider, so variant switches never wait on network requests.
128
- - πŸ› οΈ **Type-Safety**: `createFeatureContext(features)` returns a provider and hooks bound to one store's schema. Misspelled keys trigger compile errors, and variants are constrained to the union declared by the store.
129
- - 🧬 **Divergence Reports**: When handed a shipped set, a provider compares the config version against the store. It names decisions it cannot reproduce via `onDivergence`. Where the set and the store each carry a config version and the two differ, `onVersionMismatch` decides whether the tree renders the shipped set or a local re-resolution. A store built from a bare definitions array carries no version, so a provider over one reports `unversioned` and keeps the shipped set whatever `onVersionMismatch` asks for. Build both sides from a document that carries a version to make the choice available.
130
- - πŸ“¦ **Lightweight Footprint**: The package is ESM only and requires Node 20 or newer. Its only peer dependency is React 18 or 19, with `@evanion/feature` pinned as a dependency.
102
+ - **Zero Prop-Drilling**: Components name the key they care about and read the decision from the provider above them.
103
+ - **One Instant Per Render**: A set a render resolved states the instant it was created. The provider reads that instant as the default for anything it resolves itself, ensuring no two components in one tree straddle a time window.
104
+ - **Local Reads**: Hooks read decisions already held by the provider, so variant switches never wait on network requests.
105
+ - **Type-Safety**: `createFeatureContext(features)` returns a provider and hooks bound to one store's schema. Misspelled keys trigger compile errors, and variants are constrained to the union declared by the store.
106
+ - **Divergence Reports**: When handed a shipped set, a provider compares the config version against the store. It names decisions it cannot reproduce via `onDivergence`. Where the set and the store each carry a config version and the two differ, `onVersionMismatch` decides whether the tree renders the shipped set or a local re-resolution. A store built from a bare definitions array carries no version, so a provider over one reports `unversioned` and keeps the shipped set whatever `onVersionMismatch` asks for. Build both sides from a document that carries a version to make the choice available.
107
+ - **Lightweight Footprint**: The package is ESM only and requires Node 20 or newer. Its only peer dependency is React 18 or 19, with `@evanion/feature` pinned as a dependency.
131
108
 
132
109
  ## Installation
133
110
 
@@ -141,11 +118,11 @@ npm install @evanion/react-feature @evanion/feature
141
118
 
142
119
  To master the implementation and explore worked examples, visit the full documentation site:
143
120
 
144
- πŸ‘‰ **[docs.evanion.com/react-feature](https://docs.evanion.com/react-feature/)**
121
+ πŸ‘‰ **[libs.evanion.com/docs/react-feature](https://libs.evanion.com/docs/react-feature/)**
145
122
 
146
123
  The `@evanion/react-feature` hooks operate by reading a shared model of features, rules, variants, and decision sets. Because this model is defined in the core package, its detailed documentation is located here:
147
124
 
148
- πŸ‘‰ **[docs.evanion.com/feature](https://docs.evanion.com/feature/)**
125
+ πŸ‘‰ **[libs.evanion.com/docs/feature](https://libs.evanion.com/docs/feature/)**
149
126
 
150
127
  ## License
151
128
 
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createContext as e, useContext as t, useMemo as n, useState as r } from "react";
3
3
  import { adoptDecisions as i, reportDivergence as a } from "@evanion/feature";
4
4
  import { jsx as o } from "react/jsx-runtime";
5
- //#region src/hydrate.ts
5
+ // src/hydrate.ts
6
6
  function s() {
7
7
  try {
8
8
  return process.env.NODE_ENV === "production";
@@ -10,8 +10,7 @@ function s() {
10
10
  return !0;
11
11
  }
12
12
  }
13
- //#endregion
14
- //#region src/index.tsx
13
+ // src/index.tsx
15
14
  function c(e) {
16
15
  return e;
17
16
  }
@@ -114,5 +113,4 @@ function S(t) {
114
113
  }
115
114
  };
116
115
  }
117
- //#endregion
118
116
  export { h as FeatureProvider, S as createFeatureContext, _ as useFeature, v as useFeatureEnabled, g as useFeatures, y as useVariant };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evanion/react-feature",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The React binding for @evanion/feature: a provider and hooks over an already-built feature store.",
5
5
  "keywords": [
6
6
  "react",
@@ -54,7 +54,7 @@
54
54
  "provenance": true
55
55
  },
56
56
  "dependencies": {
57
- "@evanion/feature": "0.1.0"
57
+ "@evanion/feature": "0.2.0"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "react": "^18.0.0 || ^19.0.0"