@humanforest/tokens 0.3.5 → 0.3.7
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 +18 -0
- package/package.json +2 -1
- package/src/glyphs.ts +4 -4
- package/src/sublogoSvg.ts +7 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Every @humanforest package shares one version, so one entry covers all seven packages. Newest first.
|
|
4
|
+
|
|
5
|
+
## 0.3.7 — 2026-09-13
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **ui**: add FMapContextMenu, a right-click menu on the map
|
|
10
|
+
- **charts**: chart frames and sparklines can be named for screen readers
|
|
11
|
+
|
|
12
|
+
### Fixes
|
|
13
|
+
|
|
14
|
+
- **charts**: CellScale types what useCellScale returns
|
|
15
|
+
- **charts**: an empty distribution bar is still named, as "No data"
|
|
16
|
+
- **charts**: a bar sparkline warns that :curve="false" is ignored
|
|
17
|
+
- **charts**: a sparkline leaves non-finite readings off its scale
|
|
18
|
+
- **tokens**: the sub-logo builder passes noUncheckedIndexedAccess
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humanforest/tokens",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Forest design tokens — the OKLCH colour engine (src/colourEngine.ts) plus the CSS + JSON it generates via scripts/{scales,type,motion,deck,dataviz,logo}.ts, and the logo SVGs. The generated files are framework-agnostic; do not edit them by hand, run `bun run build`.",
|
|
5
5
|
"files": [
|
|
6
|
+
"CHANGELOG.md",
|
|
6
7
|
"glyphs",
|
|
7
8
|
"scales",
|
|
8
9
|
"type",
|
package/src/glyphs.ts
CHANGED
|
@@ -14,7 +14,7 @@ import glyphAtlas from '../glyphs/glyphs.json';
|
|
|
14
14
|
import { WORDMARK_PATHS, F } from './logo';
|
|
15
15
|
|
|
16
16
|
type Glyph = { d?: string; advance: number; x1?: number; y1?: number; x2?: number; y2?: number };
|
|
17
|
-
type Atlas = Record<
|
|
17
|
+
type Atlas = Record<FontKey, { upm: number; glyphs: Record<string, Glyph> }>;
|
|
18
18
|
const ATLAS = glyphAtlas as unknown as Atlas;
|
|
19
19
|
|
|
20
20
|
export type FontKey = 'gt' | 'mohr';
|
|
@@ -77,8 +77,8 @@ export function setWord(
|
|
|
77
77
|
// lands WORDMARK_F_GAP away — calibrated on the f→o pair the wordmark itself defines.
|
|
78
78
|
const gtF = ATLAS.gt.glyphs['f'];
|
|
79
79
|
const gtO = ATLAS.gt.glyphs['o'];
|
|
80
|
-
const fLsb = (gtF
|
|
81
|
-
const fAdvance = fLsb + F.w + (WORDMARK_F_GAP - (gtO
|
|
80
|
+
const fLsb = (gtF?.x1 ?? 0) * (size / ATLAS.gt.upm);
|
|
81
|
+
const fAdvance = fLsb + F.w + (WORDMARK_F_GAP - (gtO?.x1 ?? 0) * (size / ATLAS.gt.upm));
|
|
82
82
|
|
|
83
83
|
const out: PlacedGlyph[] = [];
|
|
84
84
|
let pen = x;
|
|
@@ -91,7 +91,7 @@ export function setWord(
|
|
|
91
91
|
for (const ch of text) {
|
|
92
92
|
if (brandF && ch === 'f') {
|
|
93
93
|
// the artwork, authored in wordmark units with its baseline at F.h — no scaling, it IS the size
|
|
94
|
-
out.push({ d: WORDMARK_PATHS[0]
|
|
94
|
+
out.push({ d: WORDMARK_PATHS[0]!, transform: `translate(${round(pen + fLsb)} ${round(baseline - F.h)})`, cut: false });
|
|
95
95
|
extend(pen + fLsb, baseline - F.h, pen + fLsb + F.w, baseline);
|
|
96
96
|
pen += fAdvance;
|
|
97
97
|
continue;
|
package/src/sublogoSvg.ts
CHANGED
|
@@ -17,7 +17,11 @@ import {
|
|
|
17
17
|
} from './sublogo';
|
|
18
18
|
|
|
19
19
|
const ramps = rj as unknown as Record<string, { levels: Record<number, { hex: string; p3: string }> }>;
|
|
20
|
-
const level = (family: string, lvl: number) =>
|
|
20
|
+
const level = (family: string, lvl: number) => {
|
|
21
|
+
const colour = ramps[family]?.levels[lvl];
|
|
22
|
+
if (!colour) throw new Error(`sublogoSvg: the ramps have no ${family} ${lvl}`);
|
|
23
|
+
return colour;
|
|
24
|
+
};
|
|
21
25
|
const fillOf = (family: string, lvl: number) => {
|
|
22
26
|
const { hex, p3 } = level(family, lvl);
|
|
23
27
|
return `fill="${hex}" style="fill:${hex};fill:${p3};fill-opacity:1;"`;
|
|
@@ -106,9 +110,9 @@ export function buildIconSvg(seed: SubBrand, { classes = true } = {}): { svg: st
|
|
|
106
110
|
|
|
107
111
|
const ic = iconGeometry();
|
|
108
112
|
const upper = seed.word.toUpperCase();
|
|
109
|
-
const probe = setWord(upper
|
|
113
|
+
const probe = setWord(upper.charAt(0), { font: 'mohr', size: SUBLOGO_MOHR_SIZE });
|
|
110
114
|
const size = (SUBLOGO_MOHR_SIZE * ic.letterCap) / (probe.inkBottom - probe.inkTop);
|
|
111
|
-
const run = setWord(upper
|
|
115
|
+
const run = setWord(upper.charAt(0), { font: 'mohr', size });
|
|
112
116
|
const x = ic.cx - (run.inkLeft + (run.inkRight - run.inkLeft) / 2);
|
|
113
117
|
const y = ic.cy - (run.inkTop + (run.inkBottom - run.inkTop) / 2);
|
|
114
118
|
|