baseline-foundry 0.1.6 → 0.2.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.
Files changed (80) hide show
  1. package/README.md +22 -7
  2. package/config/canonical-spacing.resolved.json +71 -0
  3. package/config/experiments/ibm-plex-engine-smoke.json +7 -6
  4. package/config/experiments/ubuntu-engine-smoke.json +7 -6
  5. package/config/foundation-theme.json +7 -6
  6. package/config/tiers/app.json +8 -9
  7. package/config/tiers/documentation.json +7 -8
  8. package/config/tiers/editorial.json +7 -8
  9. package/config/tiers/os.json +7 -8
  10. package/dist/application-layout.js +1 -1
  11. package/dist/build.d.ts +1 -0
  12. package/dist/build.js +98 -36
  13. package/dist/css-app-tier.js +4 -46
  14. package/dist/css-component-contracts.d.ts +7 -0
  15. package/dist/css-component-contracts.js +82 -0
  16. package/dist/css-components/application-geometry.d.ts +5 -0
  17. package/dist/css-components/application-geometry.js +31 -0
  18. package/dist/css-components/article-pagination.js +6 -5
  19. package/dist/css-components/button-actions.js +68 -4
  20. package/dist/css-components/cards-options.js +2 -2
  21. package/dist/css-components/chip-badge-status.d.ts +0 -1
  22. package/dist/css-components/chip-badge-status.js +37 -15
  23. package/dist/css-components/content-card.js +11 -10
  24. package/dist/css-components/control-geometry.d.ts +12 -0
  25. package/dist/css-components/control-geometry.js +22 -0
  26. package/dist/css-components/cta-figure-aspect.js +2 -2
  27. package/dist/css-components/document-navigation.js +28 -18
  28. package/dist/css-components/editorial-content.js +1 -1
  29. package/dist/css-components/icon.js +24 -2
  30. package/dist/css-components/interactive-feedback.js +27 -14
  31. package/dist/css-components/interactive-tables.js +9 -6
  32. package/dist/css-components/legacy-navigation.js +32 -25
  33. package/dist/css-components/list-tree.js +5 -5
  34. package/dist/css-components/list.js +17 -12
  35. package/dist/css-components/logo-media.js +2 -2
  36. package/dist/css-components/navigation-geometry.d.ts +5 -0
  37. package/dist/css-components/navigation-geometry.js +30 -0
  38. package/dist/css-components/nested-controls.d.ts +8 -0
  39. package/dist/css-components/nested-controls.js +37 -0
  40. package/dist/css-components/panel.js +12 -13
  41. package/dist/css-components/search-box-and-filter.d.ts +0 -1
  42. package/dist/css-components/search-box-and-filter.js +3 -3
  43. package/dist/css-components/sites-editorial-ports.js +8 -1
  44. package/dist/css-components/sites-foundation.js +2 -2
  45. package/dist/css-components/table.js +9 -1
  46. package/dist/css-components/tabs-choice-breadcrumbs.js +9 -9
  47. package/dist/css-components/tiered-list-equal-height-row.js +2 -2
  48. package/dist/css-components.js +99 -229
  49. package/dist/css.js +44 -1
  50. package/dist/dtcg-spacing.d.ts +40 -0
  51. package/dist/dtcg-spacing.js +163 -0
  52. package/dist/experiments/ibm-plex-engine-smoke/styles.css +557 -360
  53. package/dist/experiments/ibm-plex-engine-smoke/surfaces.json +182 -14
  54. package/dist/experiments/ibm-plex-engine-smoke/tokens.json +91 -7
  55. package/dist/index.d.ts +1 -0
  56. package/dist/presets/app-tier/styles.css +700 -494
  57. package/dist/presets/app-tier/surfaces.json +709 -29
  58. package/dist/presets/app-tier/tokens.json +178 -8
  59. package/dist/presets/prose/styles.css +699 -486
  60. package/dist/presets/prose/surfaces.json +709 -29
  61. package/dist/presets/prose/tokens.json +177 -7
  62. package/dist/styles.css +699 -486
  63. package/dist/surfaces.json +709 -29
  64. package/dist/tiers/app/styles.css +700 -494
  65. package/dist/tiers/app/surfaces.json +709 -29
  66. package/dist/tiers/app/tokens.json +178 -8
  67. package/dist/tiers/documentation/styles.css +699 -486
  68. package/dist/tiers/documentation/surfaces.json +709 -29
  69. package/dist/tiers/documentation/tokens.json +177 -7
  70. package/dist/tiers/editorial/styles.css +699 -486
  71. package/dist/tiers/editorial/surfaces.json +709 -29
  72. package/dist/tiers/editorial/tokens.json +177 -7
  73. package/dist/tiers/os/styles.css +699 -486
  74. package/dist/tiers/os/surfaces.json +709 -29
  75. package/dist/tiers/os/tokens.json +177 -7
  76. package/dist/tokens.json +177 -7
  77. package/dist/types.d.ts +13 -13
  78. package/dist/vanilla-theme-colors.js +5 -1
  79. package/docs/publishing.md +7 -1
  80. package/package.json +1 -1
package/README.md CHANGED
@@ -115,7 +115,7 @@ The verified GitHub release artifact remains available as a fallback for
115
115
  environments that cannot reach the npm registry:
116
116
 
117
117
  ```bash
118
- npm install https://github.com/lyubomir-popov/baseline-foundry/releases/download/v0.1.6/baseline-foundry-0.1.6.tgz
118
+ npm install https://github.com/lyubomir-popov/baseline-foundry/releases/download/v0.2.0/baseline-foundry-0.2.0.tgz
119
119
  ```
120
120
 
121
121
  Use the attached `.tgz`, not the GitHub source archive: generated `dist/`
@@ -291,6 +291,7 @@ Independent surface contract:
291
291
  - tier choice is a top-level class on any `.bf-theme` container: `.bf-tier-editorial`, `.bf-tier-documentation`, `.bf-tier-app`, `.bf-tier-os`
292
292
  - multiple containers can coexist side by side under the same stylesheet
293
293
  - `dist/surfaces.json` stores the runtime tokens and the font-metric artifact that produced each shipped surface — see [docs/surfaces-manifest.md](docs/surfaces-manifest.md) for the full schema, stability guarantees, and consumer recipes
294
+ - built-in spacing is sourced from the integrity-pinned Canonical DTCG artifact; the twelve `--spacing-*` properties carry final Canonical values and the temporary `--bf-*` aliases resolve directly to them during the bounded deprecation window; custom themes stay BF-namespaced as documented in [docs/spacing-token-adapter.md](docs/spacing-token-adapter.md)
294
295
  - the published manifest omits local build-machine config/baseline file paths, so the shipped JSON stays portable
295
296
  - every tier keeps metric-derived runtime alignment while nested stacks own semantic spacing
296
297
 
@@ -444,6 +445,7 @@ The font files are resolved relative to that config file, so a downstream repo c
444
445
  At minimum, define:
445
446
 
446
447
  - `baselineUnit`
448
+ - `inlineUnitRem`
447
449
  - `fontFiles`
448
450
  - `fontStacks`
449
451
  - `elements`
@@ -451,6 +453,18 @@ At minimum, define:
451
453
  - `layout`
452
454
  - `components`
453
455
 
456
+ > **Unreleased custom-theme migration:** 020a changes the exported
457
+ > `ThemeConfig`/`ThemeComponentsConfig` shape and therefore also changes what
458
+ > `readThemeConfig` accepts. Existing custom themes must add
459
+ > `inlineUnitRem` (the built-in value is `0.25`) and replace
460
+ > `inlineInsetFieldRem`, `inlineInsetActionRem`, and
461
+ > `inlineInsetContinuationRem` with whole-unit `inlineInset*Units` counts. Add
462
+ > `markGapInlineUnits`, and replace `panelPaddingInlineBaselineUnits` with
463
+ > `panelPaddingInlineUnits`. Convert a previous rem value with
464
+ > `rem / inlineUnitRem`; convert the previous panel baseline count with
465
+ > `(oldCount * baselineUnit) / inlineUnitRem`. Old config files fail fast after
466
+ > this change. No release containing this API change has been published.
467
+
454
468
  Example sketch for a downstream Ubuntu Sans theme:
455
469
 
456
470
  ```json
@@ -469,6 +483,7 @@ Example sketch for a downstream Ubuntu Sans theme:
469
483
  "fontStacks": {
470
484
  "ubuntu-sans": "\"Ubuntu Sans\", \"Ubuntu\", system-ui, sans-serif"
471
485
  },
486
+ "inlineUnitRem": 0.25,
472
487
  "elements": [
473
488
  {
474
489
  "identifier": "body",
@@ -497,14 +512,14 @@ Example sketch for a downstream Ubuntu Sans theme:
497
512
  "components": {
498
513
  "borderWidthRem": 0.0625,
499
514
  "radiusRem": 0,
500
- "controlBlockPaddingRem": 0.5,
501
- "controlCompactBlockPaddingRem": 0.25,
502
- "controlInlinePaddingRem": 1,
515
+ "inlineInsetFieldUnits": 2,
516
+ "inlineInsetActionUnits": 4,
517
+ "inlineInsetContinuationUnits": 8,
518
+ "markGapInlineUnits": 2,
503
519
  "controlVisualSizeRem": 0.75,
504
520
  "fieldGapBaselineUnits": 1,
505
- "panelPaddingInlineBaselineUnits": 2,
506
- "panelPaddingBlockBaselineUnits": 2,
507
- "accordionIndentBaselineUnits": 3
521
+ "panelPaddingInlineUnits": 4,
522
+ "panelPaddingBlockBaselineUnits": 2
508
523
  }
509
524
  }
510
525
  ```
@@ -0,0 +1,71 @@
1
+ {
2
+ "format": "canonical-resolver-apply-spacing-v1",
3
+ "integrity": {
4
+ "algorithm": "sha256",
5
+ "canonicalProducts": "97cffe22691cebbe29d786d2fbe10d04d014d412ed35ccaca386ca41e73bd571"
6
+ },
7
+ "source": {
8
+ "package": "@canonical/design-tokens",
9
+ "repository": "https://github.com/canonical/design-tokens",
10
+ "commit": "18f57b95b1aa1dfe85a45746016b055c807d6628",
11
+ "resolver": "tokens/canonical/canonical.resolver.json"
12
+ },
13
+ "products": {
14
+ "site": {
15
+ "spacing.baseline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
16
+ "spacing.gap.field.block": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
17
+ "spacing.gap.mark.inline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
18
+ "spacing.gap.group.block": { "$type": "dimension", "$value": { "value": 1.5, "unit": "rem" } },
19
+ "spacing.gap.pattern.block": { "$type": "dimension", "$value": { "value": 4, "unit": "rem" } },
20
+ "spacing.gap.region.block": { "$type": "dimension", "$value": { "value": 8, "unit": "rem" } },
21
+ "spacing.inset.field.inline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
22
+ "spacing.inset.action.inline": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
23
+ "spacing.inset.continuation.inline": { "$type": "dimension", "$value": { "value": 2, "unit": "rem" } },
24
+ "spacing.inset.surface.inline": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
25
+ "spacing.inset.surface.block": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
26
+ "spacing.inset.strip.block": { "$type": "dimension", "$value": { "value": 4, "unit": "rem" } }
27
+ },
28
+ "docs": {
29
+ "spacing.baseline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
30
+ "spacing.gap.field.block": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
31
+ "spacing.gap.mark.inline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
32
+ "spacing.gap.group.block": { "$type": "dimension", "$value": { "value": 1.5, "unit": "rem" } },
33
+ "spacing.gap.pattern.block": { "$type": "dimension", "$value": { "value": 3, "unit": "rem" } },
34
+ "spacing.gap.region.block": { "$type": "dimension", "$value": { "value": 6, "unit": "rem" } },
35
+ "spacing.inset.field.inline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
36
+ "spacing.inset.action.inline": { "$type": "dimension", "$value": { "value": 0.75, "unit": "rem" } },
37
+ "spacing.inset.continuation.inline": { "$type": "dimension", "$value": { "value": 1.5, "unit": "rem" } },
38
+ "spacing.inset.surface.inline": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
39
+ "spacing.inset.surface.block": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
40
+ "spacing.inset.strip.block": { "$type": "dimension", "$value": { "value": 3, "unit": "rem" } }
41
+ },
42
+ "app": {
43
+ "spacing.baseline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
44
+ "spacing.gap.field.block": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
45
+ "spacing.gap.mark.inline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
46
+ "spacing.gap.group.block": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
47
+ "spacing.gap.pattern.block": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
48
+ "spacing.gap.region.block": { "$type": "dimension", "$value": { "value": 2, "unit": "rem" } },
49
+ "spacing.inset.field.inline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
50
+ "spacing.inset.action.inline": { "$type": "dimension", "$value": { "value": 0.75, "unit": "rem" } },
51
+ "spacing.inset.continuation.inline": { "$type": "dimension", "$value": { "value": 1.5, "unit": "rem" } },
52
+ "spacing.inset.surface.inline": { "$type": "dimension", "$value": { "value": 0.75, "unit": "rem" } },
53
+ "spacing.inset.surface.block": { "$type": "dimension", "$value": { "value": 0.75, "unit": "rem" } },
54
+ "spacing.inset.strip.block": { "$type": "dimension", "$value": { "value": 3, "unit": "rem" } }
55
+ },
56
+ "os": {
57
+ "spacing.baseline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
58
+ "spacing.gap.field.block": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
59
+ "spacing.gap.mark.inline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
60
+ "spacing.gap.group.block": { "$type": "dimension", "$value": { "value": 1.5, "unit": "rem" } },
61
+ "spacing.gap.pattern.block": { "$type": "dimension", "$value": { "value": 3, "unit": "rem" } },
62
+ "spacing.gap.region.block": { "$type": "dimension", "$value": { "value": 6, "unit": "rem" } },
63
+ "spacing.inset.field.inline": { "$type": "dimension", "$value": { "value": 0.25, "unit": "rem" } },
64
+ "spacing.inset.action.inline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
65
+ "spacing.inset.continuation.inline": { "$type": "dimension", "$value": { "value": 1.25, "unit": "rem" } },
66
+ "spacing.inset.surface.inline": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
67
+ "spacing.inset.surface.block": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
68
+ "spacing.inset.strip.block": { "$type": "dimension", "$value": { "value": 2, "unit": "rem" } }
69
+ }
70
+ }
71
+ }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.5,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ibm-plex-sans",
@@ -103,13 +104,13 @@
103
104
  "components": {
104
105
  "borderWidthRem": 0.0625,
105
106
  "radiusRem": 0,
106
- "controlBlockPaddingRem": 0.5,
107
- "controlCompactBlockPaddingRem": 0.25,
108
- "controlInlinePaddingRem": 1,
107
+ "inlineInsetFieldUnits": 2,
108
+ "inlineInsetActionUnits": 4,
109
+ "inlineInsetContinuationUnits": 8,
110
+ "markGapInlineUnits": 2,
109
111
  "controlVisualSizeRem": 1,
110
112
  "fieldGapBaselineUnits": 1,
111
- "panelPaddingInlineBaselineUnits": 2,
112
- "panelPaddingBlockBaselineUnits": 2,
113
- "accordionIndentBaselineUnits": 3
113
+ "panelPaddingInlineUnits": 4,
114
+ "panelPaddingBlockBaselineUnits": 2
114
115
  }
115
116
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.5,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ubuntu-sans",
@@ -103,13 +104,13 @@
103
104
  "components": {
104
105
  "borderWidthRem": 0.0625,
105
106
  "radiusRem": 0,
106
- "controlBlockPaddingRem": 0.5,
107
- "controlCompactBlockPaddingRem": 0.25,
108
- "controlInlinePaddingRem": 1,
107
+ "inlineInsetFieldUnits": 2,
108
+ "inlineInsetActionUnits": 4,
109
+ "inlineInsetContinuationUnits": 8,
110
+ "markGapInlineUnits": 2,
109
111
  "controlVisualSizeRem": 1,
110
112
  "fieldGapBaselineUnits": 1,
111
- "panelPaddingInlineBaselineUnits": 2,
112
- "panelPaddingBlockBaselineUnits": 2,
113
- "accordionIndentBaselineUnits": 3
113
+ "panelPaddingInlineUnits": 4,
114
+ "panelPaddingBlockBaselineUnits": 2
114
115
  }
115
116
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.5,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ubuntu-sans",
@@ -105,13 +106,13 @@
105
106
  "components": {
106
107
  "borderWidthRem": 0.0625,
107
108
  "radiusRem": 0,
108
- "controlBlockPaddingRem": 0.5,
109
- "controlCompactBlockPaddingRem": 0.25,
110
- "controlInlinePaddingRem": 1,
109
+ "inlineInsetFieldUnits": 2,
110
+ "inlineInsetActionUnits": 4,
111
+ "inlineInsetContinuationUnits": 8,
112
+ "markGapInlineUnits": 2,
111
113
  "controlVisualSizeRem": 1,
112
114
  "fieldGapBaselineUnits": 1,
113
- "panelPaddingInlineBaselineUnits": 2,
114
- "panelPaddingBlockBaselineUnits": 2,
115
- "accordionIndentBaselineUnits": 3
115
+ "panelPaddingInlineUnits": 4,
116
+ "panelPaddingBlockBaselineUnits": 2
116
117
  }
117
118
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.25,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ubuntu-sans",
@@ -105,16 +106,14 @@
105
106
  },
106
107
  "components": {
107
108
  "borderWidthRem": 0.0625,
108
- "radiusRem": 0.125,
109
- "controlBlockPaddingRem": 0.5,
110
- "controlCompactBlockPaddingRem": 0.375,
111
- "controlInlinePaddingRem": 1,
112
- "controlInlinePaddingActionRem": 1,
113
- "controlInlinePaddingFieldRem": 0.25,
109
+ "radiusRem": 0,
110
+ "inlineInsetFieldUnits": 1,
111
+ "inlineInsetActionUnits": 3,
112
+ "inlineInsetContinuationUnits": 6,
113
+ "markGapInlineUnits": 1,
114
114
  "controlVisualSizeRem": 1,
115
115
  "fieldGapBaselineUnits": 2,
116
- "panelPaddingInlineBaselineUnits": 3,
117
- "panelPaddingBlockBaselineUnits": 3,
118
- "accordionIndentBaselineUnits": 6
116
+ "panelPaddingInlineUnits": 3,
117
+ "panelPaddingBlockBaselineUnits": 3
119
118
  }
120
119
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.25,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ubuntu-sans",
@@ -106,15 +107,13 @@
106
107
  "components": {
107
108
  "borderWidthRem": 0.0625,
108
109
  "radiusRem": 0,
109
- "controlBlockPaddingRem": 0.5,
110
- "controlCompactBlockPaddingRem": 0.375,
111
- "controlInlinePaddingRem": 0.875,
112
- "controlInlinePaddingActionRem": 1,
113
- "controlInlinePaddingFieldRem": 0.5,
110
+ "inlineInsetFieldUnits": 2,
111
+ "inlineInsetActionUnits": 3,
112
+ "inlineInsetContinuationUnits": 6,
113
+ "markGapInlineUnits": 2,
114
114
  "controlVisualSizeRem": 0.875,
115
115
  "fieldGapBaselineUnits": 2,
116
- "panelPaddingInlineBaselineUnits": 4,
117
- "panelPaddingBlockBaselineUnits": 4,
118
- "accordionIndentBaselineUnits": 6
116
+ "panelPaddingInlineUnits": 4,
117
+ "panelPaddingBlockBaselineUnits": 4
119
118
  }
120
119
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.5,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ubuntu-sans",
@@ -106,15 +107,13 @@
106
107
  "components": {
107
108
  "borderWidthRem": 0.0625,
108
109
  "radiusRem": 0,
109
- "controlBlockPaddingRem": 0.5,
110
- "controlCompactBlockPaddingRem": 0.25,
111
- "controlInlinePaddingRem": 1,
112
- "controlInlinePaddingActionRem": 1,
113
- "controlInlinePaddingFieldRem": 0.5,
110
+ "inlineInsetFieldUnits": 2,
111
+ "inlineInsetActionUnits": 4,
112
+ "inlineInsetContinuationUnits": 8,
113
+ "markGapInlineUnits": 2,
114
114
  "controlVisualSizeRem": 1,
115
115
  "fieldGapBaselineUnits": 1,
116
- "panelPaddingInlineBaselineUnits": 2,
117
- "panelPaddingBlockBaselineUnits": 2,
118
- "accordionIndentBaselineUnits": 3
116
+ "panelPaddingInlineUnits": 4,
117
+ "panelPaddingBlockBaselineUnits": 2
119
118
  }
120
119
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "baselineUnit": 0.25,
3
+ "inlineUnitRem": 0.25,
3
4
  "fontFiles": [
4
5
  {
5
6
  "family": "ubuntu-sans",
@@ -106,15 +107,13 @@
106
107
  "components": {
107
108
  "borderWidthRem": 0.0625,
108
109
  "radiusRem": 0,
109
- "controlBlockPaddingRem": 0.375,
110
- "controlCompactBlockPaddingRem": 0.25,
111
- "controlInlinePaddingRem": 0.75,
112
- "controlInlinePaddingActionRem": 1,
113
- "controlInlinePaddingFieldRem": 0.25,
110
+ "inlineInsetFieldUnits": 1,
111
+ "inlineInsetActionUnits": 2,
112
+ "inlineInsetContinuationUnits": 5,
113
+ "markGapInlineUnits": 1,
114
114
  "controlVisualSizeRem": 0.75,
115
115
  "fieldGapBaselineUnits": 1,
116
- "panelPaddingInlineBaselineUnits": 2,
117
- "panelPaddingBlockBaselineUnits": 2,
118
- "accordionIndentBaselineUnits": 3
116
+ "panelPaddingInlineUnits": 2,
117
+ "panelPaddingBlockBaselineUnits": 2
119
118
  }
120
119
  }
@@ -7,7 +7,7 @@ const CLOSE_SELECTOR = "[data-application-layout-close]";
7
7
  const PIN_SELECTOR = "[data-application-layout-pin]";
8
8
  const COLLAPSED_CLASS = "is-collapsed";
9
9
  const PINNED_CLASS = "is-pinned";
10
- const LARGE_BREAKPOINT = "(min-width: 64.75rem)";
10
+ const LARGE_BREAKPOINT = "(min-width: 48rem)";
11
11
  const lastTriggerByNavigation = new WeakMap();
12
12
  function queryAllWithinRoot(root, selector) {
13
13
  const elements = Array.from(root.querySelectorAll(selector));
package/dist/build.d.ts CHANGED
@@ -12,6 +12,7 @@ export interface BuildThemeFromConfigOptions {
12
12
  surfaceLabel?: string;
13
13
  additionalSurfaces?: AdditionalThemeSurfaceBuildConfig[];
14
14
  }
15
+ export declare function validateThemeConfig(config: ThemeConfig): void;
15
16
  export declare function readThemeConfig(configPath: string): Promise<ThemeConfig>;
16
17
  export declare function buildThemeFromConfig(configPath?: string, options?: BuildThemeFromConfigOptions): Promise<BuildThemeResult>;
17
18
  export declare function buildThemeFromTier(tier: TierName): Promise<BuildThemeResult>;
package/dist/build.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { generateFoundryCss } from "./css.js";
4
+ import { assertSpacingSetsEqual, canonicalProductForBuiltInTheme, dtcgSpacingValue, legacyThemeConfigSpacing, readCanonicalSpacingProduct } from "./dtcg-spacing.js";
4
5
  import { normalizeBuiltInThemeName, presetNames, resolveBuiltInThemePath, resolvePresetPath, resolveTierPath, tierNames } from "./presets.js";
6
+ const DISCLOSURE_ICON_INLINE_SIZE_REM = 1;
5
7
  function parseRem(remValue) {
6
8
  return Number.parseFloat(remValue.replace("rem", ""));
7
9
  }
@@ -52,18 +54,14 @@ const REQUIRED_LAYOUT_FIELDS = [
52
54
  const REQUIRED_COMPONENT_FIELDS = [
53
55
  "borderWidthRem",
54
56
  "radiusRem",
55
- "controlBlockPaddingRem",
56
- "controlInlinePaddingRem",
57
+ "inlineInsetFieldUnits",
58
+ "inlineInsetActionUnits",
59
+ "inlineInsetContinuationUnits",
60
+ "markGapInlineUnits",
57
61
  "controlVisualSizeRem",
58
62
  "fieldGapBaselineUnits",
59
- "panelPaddingInlineBaselineUnits",
60
- "panelPaddingBlockBaselineUnits",
61
- "accordionIndentBaselineUnits"
62
- ];
63
- const OPTIONAL_COMPONENT_FIELDS = [
64
- "controlCompactBlockPaddingRem",
65
- "controlInlinePaddingActionRem",
66
- "controlInlinePaddingFieldRem"
63
+ "panelPaddingInlineUnits",
64
+ "panelPaddingBlockBaselineUnits"
67
65
  ];
68
66
  function assertNoDuplicateRoleKeys(raw, configPath) {
69
67
  const rolesMatch = raw.match(/"roles"\s*:\s*\{([\s\S]*?)\}/);
@@ -79,7 +77,7 @@ function assertNoDuplicateRoleKeys(raw, configPath) {
79
77
  seen.add(roleName);
80
78
  }
81
79
  }
82
- function validateConfig(config) {
80
+ export function validateThemeConfig(config) {
83
81
  if (!config.fontFiles.length) {
84
82
  throw new Error("Theme config requires at least one font file.");
85
83
  }
@@ -99,18 +97,52 @@ function validateConfig(config) {
99
97
  if (config.baselineUnit <= 0) {
100
98
  throw new Error('Theme config field "baselineUnit" must be greater than zero.');
101
99
  }
100
+ assertFiniteNumberConfigField(config.inlineUnitRem, "inlineUnitRem");
101
+ if (config.inlineUnitRem <= 0) {
102
+ throw new Error('Theme config field "inlineUnitRem" must be greater than zero.');
103
+ }
102
104
  for (const field of REQUIRED_LAYOUT_FIELDS) {
103
105
  assertFiniteNumberConfigField(config.layout[field], `layout.${field}`);
104
106
  }
105
107
  for (const field of REQUIRED_COMPONENT_FIELDS) {
106
108
  assertFiniteNumberConfigField(config.components[field], `components.${field}`);
107
109
  }
108
- for (const field of OPTIONAL_COMPONENT_FIELDS) {
109
- const value = config.components[field];
110
- if (value !== undefined) {
111
- assertFiniteNumberConfigField(value, `components.${field}`);
110
+ if (config.components.borderWidthRem <= 0 || config.components.controlVisualSizeRem <= 0) {
111
+ throw new Error("Component border width and control visual size must be greater than zero.");
112
+ }
113
+ if (config.components.radiusRem < 0 ||
114
+ config.components.inlineInsetFieldUnits < 0 ||
115
+ config.components.inlineInsetActionUnits < 0 ||
116
+ config.components.inlineInsetContinuationUnits < 0 ||
117
+ config.components.markGapInlineUnits < 0 ||
118
+ config.components.fieldGapBaselineUnits < 0 ||
119
+ config.components.panelPaddingInlineUnits < 0 ||
120
+ config.components.panelPaddingBlockBaselineUnits < 0) {
121
+ throw new Error("Component radius, inline insets, gaps, and surface padding must be non-negative.");
122
+ }
123
+ for (const field of [
124
+ "inlineInsetFieldUnits",
125
+ "inlineInsetActionUnits",
126
+ "inlineInsetContinuationUnits",
127
+ "markGapInlineUnits",
128
+ "panelPaddingInlineUnits"
129
+ ]) {
130
+ if (!Number.isInteger(config.components[field])) {
131
+ throw new Error(`Theme config field "components.${field}" must be a whole inline-unit count.`);
112
132
  }
113
133
  }
134
+ if (config.components.inlineInsetActionUnits * config.inlineUnitRem < config.components.borderWidthRem) {
135
+ throw new Error("Component action inset must contain its bordered action edge.");
136
+ }
137
+ if (config.components.inlineInsetFieldUnits > config.components.inlineInsetActionUnits ||
138
+ config.components.inlineInsetActionUnits > config.components.inlineInsetContinuationUnits) {
139
+ throw new Error("Component inline inset counts must be ordered field <= action <= continuation.");
140
+ }
141
+ const authoredContinuation = config.components.inlineInsetContinuationUnits * config.inlineUnitRem;
142
+ const authoredDisclosureNeed = DISCLOSURE_ICON_INLINE_SIZE_REM + (config.components.markGapInlineUnits * config.inlineUnitRem);
143
+ if (authoredContinuation < authoredDisclosureNeed) {
144
+ throw new Error(`Component continuation inset ${toRem(authoredContinuation)} cannot contain its fixed disclosure canvas and mark gap ${toRem(authoredDisclosureNeed)}.`);
145
+ }
114
146
  const elementIdentifiers = new Set();
115
147
  for (const [index, element] of config.elements.entries()) {
116
148
  if (elementIdentifiers.has(element.identifier)) {
@@ -140,7 +172,7 @@ export async function readThemeConfig(configPath) {
140
172
  const raw = await fs.readFile(configPath, "utf8");
141
173
  assertNoDuplicateRoleKeys(raw, configPath);
142
174
  const config = JSON.parse(raw);
143
- validateConfig(config);
175
+ validateThemeConfig(config);
144
176
  return config;
145
177
  }
146
178
  function createBaselineConfig(config, sourceConfigPath, baselineConfigPath) {
@@ -205,28 +237,26 @@ function toTypographyToken(identifier, token, config) {
205
237
  textTransform: elementConfig?.textTransform
206
238
  };
207
239
  }
208
- function buildComponentTokens(config) {
209
- const controlInlinePaddingActionRem = config.components.controlInlinePaddingActionRem ?? config.components.controlInlinePaddingRem;
210
- const controlInlinePaddingFieldRem = config.components.controlInlinePaddingFieldRem ?? (controlInlinePaddingActionRem / 2);
240
+ function spacingRem(spacing, id) {
241
+ return dtcgSpacingValue(spacing[id]);
242
+ }
243
+ function buildComponentTokens(config, spacing) {
211
244
  return {
212
245
  borderWidth: toRem(config.components.borderWidthRem),
213
246
  // Vanilla's shared $bar-thickness is represented as 0.1875rem so emphasis
214
247
  // bars and thin borders both scale with root text sizing.
215
248
  barThickness: toRem(3 / 16),
216
249
  radius: toRem(config.components.radiusRem),
217
- controlBlockPadding: toRem(config.components.controlBlockPaddingRem),
218
- controlCompactBlockPadding: toRem(config.components.controlCompactBlockPaddingRem ?? config.components.controlBlockPaddingRem),
219
- controlInlinePadding: toRem(controlInlinePaddingActionRem),
220
- controlInlinePaddingAction: toRem(controlInlinePaddingActionRem),
221
- controlInlinePaddingField: toRem(controlInlinePaddingFieldRem),
250
+ inlineInsetField: spacingRem(spacing, "spacing.inset.field.inline"),
251
+ inlineInsetAction: spacingRem(spacing, "spacing.inset.action.inline"),
252
+ inlineInsetContinuation: spacingRem(spacing, "spacing.inset.continuation.inline"),
222
253
  controlVisualSize: toRem(config.components.controlVisualSizeRem),
223
- fieldGap: toRem(config.components.fieldGapBaselineUnits * config.baselineUnit),
224
- panelPaddingInline: toRem(config.components.panelPaddingInlineBaselineUnits * config.baselineUnit),
225
- panelPaddingBlock: toRem(config.components.panelPaddingBlockBaselineUnits * config.baselineUnit),
226
- accordionIndent: toRem(config.components.accordionIndentBaselineUnits * config.baselineUnit)
254
+ fieldGap: spacingRem(spacing, "spacing.gap.field.block"),
255
+ panelPaddingInline: spacingRem(spacing, "spacing.inset.surface.inline"),
256
+ panelPaddingBlock: spacingRem(spacing, "spacing.inset.surface.block")
227
257
  };
228
258
  }
229
- function buildThemeTokens(config, baselineTokens) {
259
+ function buildThemeTokens(config, baselineTokens, spacing, canonicalSpacing) {
230
260
  const elements = Object.fromEntries(Object.entries(baselineTokens.elements).map(([identifier, token]) => [identifier, toTypographyToken(identifier, token, config)]));
231
261
  const roles = Object.fromEntries(Object.entries(config.roles).map(([roleName, identifier]) => {
232
262
  const roleToken = elements[identifier];
@@ -235,8 +265,31 @@ function buildThemeTokens(config, baselineTokens) {
235
265
  }
236
266
  return [roleName, roleToken];
237
267
  }));
268
+ const body = roles.body;
269
+ if (!body) {
270
+ throw new Error('Theme tokens require a generated "body" role.');
271
+ }
272
+ const nestedLineHeight = parseRem(body.lineHeight) - parseRem(baselineTokens.baselineUnit);
273
+ if (nestedLineHeight < parseRem(body.fontSize)) {
274
+ throw new Error(`Nested line ${toRem(nestedLineHeight)} cannot contain the body font ${body.fontSize}.`);
275
+ }
276
+ if (nestedLineHeight < config.components.controlVisualSizeRem) {
277
+ throw new Error(`Nested line ${toRem(nestedLineHeight)} cannot contain the control visual ${toRem(config.components.controlVisualSizeRem)}.`);
278
+ }
279
+ const nestedFramedPaint = nestedLineHeight + (config.components.borderWidthRem * 2);
280
+ if (nestedFramedPaint > parseRem(body.lineHeight)) {
281
+ throw new Error(`Nested framed controls require ${toRem(nestedFramedPaint)}, which exceeds the body line ${body.lineHeight}.`);
282
+ }
283
+ const leadingMarkNeed = config.components.controlVisualSizeRem +
284
+ spacing["spacing.gap.mark.inline"].$value.value;
285
+ if (spacing["spacing.inset.continuation.inline"].$value.value < leadingMarkNeed) {
286
+ throw new Error(`Continuation inset ${spacingRem(spacing, "spacing.inset.continuation.inline")} cannot contain the leading mark and gap ${toRem(leadingMarkNeed)}.`);
287
+ }
238
288
  return {
239
- baselineUnit: baselineTokens.baselineUnit,
289
+ baselineUnit: spacingRem(spacing, "spacing.baseline"),
290
+ inlineUnit: toRem(config.inlineUnitRem),
291
+ canonicalSpacing,
292
+ spacing,
240
293
  fontFiles: config.fontFiles,
241
294
  fontStacks: config.fontStacks,
242
295
  roles,
@@ -245,15 +298,15 @@ function buildThemeTokens(config, baselineTokens) {
245
298
  contentMaxWidth: toRem(config.layout.contentMaxWidthRem),
246
299
  contentPaddingInline: toRem(config.layout.contentPaddingInlineRem),
247
300
  measure: toRem(config.layout.measureRem),
248
- sectionSpace: toRem(config.layout.sectionSpaceBaselineUnits * config.baselineUnit),
249
- sectionSpaceShallow: toRem(config.layout.sectionSpaceShallowBaselineUnits * config.baselineUnit),
250
- sectionSpaceDeep: toRem(config.layout.sectionSpaceDeepBaselineUnits * config.baselineUnit),
251
- stripSpace: toRem(config.layout.stripSpaceBaselineUnits * config.baselineUnit),
301
+ sectionSpace: spacingRem(spacing, "spacing.gap.pattern.block"),
302
+ sectionSpaceShallow: spacingRem(spacing, "spacing.gap.group.block"),
303
+ sectionSpaceDeep: spacingRem(spacing, "spacing.gap.region.block"),
304
+ stripSpace: spacingRem(spacing, "spacing.inset.strip.block"),
252
305
  gridGapInline: toRem(config.layout.gridGapInlineBaselineUnits * config.baselineUnit),
253
306
  gridGapBlock: toRem(config.layout.gridGapBlockBaselineUnits * config.baselineUnit),
254
307
  pageMargin: toRem(config.layout.pageMarginBaselineUnits * config.baselineUnit)
255
308
  },
256
- components: buildComponentTokens(config)
309
+ components: buildComponentTokens(config, spacing)
257
310
  };
258
311
  }
259
312
  function inferBuiltInPresetName(resolvedConfigPath) {
@@ -305,6 +358,15 @@ function buildSurfaceManifest(defaultSurface, surfaces) {
305
358
  }
306
359
  async function buildThemeSurface(name, resolvedConfigPath, baselineDir, outputDir, options = {}) {
307
360
  const config = await readThemeConfig(resolvedConfigPath);
361
+ const builtInName = inferBuiltInPresetName(resolvedConfigPath);
362
+ const legacySpacing = legacyThemeConfigSpacing(config);
363
+ const canonicalSpacing = builtInName
364
+ ? await readCanonicalSpacingProduct(canonicalProductForBuiltInTheme(builtInName))
365
+ : undefined;
366
+ const spacing = canonicalSpacing ? structuredClone(canonicalSpacing) : legacySpacing;
367
+ if (builtInName) {
368
+ assertSpacingSetsEqual(spacing, legacySpacing, `Built-in ${builtInName} spacing authoring assertion (update the pinned Canonical artifact and matching tier counts together)`);
369
+ }
308
370
  const resolvedBaselineDir = path.resolve(baselineDir);
309
371
  const resolvedOutputDir = path.resolve(outputDir);
310
372
  await ensureDirectory(resolvedBaselineDir);
@@ -324,7 +386,7 @@ async function buildThemeSurface(name, resolvedConfigPath, baselineDir, outputDi
324
386
  configPath: resolvedConfigPath,
325
387
  baselineConfigPath,
326
388
  baselineTokensPath: path.join(resolvedBaselineDir, "tokens.json"),
327
- tokens: buildThemeTokens(runtimeConfig, baselineTokens),
389
+ tokens: buildThemeTokens(runtimeConfig, baselineTokens, spacing, canonicalSpacing),
328
390
  metrics: runtimeMetricsTokens(baselineTokens, runtimeConfig.fontFiles)
329
391
  };
330
392
  }