@domandigital/craft 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @domandigital/craft
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f49922c: A font size in `em` or `%` counts against its own budget, not the type scale's.
8
+
9
+ `code { font-size: 0.875em }` does not add a step to a scale. It states one
10
+ relationship — code is 87.5% of whatever it sits in — and applies it wherever
11
+ code appears. Counting it as a step is the same category error section 9 already
12
+ corrected once for the framework's theme: a number that is not part of the
13
+ vocabulary a reader has to hold.
14
+
15
+ They are still counted, under `maxRelativeFontSizes` (house value 3), because
16
+ the failure they can cause is real — eight competing ratios is as unreadable as
17
+ eight competing steps. Split, not dropped. A value that stops being reported is
18
+ a value that grows.
19
+
20
+ `counts.relativeFontSizes` is new; `counts.fontSizes` now excludes them, so a
21
+ surface using `em` will report a lower scale count than under 0.4.0.
22
+
23
+ Only bare ratios move: `0.875em` and `75%` are relative, `0.875rem` is not, and
24
+ neither is a composite like `max(16px, 1em)`.
25
+
3
26
  ## 0.4.0
4
27
 
5
28
  ### Minor Changes
package/STANDARD.md CHANGED
@@ -113,6 +113,14 @@ Images: AVIF and WebP, in that order.
113
113
  Per surface: **≤10 font sizes, ≤3 weights, ≤2 families** (plus mono),
114
114
  **≤4 radii, ≤4 shadows**, accent hues clustered within **15° OKLCh**.
115
115
 
116
+ A size written in `em` or `%` counts separately, **≤3**. It is a ratio, not a
117
+ step: `code { font-size: 0.875em }` states one relationship and applies it
118
+ wherever code appears, rather than adding a rung to the ladder. Counting it
119
+ against the scale is the same category error as counting the framework's theme.
120
+ It is still counted, because eight competing ratios is as unreadable as eight
121
+ competing steps — split, not dropped. A value that stops being reported is a
122
+ value that grows.
123
+
116
124
  Differentiation guards pass anything that differs from its siblings, however
117
125
  ugly. What they cannot see is accumulation — eighteen font sizes, six shadows,
118
126
  four competing accents, each added reasonably, together reading as noise.
@@ -168,6 +176,7 @@ A rule here has to be one that is wrong to break. Everything else is a default.
168
176
  {
169
177
  "budget": {
170
178
  "maxFontSizes": 10,
179
+ "maxRelativeFontSizes": 3,
171
180
  "maxFontWeights": 3,
172
181
  "maxFontFamilies": 2,
173
182
  "maxRadii": 4,
package/dist/index.cjs CHANGED
@@ -812,6 +812,7 @@ function densityTokens(name, rootPx = 16) {
812
812
  // src/restraint/index.ts
813
813
  var HOUSE_BUDGET = {
814
814
  maxFontSizes: 10,
815
+ maxRelativeFontSizes: 3,
815
816
  maxFontWeights: 3,
816
817
  maxFontFamilies: 2,
817
818
  maxRadii: 4,
@@ -963,7 +964,17 @@ function checkRestraint(input) {
963
964
  const push = (rule, severity, message, found) => {
964
965
  violations.push({ rule, severity, message, found });
965
966
  };
966
- const fontSizes = distinctValues(css, "font-size", props, unresolved);
967
+ const allSizes = distinctValues(css, "font-size", props, unresolved);
968
+ const relativeSizes = allSizes.filter((v) => /^[\d.]+(em|%)$/.test(v));
969
+ const fontSizes = allSizes.filter((v) => !relativeSizes.includes(v));
970
+ if (relativeSizes.length > budget.maxRelativeFontSizes) {
971
+ push(
972
+ "relative-font-sizes",
973
+ "error",
974
+ `${relativeSizes.length} context-relative font sizes, budget ${budget.maxRelativeFontSizes}. A ratio is a relationship; more than a few and it is a second scale nobody named.`,
975
+ relativeSizes
976
+ );
977
+ }
967
978
  if (fontSizes.length > budget.maxFontSizes) {
968
979
  push(
969
980
  "font-sizes",
@@ -1146,6 +1157,7 @@ function checkRestraint(input) {
1146
1157
  violations,
1147
1158
  counts: {
1148
1159
  fontSizes: fontSizes.length,
1160
+ relativeFontSizes: relativeSizes.length,
1149
1161
  fontWeights: allWeights.length,
1150
1162
  fontFamilies: families.length,
1151
1163
  radii: radii.length,
package/dist/index.d.cts CHANGED
@@ -600,6 +600,8 @@ declare function densityTokens(name: DensityName, rootPx?: number): Record<strin
600
600
  */
601
601
  interface RestraintBudget {
602
602
  maxFontSizes: number;
603
+ /** Context-relative font sizes (`em`, `%`) -- ratios, not steps. See section 9. */
604
+ maxRelativeFontSizes: number;
603
605
  maxFontWeights: number;
604
606
  /** Excludes the monospace face, which is a functional choice not a stylistic one. */
605
607
  maxFontFamilies: number;
package/dist/index.d.ts CHANGED
@@ -600,6 +600,8 @@ declare function densityTokens(name: DensityName, rootPx?: number): Record<strin
600
600
  */
601
601
  interface RestraintBudget {
602
602
  maxFontSizes: number;
603
+ /** Context-relative font sizes (`em`, `%`) -- ratios, not steps. See section 9. */
604
+ maxRelativeFontSizes: number;
603
605
  maxFontWeights: number;
604
606
  /** Excludes the monospace face, which is a functional choice not a stylistic one. */
605
607
  maxFontFamilies: number;
package/dist/index.js CHANGED
@@ -740,6 +740,7 @@ function densityTokens(name, rootPx = 16) {
740
740
  // src/restraint/index.ts
741
741
  var HOUSE_BUDGET = {
742
742
  maxFontSizes: 10,
743
+ maxRelativeFontSizes: 3,
743
744
  maxFontWeights: 3,
744
745
  maxFontFamilies: 2,
745
746
  maxRadii: 4,
@@ -891,7 +892,17 @@ function checkRestraint(input) {
891
892
  const push = (rule, severity, message, found) => {
892
893
  violations.push({ rule, severity, message, found });
893
894
  };
894
- const fontSizes = distinctValues(css, "font-size", props, unresolved);
895
+ const allSizes = distinctValues(css, "font-size", props, unresolved);
896
+ const relativeSizes = allSizes.filter((v) => /^[\d.]+(em|%)$/.test(v));
897
+ const fontSizes = allSizes.filter((v) => !relativeSizes.includes(v));
898
+ if (relativeSizes.length > budget.maxRelativeFontSizes) {
899
+ push(
900
+ "relative-font-sizes",
901
+ "error",
902
+ `${relativeSizes.length} context-relative font sizes, budget ${budget.maxRelativeFontSizes}. A ratio is a relationship; more than a few and it is a second scale nobody named.`,
903
+ relativeSizes
904
+ );
905
+ }
895
906
  if (fontSizes.length > budget.maxFontSizes) {
896
907
  push(
897
908
  "font-sizes",
@@ -1074,6 +1085,7 @@ function checkRestraint(input) {
1074
1085
  violations,
1075
1086
  counts: {
1076
1087
  fontSizes: fontSizes.length,
1088
+ relativeFontSizes: relativeSizes.length,
1077
1089
  fontWeights: allWeights.length,
1078
1090
  fontFamilies: families.length,
1079
1091
  radii: radii.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domandigital/craft",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "The Doman Digital house craft standard as numbers: OKLCh colour ramps that snap to existing anchors, derived semantic tokens with measured WCAG and APCA contrast, one shared motion vocabulary for CSS and JS, and a base stylesheet. Zero dependencies.",
6
6
  "license": "Apache-2.0",