@hideyukimori/nene2-ui 0.6.0 → 0.8.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 +43 -1
- package/dist/primitives/Input.js +1 -1
- package/dist/primitives/Input.js.map +1 -1
- package/dist/primitives/Select.js +1 -1
- package/dist/primitives/Select.js.map +1 -1
- package/dist/primitives/Textarea.js +1 -1
- package/dist/primitives/Textarea.js.map +1 -1
- package/package.json +1 -1
- package/themes/default.css +61 -2
package/README.md
CHANGED
|
@@ -153,7 +153,16 @@ component follows.
|
|
|
153
153
|
|
|
154
154
|
### ① The scale — 🔒 do not redefine
|
|
155
155
|
|
|
156
|
-
`--spacing-x-3xs` … `--spacing-x-2xl`,
|
|
156
|
+
`--spacing-x-3xs` … `--spacing-x-2xl`, `--radius-x-none` … `--radius-x-3xl` plus
|
|
157
|
+
`--radius-x-pill`, `--text-x-2xs` … `--text-x-xl`, and the colour palette.
|
|
158
|
+
|
|
159
|
+
🔴 **A namespace with one step has no slots, only aliases.** Until 0.8.0 the radius
|
|
160
|
+
namespace held a single value and eight slots pointed at it, so a product following the
|
|
161
|
+
rules could render exactly one rounding — and every structural check passed, because the
|
|
162
|
+
slots existed and their defaults referenced the scale. The scale had been promoted verbatim
|
|
163
|
+
from the one product with the fewest conformance violations, which turned out to be the
|
|
164
|
+
product with the fewest choices. **A component implementation may come from one ship; the
|
|
165
|
+
set of choices may only come from the fleet's distribution.**
|
|
157
166
|
|
|
158
167
|
```css
|
|
159
168
|
--spacing-x-slot-card-pad: 1.375rem; /* 🔴 no */
|
|
@@ -177,8 +186,41 @@ to match it also fits _worse_, not better:
|
|
|
177
186
|
More exact matches, five times the worst error — a scale bent toward one histogram drops its
|
|
178
187
|
own ends.
|
|
179
188
|
|
|
189
|
+
The radius scale was measured the same way, across the 266 radius values ten products apply
|
|
190
|
+
(2026-08-23). Candidates were scored on a second axis as well: whether two values that exist
|
|
191
|
+
**by design** land on the same step. Average error alone would have accepted folding `2px`
|
|
192
|
+
into `0`, because 2px is a 2px error — but nene-records ships nine themes at 0px and three at
|
|
193
|
+
2–3px as separate product themes, so that error deletes a distinction rather than rounding
|
|
194
|
+
one.
|
|
195
|
+
|
|
196
|
+
| radius scale | exact match | within 2px | designed values collapsed |
|
|
197
|
+
| --------------------------- | ----------: | ---------: | ------------------------: |
|
|
198
|
+
| **the kit's nine + pill** | **69.9%** | **97.7%** | **3** (all 1px apart) |
|
|
199
|
+
| eight, without a `10px` step | 64.3% | 97.7% | 4 |
|
|
200
|
+
| seven, without `2px` | 43.2% | 97.7% | 4 |
|
|
201
|
+
|
|
202
|
+
🔑 **A scale is judged by what it can still tell apart, not only by how far it moves things.**
|
|
203
|
+
|
|
180
204
|
🔑 **The scale is the set you keep to. The slots are what your brand looks like.**
|
|
181
205
|
|
|
206
|
+
### 🔴 One slot is not yours to tune
|
|
207
|
+
|
|
208
|
+
`--text-x-slot-control-touch-size` is a **device constraint, not a design choice**. iOS Safari
|
|
209
|
+
zooms the whole page when a focused control is under 16px, so lowering this brings that back.
|
|
210
|
+
|
|
211
|
+
It is a slot at all only because the kit cannot know your rem base — not because the value is
|
|
212
|
+
open. Set `--text-x-slot-control-size` to whatever suits your body text; leave the touch one
|
|
213
|
+
pointing at `--text-x-ios-floor`.
|
|
214
|
+
|
|
215
|
+
Until 0.7.0 the kit wrote this as `max(var(--text-x-md), var(--text-x-ios-floor))`, which is
|
|
216
|
+
the same idea expressed in a way that cannot work: `max()` picks the larger number and cannot
|
|
217
|
+
ask what kind of device it is on, so every desktop control was pushed to 16px too — visibly
|
|
218
|
+
larger than the text beside it in any product whose body is 14px. The two slots split that
|
|
219
|
+
into "the size you chose" and "the floor the device imposes", and the components apply the
|
|
220
|
+
second only under `@media (pointer: coarse)`.
|
|
221
|
+
|
|
222
|
+
🔑 **Pointer, not width.** An iPad in landscape is wide and still zooms.
|
|
223
|
+
|
|
182
224
|
### Composing a slot
|
|
183
225
|
|
|
184
226
|
A slot can hold several steps — four-sided padding is just CSS:
|
package/dist/primitives/Input.js
CHANGED
|
@@ -3,7 +3,7 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
import { cx } from '../lib/cx.js';
|
|
4
4
|
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
5
|
import { useFieldWiring } from '../forms/field-context.js';
|
|
6
|
-
const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
|
|
6
|
+
const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size pointer-coarse:text-x-slot-control-touch-size text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
|
|
7
7
|
/**
|
|
8
8
|
* Text input primitive. forwardRef so it works directly with react-hook-form `register`.
|
|
9
9
|
* Visual values come from theme tokens only.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/primitives/Input.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4B,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/primitives/Input.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4B,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,uPAAuP,aAAa,EAAE,CAAC;AAE1R;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EACE,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,gBAAO,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AACzF,CAAC,CAAC,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
import { cx } from '../lib/cx.js';
|
|
4
4
|
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
5
|
import { useFieldWiring } from '../forms/field-context.js';
|
|
6
|
-
const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size text-text-primary ${CONTROL_CLASS}`;
|
|
6
|
+
const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size pointer-coarse:text-x-slot-control-touch-size text-text-primary ${CONTROL_CLASS}`;
|
|
7
7
|
/**
|
|
8
8
|
* Select primitive. forwardRef so it works directly with react-hook-form `register`.
|
|
9
9
|
* Visual values come from theme tokens only.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","sourceRoot":"","sources":["../../src/primitives/Select.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6C,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAM3D,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"Select.js","sourceRoot":"","sources":["../../src/primitives/Select.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6C,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAM3D,MAAM,UAAU,GAAG,2NAA2N,aAAa,EAAE,CAAC;AAE9P;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EACE,QAAQ,EACR,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,CACL,iBAAQ,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,YACzE,QAAQ,GACF,CACV,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { forwardRef } from 'react';
|
|
|
3
3
|
import { cx } from '../lib/cx.js';
|
|
4
4
|
import { CONTROL_CLASS } from '../lib/states.js';
|
|
5
5
|
import { useFieldWiring } from '../forms/field-context.js';
|
|
6
|
-
const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
|
|
6
|
+
const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size pointer-coarse:text-x-slot-control-touch-size text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
|
|
7
7
|
/**
|
|
8
8
|
* Multi-line text input. Deliberately identical to `Input` apart from the element, so the
|
|
9
9
|
* two never drift: five ships wrote their own `Textarea.tsx` and the kit shipped without
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.js","sourceRoot":"","sources":["../../src/primitives/Textarea.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA+B,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"Textarea.js","sourceRoot":"","sources":["../../src/primitives/Textarea.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA+B,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,uPAAuP,aAAa,EAAE,CAAC;AAE1R;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAqC,SAAS,QAAQ,CACtF,EACE,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,mBAAU,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AAC5F,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hideyukimori/nene2-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "NeNe fleet shared React UI kit — token-driven primitives on Tailwind v4 @theme. Components carry no design of their own; themes do.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/themes/default.css
CHANGED
|
@@ -138,8 +138,24 @@
|
|
|
138
138
|
--color-x-slot-field-error: var(--color-danger);
|
|
139
139
|
--text-x-slot-field-error-size: var(--text-x-2xs);
|
|
140
140
|
--text-x-slot-field-label-size: var(--text-x-xs);
|
|
141
|
-
--font-weight-
|
|
142
|
-
|
|
141
|
+
/* 🔴 `var(--font-weight-medium)`, not `500`. Identical output — Tailwind defines that
|
|
142
|
+
* step as 500 — but a literal here is a weight the kit invented, and the namespace has a
|
|
143
|
+
* nine-step scale already (thin…black). This one escaped the "slot defaults are scale
|
|
144
|
+
* references only" check because that check listed the namespaces it knew about; found
|
|
145
|
+
* while adding the radius scale (#348). */
|
|
146
|
+
--font-weight-x-slot-field-label: var(--font-weight-medium);
|
|
147
|
+
/* Control text. Two slots, because one value cannot answer "how is this being pointed at".
|
|
148
|
+
*
|
|
149
|
+
* 0.6.0 used `max(var(--text-x-md), var(--text-x-ios-floor))`, which raised every control
|
|
150
|
+
* to 16px — including on a desktop whose body text is 14px, where the inputs then look
|
|
151
|
+
* oversized next to everything else (found by hide on a real screen, 2026-08-23). `max()`
|
|
152
|
+
* cannot ask what kind of device it is on; it only ever picks the larger number.
|
|
153
|
+
*
|
|
154
|
+
* 🔴 The touch slot is a device constraint, not a design choice. iOS Safari zooms the whole
|
|
155
|
+
* page when a focused control is under 16px, so lowering it re-introduces that. It is a slot
|
|
156
|
+
* only because the kit cannot know a product's rem base — not because it is yours to tune. */
|
|
157
|
+
--text-x-slot-control-size: var(--text-x-md);
|
|
158
|
+
--text-x-slot-control-touch-size: var(--text-x-ios-floor);
|
|
143
159
|
|
|
144
160
|
/* Sentinel for the consumer's build (#316). Zero-width, so applying it does nothing.
|
|
145
161
|
* Its only job is to exist: `p-x-source-probe` appears nowhere except this kit's `dist`,
|
|
@@ -152,7 +168,50 @@
|
|
|
152
168
|
* gave them nothing (50 x10, 40 x4, 30 x6, measured 2026-08-23 across 20 uses). */
|
|
153
169
|
--opacity-x-disabled: 50%;
|
|
154
170
|
|
|
171
|
+
/* The radius scale. Nine steps plus pill, chosen the same way the spacing scale was —
|
|
172
|
+
* by measuring the fleet, not by taste. Snapping the 266 radius values the fleet actually
|
|
173
|
+
* applies (`border-radius` declarations and `--radius-*` theme tokens across ten products,
|
|
174
|
+
* 2026-08-23, #348) onto these nine puts 69.9% exactly on a step and 97.7% within 2px.
|
|
175
|
+
*
|
|
176
|
+
* 🔴 This replaces a scale that had ONE step. Eight slots all pointed at `--radius-x-md`,
|
|
177
|
+
* so a product following the rules could only ever render 8px — and a slot whose value set
|
|
178
|
+
* has one member is not a slot. The cause is recorded because it generalizes: the kit's
|
|
179
|
+
* theme was promoted verbatim from nene-payout, and payout is the fleet's only product
|
|
180
|
+
* with a single radius. Promoting from the product with the fewest conformance violations
|
|
181
|
+
* exported its poverty as the norm — having no choices is not the same as choosing well.
|
|
182
|
+
* A component implementation may come from one ship; the SET OF CHOICES may not.
|
|
183
|
+
*
|
|
184
|
+
* 🔴 `2px` is its own step because it is the single most common radius in the fleet
|
|
185
|
+
* (56 of 266). nene-records ships 9 themes at 0px and 3 at 2-3px as separate product
|
|
186
|
+
* themes — so folding 2px into 0 would not be a rounding error, it would delete a
|
|
187
|
+
* distinction somebody drew on purpose. Candidate scales were therefore scored on a
|
|
188
|
+
* second axis besides average error: whether two values that exist by design collapse
|
|
189
|
+
* onto one step (vault's proposal). The steps kept apart here are 0/2, 6/8 and 10/12;
|
|
190
|
+
* what still collapses (3-4, 5-6, 9-10) is 1px apart, below a scale's resolution.
|
|
191
|
+
*
|
|
192
|
+
* `--radius-x-md` keeps the value it had. Every slot points at it, so changing it would
|
|
193
|
+
* move every product's appearance silently — the scale gains steps, the default does not
|
|
194
|
+
* move. */
|
|
195
|
+
--radius-x-none: 0;
|
|
196
|
+
--radius-x-2xs: 2px;
|
|
197
|
+
--radius-x-xs: 4px;
|
|
198
|
+
--radius-x-sm: 6px;
|
|
155
199
|
--radius-x-md: 0.5rem;
|
|
200
|
+
--radius-x-lg: 10px;
|
|
201
|
+
--radius-x-xl: 12px;
|
|
202
|
+
--radius-x-2xl: 16px;
|
|
203
|
+
--radius-x-3xl: 24px;
|
|
204
|
+
|
|
205
|
+
/* Fully round. A step, not a footnote: `rounded-x-pill` is the most-used radius in
|
|
206
|
+
* nene-field (48 uses) and appears in five products (64 uses total).
|
|
207
|
+
*
|
|
208
|
+
* 🔴 A product whose design language has no rounding does NOT redefine this step — it
|
|
209
|
+
* points its slots at `--radius-x-none`. nene-records reaches the same end today by
|
|
210
|
+
* setting its own `--radius-full: 0px`, which works only because its components hard-code
|
|
211
|
+
* `rounded-full`. Overriding a scale step changes what a name means fleet-wide; overriding
|
|
212
|
+
* a slot changes one product's choice. The second is the mechanism; the first is the drift
|
|
213
|
+
* the scale exists to prevent. */
|
|
214
|
+
--radius-x-pill: 9999px;
|
|
156
215
|
|
|
157
216
|
/* The spacing scale. Nine steps, chosen by measurement rather than taste: snapping the
|
|
158
217
|
* 944 spacing utilities the fleet writes by hand onto these nine moves 98.2% of them by
|