Skip to content

Commit bcbd158

Browse files
chore: version packages
1 parent 6e2d42d commit bcbd158

3 files changed

Lines changed: 156 additions & 160 deletions

File tree

.changeset/glaze-color-value-shorthand.md

Lines changed: 0 additions & 159 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,160 @@
11
# @tenphi/glaze
22

3+
## 0.10.0
4+
5+
### Minor Changes
6+
7+
- [#50](https://github.com/tenphi/glaze/pull/50) [`6e2d42d`](https://github.com/tenphi/glaze/commit/6e2d42dac6aa571ec02636bd029c662b2bf7fa3f) Thanks [@tenphi](https://github.com/tenphi)! - Revamp `glaze.color()` with a value-shorthand overload, seed-anchored
8+
contrast solving, a per-call lightness-scaling argument, and a `.css()`
9+
export. `glaze.shadow()` now accepts the same value forms as `glaze.color()`.
10+
11+
**New defaults for `glaze.color()`** — split by input form so end-user
12+
string values (color picker / theme settings) get a natural light/dark
13+
inversion, while programmatic object / tuple / structured inputs keep
14+
predictable linear behavior:
15+
- **String value-shorthand** (hex, `rgb()`, `hsl()`, `okhsl()`,
16+
`oklch()`): `mode: 'auto'` with snapshotted scaling
17+
`{ lightLightness: false, darkLightness: [globalConfig.darkLightness[0], 100] }`.
18+
Light preserves the input exactly; dark Möbius-inverts up to `100`,
19+
so `glaze.color('#000')` renders as `#fff` in dark mode and
20+
`glaze.color('#fff')` falls to the dark `lo` floor (default `0.15`).
21+
The dark `lo` is snapshotted from `globalConfig` at color-creation
22+
time, matching how an explicit `scaling.darkLightness: [lo, hi]`
23+
behaves.
24+
- **Object / tuple value-shorthand** (`{ h, s, l }`, `[r, g, b]`) and
25+
**structured form**: `mode: 'fixed'` with light preserved and dark
26+
linearly mapped into `globalConfig.darkLightness` (default `[15, 95]`),
27+
also snapshotted at create time so later `glaze.configure()` calls
28+
don't retroactively change already-created tokens.
29+
- Override per call via the new third positional argument
30+
`GlazeColorScaling`: `{ lightLightness?: false | [lo, hi]; darkLightness?: false | [lo, hi] }`.
31+
`false` disables the remap, a tuple sets a custom window. To opt
32+
string inputs back into the previous fixed-linear default, pass
33+
`{ mode: 'fixed' }` as the second arg or supply an explicit
34+
`scaling`.
35+
36+
**Behavior change (minor bump):**
37+
- String value-shorthand callers will see a Möbius-inverted dark
38+
variant by default — `glaze.color('#000').resolve().dark.l` is now
39+
`≈ 1.0`, not `0.15`. To preserve the old fixed-linear behavior pass
40+
`{ mode: 'fixed' }` as the second argument.
41+
- Structured callers without an explicit `mode` will see
42+
`glaze.color({...}).resolve().light.l` match the input lightness
43+
exactly instead of being remapped to `globalConfig.lightLightness`.
44+
To preserve the old behavior pass
45+
`{ lightLightness: globalConfig.lightLightness }` as the second
46+
argument.
47+
- The default lightness windows for object / tuple / structured
48+
inputs are now snapshotted from `globalConfig.darkLightness` at
49+
color-creation time, matching the existing behavior for string
50+
inputs. Tokens created before a `glaze.configure()` call no longer
51+
pick up the new dark window on their next `.resolve()`. To get the
52+
old "live config" behavior, recreate the token after `configure()`.
53+
54+
**Value shorthand additions:**
55+
- Accepts hex (`#rgb` / `#rrggbb` / `#rrggbbaa`), the four CSS color
56+
functions Glaze itself emits (`rgb()`, `hsl()`, `okhsl()`, `oklch()`),
57+
`OkhslColor` objects (`{ h, s, l }`), and `[r, g, b]` (0–255) tuples
58+
as the first argument. Every string emitted by `theme.tasty() / .json() / .css()`
59+
round-trips back through `glaze.color()`.
60+
- 8-digit hex and `rgba()` / `hsla()` / slash-alpha alpha components are
61+
parsed and dropped with a `console.warn` (standalone colors have no
62+
opacity field).
63+
- `oklch()` chroma now correctly interprets percent values per CSS Color 4
64+
(`100% → 0.4`).
65+
- `OkhslColor` and `[r, g, b]` inputs are validated up front with helpful
66+
error messages — passing 0–100-scale `s`/`l` throws with a hint to use
67+
the structured form, and out-of-range RGB tuples throw with the offending
68+
value in the message.
69+
70+
**Anchor model:** by default, relative `lightness: '+N'` and
71+
`contrast: <ratio>` are anchored to the literal seed (the value passed
72+
to `glaze.color()`), so the contrast solver compares against the
73+
unmapped user-provided color across every variant. Pass
74+
`overrides.base` (a `GlazeColorToken`) to anchor against another
75+
color's resolved variant per scheme instead.
76+
77+
**Color pairing via `base`:** `GlazeColorOverrides.base` lets one
78+
standalone color depend on another. Accepts either a `GlazeColorToken`
79+
or any `GlazeColorValue` (hex / `rgb()` / `OkhslColor` / `[r, g, b]`);
80+
raw values are auto-wrapped via `glaze.color(value)` and inherit the
81+
same string-vs-object defaults. When set:
82+
- `contrast` is solved per scheme against the base's resolved variant
83+
(light / dark / lightContrast / darkContrast).
84+
- Relative `lightness: '+N'` / `'-N'` is anchored to the base's
85+
lightness per scheme (matches theme behavior for dependent colors).
86+
- Relative `hue: '+N'` still anchors to the seed (the value passed to
87+
`glaze.color()`), not the base.
88+
- `mode` is the per-pair knob — pass `mode: 'fixed'` to disable Möbius
89+
inversion for the dependent color, `mode: 'auto'` to keep it.
90+
91+
The base token's `.resolve()` is called lazily on first resolve and
92+
the result is captured by reference, matching existing snapshot
93+
semantics. Internally, `resolveAllColors` accepts pre-resolved
94+
external bases and seeds them into the resolution context;
95+
`validateColorDefs` and `topoSort` treat external base names as leaves.
96+
97+
**`opacity` and `name` on `glaze.color()`:**
98+
- `GlazeColorOverrides.opacity` (and the same field on
99+
`GlazeColorInput`) sets a fixed alpha 0–1 that surfaces in every
100+
scheme variant. Combining with `contrast` is not recommended (perceived
101+
lightness becomes unpredictable) — `glaze` emits a `console.warn` in
102+
that case.
103+
- `GlazeColorOverrides.name` (and the same field on `GlazeColorInput`)
104+
is a human-readable label that surfaces in error and warning messages
105+
in place of the internal `"value"` sentinel. Empty / whitespace-only
106+
names and reserved internal names (`"value"`, `"seed"`,
107+
`"externalBase"`) are rejected with a clear error.
108+
109+
**Structured form parity:** the `glaze.color({...})` overload now
110+
accepts `opacity`, `contrast`, `base`, and `name` in addition to the
111+
existing `hue`, `saturation`, `lightness`, `saturationFactor`, and
112+
`mode`. `contrast` without `base` synthesizes a hidden static seed
113+
from the input's normal-mode lightness so the contrast solver always
114+
has an anchor (mirrors value-form behavior). `hue` (finite),
115+
`saturation` / `lightness` (0–100), `saturationFactor` (0–1), and
116+
`opacity` (0–1) are range-checked up front with helpful error
117+
messages — non-finite or out-of-range values fail at creation rather
118+
than producing a NaN-laden token.
119+
120+
**Contrast warning:** when the contrast solver cannot meet the
121+
requested target (e.g. AAA against a mid-grey base — physically
122+
unreachable), `glaze` emits a single `console.warn` per
123+
`(name, scheme, target)` triple naming the affected color, scheme, and
124+
the actual achieved ratio. The token still resolves to the closest
125+
passing variant. Use the `name` override to make the warning easier to
126+
trace.
127+
128+
**Persisting standalone colors:** `token.export()` returns a JSON-safe
129+
snapshot containing the original `value` (or structured input), the
130+
overrides, and the captured `scaling`. Token-typed `base` is
131+
recursively serialized; value-typed `base` is preserved as the raw
132+
value. Pass the result to `glaze.colorFrom(data)` to rehydrate a token
133+
that resolves byte-for-byte identically to the original — across
134+
`glaze.configure()` calls and across processes. The captured `scaling`
135+
snapshots both `lightLightness` and `darkLightness` from `globalConfig`
136+
at create time, so later `glaze.configure()` calls don't retroactively
137+
change exported tokens regardless of input form.
138+
139+
**`.css({ name })` export:** new method on the standalone color token
140+
reaches export parity with `theme.css()`. Existing
141+
`.token() / .tasty() / .json()` continue to work unchanged.
142+
143+
**`glaze.shadow()` upgrade:** `bg` and `fg` now accept any
144+
`GlazeColorValue` form — hex, `rgb()` / `hsl()` / `okhsl()` / `oklch()`
145+
strings, `OkhslColor` objects, or `[r, g, b]` tuples — sharing the same
146+
parser as `glaze.color()`.
147+
148+
**Internal:** standalone color tokens now memoize the underlying resolve
149+
across `.resolve() / .token() / .tasty() / .json() / .css()` calls.
150+
151+
**Public type additions:** `GlazeColorValue`, `GlazeColorOverrides`,
152+
`GlazeColorOverridesExport`, `GlazeColorCssOptions`,
153+
`GlazeColorScaling`, `GlazeColorTokenExport`, `GlazeColorInputExport`.
154+
New `glaze.colorFrom(data)` factory and `token.export()` method on
155+
`GlazeColorToken`. New `hslToSrgb`, `oklabToOkhsl`, and `parseHexAlpha`
156+
math helpers re-exported from the package root.
157+
3158
## 0.9.3
4159

5160
### Patch Changes

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tenphi/glaze",
3-
"version": "0.9.3",
3+
"version": "0.10.0",
44
"description": "OKHSL-based color theme generator with WCAG contrast solving for light, dark, and high-contrast schemes",
55
"type": "module",
66
"main": "./dist/index.cjs",

0 commit comments

Comments
 (0)