@bridge-ds/core 0.17.0 → 0.19.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 (64) hide show
  1. package/bridge.config.schema.json +16 -0
  2. package/dist/activity.d.ts +207 -0
  3. package/dist/audit/index.js +3 -3
  4. package/dist/audit/report.d.ts +17 -2
  5. package/dist/branch-actions.d.ts +7 -1
  6. package/dist/build-requests-github.d.ts +25 -0
  7. package/dist/build-requests.d.ts +403 -0
  8. package/dist/changelog-model.d.ts +102 -0
  9. package/dist/component-spec.d.ts +3 -1
  10. package/dist/config.d.ts +21 -0
  11. package/dist/css-color.d.ts +25 -0
  12. package/dist/docs-proposal.d.ts +1 -0
  13. package/dist/explorations.d.ts +1 -0
  14. package/dist/fidelity-references.d.ts +12 -0
  15. package/dist/figma-fix-loop.d.ts +153 -0
  16. package/dist/figma-fixes.d.ts +169 -0
  17. package/dist/figma-push-github.d.ts +7 -2
  18. package/dist/figma-push.d.ts +15 -2
  19. package/dist/gap-case.d.ts +144 -0
  20. package/dist/github-client.d.ts +31 -0
  21. package/dist/id-map.d.ts +10 -0
  22. package/dist/index.d.ts +14 -0
  23. package/dist/index.js +3944 -774
  24. package/dist/index.js.map +1 -1
  25. package/dist/layered-review.d.ts +2 -0
  26. package/dist/measure-status.d.ts +127 -0
  27. package/dist/measured-only.d.ts +28 -0
  28. package/dist/measured-spec.d.ts +349 -0
  29. package/dist/measured-tokens.d.ts +25 -0
  30. package/dist/motion-docs.d.ts +51 -0
  31. package/dist/node/audit.d.ts +11 -3
  32. package/dist/node/index.d.ts +1 -0
  33. package/dist/node/index.js +1637 -24
  34. package/dist/node/index.js.map +1 -1
  35. package/dist/node/measure-script.d.ts +1 -0
  36. package/dist/node/measure.d.ts +212 -0
  37. package/dist/node/spec-css.d.ts +9 -1
  38. package/dist/node/tokens-script.d.ts +3 -0
  39. package/dist/pr-composer.d.ts +5 -0
  40. package/dist/previews.d.ts +4 -1
  41. package/dist/{prod-branch-DenQkr_e.js → prod-branch-Bdx_2bRQ.js} +197 -159
  42. package/dist/prod-branch-Bdx_2bRQ.js.map +1 -0
  43. package/dist/prod-branch.d.ts +1 -1
  44. package/dist/repo-model.d.ts +5 -1
  45. package/dist/repo-source-github.d.ts +8 -0
  46. package/dist/{repo-source-B4jNZhyC.js → repo-source-m0Tc603o.js} +1406 -629
  47. package/dist/repo-source-m0Tc603o.js.map +1 -0
  48. package/dist/repo-source.d.ts +6 -0
  49. package/dist/{report-DVEmUr0p.js → report-DFPKygfk.js} +17 -6
  50. package/dist/{report-DVEmUr0p.js.map → report-DFPKygfk.js.map} +1 -1
  51. package/dist/requester.d.ts +14 -0
  52. package/dist/requests.d.ts +2 -0
  53. package/dist/review-gate.d.ts +183 -2
  54. package/dist/risk.d.ts +12 -0
  55. package/dist/share-branch.d.ts +1 -1
  56. package/dist/snapshot.d.ts +34 -0
  57. package/dist/suggestion-review.d.ts +2 -0
  58. package/dist/suggestions-github.d.ts +21 -0
  59. package/dist/suggestions.d.ts +6 -0
  60. package/dist/token-proposal.d.ts +7 -0
  61. package/dist/try-in-product.d.ts +9 -0
  62. package/package.json +1 -1
  63. package/dist/prod-branch-DenQkr_e.js.map +0 -1
  64. package/dist/repo-source-B4jNZhyC.js.map +0 -1
@@ -84,5 +84,7 @@ export interface ProposalBodyInput {
84
84
  /** "Bridge MCP", "the bridge CLI". */
85
85
  tool?: string;
86
86
  author?: string;
87
+ /** Pushed from the Figma plugin: design-approved, the tier line says what happens next (docs/BUILD-REQUESTS.md). */
88
+ fromFigma?: boolean | undefined;
87
89
  }
88
90
  export declare function composeProposalBody(args: ProposalBodyInput): string;
@@ -0,0 +1,127 @@
1
+ import type { SpecPart, SpecVariant } from './component-spec';
2
+ import { type FieldDiff, type MeasuredArgType, type MeasuredSpecsStory, type MeasuredState } from './measured-spec';
3
+ export interface VariantMeasure {
4
+ /** Args passed to the story (`{ variant: 'danger', size: 'lg', disabled: true }`). */
5
+ overrides: Record<string, string | number | boolean>;
6
+ /** Pseudo state forced on the component; absent at rest and for disabled (an arg). */
7
+ state?: MeasuredState | undefined;
8
+ }
9
+ export interface PlanVariantOptions {
10
+ /** Props to vary; default every enum prop (2 to 12 options) that is not wiring (`as`, `type`, `className`...). */
11
+ axes?: string[] | undefined;
12
+ /** Exact values per prop (from a Figma mapping: variantValuesFromMapping); replaces `axes`. Booleans vary too. */
13
+ values?: Record<string, (string | boolean)[]> | undefined;
14
+ /** Exact prop combinations (variantCombosFromMapping); replaces `values` and `axes`. */
15
+ combos?: Record<string, string | boolean>[] | undefined;
16
+ /** States to measure on each combination (default rest, hover, disabled). */
17
+ states?: ('rest' | MeasuredState | 'disabled')[] | undefined;
18
+ /** At most this many measures (default 128); the axes are kept, states are dropped first. */
19
+ max?: number | undefined;
20
+ }
21
+ /**
22
+ * Every variant to measure for a component, from its argTypes: the cartesian product of its enum props, times the
23
+ * states (hover, focus and active forced in Chrome, disabled as an arg when the component has a disabled prop).
24
+ */
25
+ export declare function planVariantMeasures(argTypes: Record<string, MeasuredArgType>, o?: PlanVariantOptions): VariantMeasure[];
26
+ /**
27
+ * The prop combinations a Figma component's variants mean in code (State aside): the product of its VARIANT axes,
28
+ * each value with the props it sets (Checked=mixed sets `checked: false, indeterminate: true`). Unmapped values are left out.
29
+ */
30
+ export declare function variantCombosFromMapping(mapping: PropsToFigma): Record<string, string | boolean>[];
31
+ /**
32
+ * The prop combinations to measure for some axes, at most `cap`: the full product when it fits; else every value of
33
+ * each axis alone (the others at their first value), then every pair of axes, until the cap. `capped` says the full
34
+ * product was not measured.
35
+ */
36
+ export declare function boundedCombos(axes: [string, (string | boolean)[]][], cap?: number): {
37
+ combos: Record<string, string | boolean>[];
38
+ capped: boolean;
39
+ };
40
+ /** The values to measure per prop for a Figma component: its VARIANT axes mapped to props (State aside). */
41
+ export declare function variantValuesFromMapping(mapping: PropsToFigma): Record<string, (string | boolean)[]>;
42
+ /** A Figma component property as the plugin reads it (componentPropertyDefinitions) or the specs write it. */
43
+ export interface FigmaPropertyRef {
44
+ name: string;
45
+ type: 'VARIANT' | 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP' | string;
46
+ /** VARIANT values. */
47
+ values?: string[] | undefined;
48
+ default?: unknown;
49
+ }
50
+ export interface PropMapping {
51
+ figma: string;
52
+ type: FigmaPropertyRef['type'];
53
+ /** The code prop, or `state` for a Figma State axis (pseudo states and disabled). */
54
+ prop: string;
55
+ /** VARIANT: Figma value -> code value. Missing values are listed in `unmatchedValues`. */
56
+ values?: Record<string, string | boolean> | undefined;
57
+ /** VARIANT values that also set other props (Checked=mixed: `{ indeterminate: true }`). */
58
+ also?: Record<string, Record<string, string | boolean>> | undefined;
59
+ unmatchedValues?: string[] | undefined;
60
+ }
61
+ export interface PropsToFigma {
62
+ mapped: PropMapping[];
63
+ /** Figma properties with no code prop ("tone has no prop in code"). */
64
+ figmaOnly: string[];
65
+ /** Enum and boolean props with no Figma property. */
66
+ codeOnly: string[];
67
+ }
68
+ /**
69
+ * Maps Figma component properties to code props by name (case, spaces and dashes ignored; `is` prefixes and `Show x`
70
+ * booleans folded), VARIANT values to enum options the same way, and a Figma `State` axis to pseudo states and the
71
+ * disabled prop.
72
+ */
73
+ export declare function mapPropsToFigma(argTypes: Record<string, MeasuredArgType>, figma: FigmaPropertyRef[]): PropsToFigma;
74
+ export type ComponentCheck = 'matches' | 'differs' | 'cant-check';
75
+ /** Why a component can't be checked yet: a closed list, so the copy stays honest. */
76
+ export type CantCheckReason = 'no-story' | 'did-not-render' | 'no-token-variables' | 'popup-closed' | 'no-figma' | 'prop-unmapped' | 'no-story-for-variant';
77
+ export declare const CANT_CHECK_COPY: Record<CantCheckReason, string>;
78
+ export interface VariantCheck {
79
+ /** Figma variant key ("Size=md, State=Hover"). */
80
+ key: string;
81
+ status: ComponentCheck;
82
+ /** Story measured for it. */
83
+ story?: string | undefined;
84
+ reason?: CantCheckReason | undefined;
85
+ diffs?: FieldDiff[] | undefined;
86
+ compared?: number | undefined;
87
+ }
88
+ export interface ComponentStatus {
89
+ name: string;
90
+ status: ComponentCheck;
91
+ /** Can't check yet: why (closed list) and the sentence to show. */
92
+ reason?: CantCheckReason | undefined;
93
+ /** One sentence in designer words: the first difference, or the reason with its detail. */
94
+ summary: string;
95
+ detail?: string | undefined;
96
+ variants: VariantCheck[];
97
+ mapping?: PropsToFigma | undefined;
98
+ /** Share of measured values tied to a declared CSS variable. */
99
+ tokenShare?: number | undefined;
100
+ }
101
+ /** The Figma side of a component, in the spec shape: what the plugin reads from the Figma set (or the specs it was drawn from). */
102
+ export interface FigmaComponentRef {
103
+ properties: FigmaPropertyRef[];
104
+ parts: SpecPart[];
105
+ variants: Pick<SpecVariant, 'props' | 'values'>[];
106
+ }
107
+ export interface ComponentStatusInput {
108
+ name: string;
109
+ /** The component's measured stories (any args and states). */
110
+ stories: MeasuredSpecsStory[];
111
+ argTypes?: Record<string, MeasuredArgType> | undefined;
112
+ figma?: FigmaComponentRef | undefined;
113
+ /** Token path -> resolved value in the measured page, for value-level agreement. */
114
+ resolve?: ((tokenPath: string) => string | number | undefined) | undefined;
115
+ /** No Figma set of this name, but sets drawn from it open (Dialog/Popup): named in the reason. */
116
+ figmaSets?: string[] | undefined;
117
+ /** Below this share of values tied to CSS variables, the library has no tokens to check (default 0.1). */
118
+ minTokenShare?: number | undefined;
119
+ }
120
+ /** A difference in designer words: "Left padding is 6 px in code, 8 px in Figma (label)". */
121
+ export declare function describeDiff(d: FieldDiff): string;
122
+ /**
123
+ * One component's status from its measured stories and its Figma side. The order of the checks is the order a team
124
+ * fixes them in: something to measure, tokens to bind, a Figma component, props that name its variants, a story per
125
+ * variant, then the values.
126
+ */
127
+ export declare function componentStatus(input: ComponentStatusInput): ComponentStatus;
@@ -0,0 +1,28 @@
1
+ import { type ComponentSpecsFile } from './component-spec';
2
+ import type { FigmaHints, FixedMeasuredSpecsFile } from './figma-fixes';
3
+ import { type MeasuredSpecsFile } from './measured-spec';
4
+ /** What building from the measure gave: sets, variants, and the stories it used. */
5
+ export interface MeasuredOnlyReport {
6
+ sets: number;
7
+ variants: number;
8
+ stories: number;
9
+ /** Components with stories that gave no set (every story failed, or none at rest). */
10
+ skipped: string[];
11
+ }
12
+ /** The screenshot of the story a variant was built from (`--shots`), path relative to measured-specs.json. */
13
+ export interface VariantShot {
14
+ file: string;
15
+ width: number;
16
+ height: number;
17
+ }
18
+ /** Set name -> variant key (variantKeyOf) -> its story's screenshot: the reference Check fidelity compares with. */
19
+ export type MeasuredShots = Record<string, Record<string, VariantShot>>;
20
+ /** Every set the measure can give, by component (the last segment of a story's title: "Figma variants/Radio" is Radio). */
21
+ export declare function specsFromMeasure(file: MeasuredSpecsFile | FixedMeasuredSpecsFile, opts?: {
22
+ known?: ((path: string) => boolean) | undefined;
23
+ }): {
24
+ specs: ComponentSpecsFile;
25
+ report: MeasuredOnlyReport;
26
+ shots: MeasuredShots;
27
+ hints: Record<string, FigmaHints>;
28
+ };
@@ -0,0 +1,349 @@
1
+ import type { SpecField, SpecLayout, SpecPart, SpecValue, SpecVariant, SpecVector } from './component-spec';
2
+ import type { ComponentStatus } from './measure-status';
3
+ /** How a value was tied to a custom property. */
4
+ export interface MeasuredToken {
5
+ /**
6
+ * `declared`: the winning CSS declaration uses the variable (strong). `matched`: no declaration does, but the value
7
+ * equals a variable defined on the root (weak: several tokens can share a value).
8
+ */
9
+ via: 'declared' | 'matched';
10
+ /** declared: the variable the declaration names, then what it aliases (`--button-bg`, `--color-action-primary-bg`). matched: up to 3 candidates. */
11
+ chain: string[];
12
+ /** declared: the declaration is the variable alone (`var(--x)`), not a calc() or a function of it. */
13
+ exact: boolean;
14
+ /** declared: the declaration text (`var(--space-2) var(--space-3)` piece for this side). */
15
+ declared?: string | undefined;
16
+ }
17
+ export interface MeasuredBox {
18
+ /** Relative to the measured root's top-left corner, CSS pixels. */
19
+ x: number;
20
+ y: number;
21
+ width: number;
22
+ height: number;
23
+ }
24
+ export interface MeasuredNode {
25
+ /** Tag name, `#text` for a text run inside an element that also holds elements. */
26
+ tag: string;
27
+ kind: 'frame' | 'text' | 'icon' | 'vector';
28
+ /** Width or height set by the CSS (not auto, a percentage or content-sized). */
29
+ sized?: {
30
+ width?: boolean | undefined;
31
+ height?: boolean | undefined;
32
+ } | undefined;
33
+ /** Inline SVG: each shape's stroke in order (rgb), as drawn. */
34
+ svgStrokes?: string[] | undefined;
35
+ /** A ::before or ::after drawn as a box (a switch knob, a checkbox's box): its tag is `::before` / `::after`. */
36
+ pseudo?: 'before' | 'after' | undefined;
37
+ classes?: string[] | undefined;
38
+ role?: string | undefined;
39
+ /** State attributes (data-state, data-variant, aria-checked...). */
40
+ attrs?: Record<string, string> | undefined;
41
+ box: MeasuredBox;
42
+ /** Computed values of the properties the measure reads (display, flex, padding, colors, fonts...). */
43
+ style: Record<string, string>;
44
+ /** CSS property -> the token behind its value. */
45
+ tokens: Record<string, MeasuredToken>;
46
+ /** Text layers: the characters. */
47
+ text?: string | undefined;
48
+ /** Icons and vectors: their markup when short. */
49
+ svg?: string | undefined;
50
+ media?: boolean | undefined;
51
+ input?: {
52
+ type: string;
53
+ value: string;
54
+ placeholder: string;
55
+ checked: boolean;
56
+ } | undefined;
57
+ /** Node or depth limit reached under this node. */
58
+ truncated?: boolean | undefined;
59
+ /** A gallery's instance (splitInstances): where its box sat in the story's root before it was re-based. */
60
+ at?: {
61
+ x: number;
62
+ y: number;
63
+ } | undefined;
64
+ children: MeasuredNode[];
65
+ }
66
+ /** A measure in the Figma pull's shape: the parts of one variant and their field values, plus what a spec leaves out. */
67
+ /** Figma alignment of one child in its parent's auto layout, relative to the parent's direction. */
68
+ export interface MeasuredChildAlign {
69
+ primary?: 'MIN' | 'CENTER' | 'MAX' | undefined;
70
+ counter?: 'MIN' | 'CENTER' | 'MAX' | undefined;
71
+ }
72
+ /** A measured auto layout: the spec layout, plus per child alignment for out-of-flow decorations rebuilt in it. */
73
+ export interface MeasuredLayout extends SpecLayout {
74
+ /** Child part id -> its alignment; the parent's padding (in `values`) carries the offset. */
75
+ align?: Record<string, MeasuredChildAlign> | undefined;
76
+ }
77
+ /** A measured part: a spec part, plus what auto layout needs to rebuild margins, overlays and decorations. */
78
+ export interface MeasuredPart extends SpecPart {
79
+ layout?: MeasuredLayout | undefined;
80
+ /** Out of flow and over its siblings or outside its parent (a popover, a badge, a focus ring): absolute in Figma, never in the size. */
81
+ overlay?: boolean | undefined;
82
+ /** Margins the part has (px, non-zero sides). */
83
+ margins?: {
84
+ top?: number | undefined;
85
+ right?: number | undefined;
86
+ bottom?: number | undefined;
87
+ left?: number | undefined;
88
+ } | undefined;
89
+ /** Uneven margins between siblings: wrap the part in a frame with this padding. */
90
+ wrap?: {
91
+ padding: {
92
+ top?: number | undefined;
93
+ right?: number | undefined;
94
+ bottom?: number | undefined;
95
+ left?: number | undefined;
96
+ };
97
+ } | undefined;
98
+ /** The radius is half the shorter side or more: a pill or a circle (its value is 999 px, or the token it is bound to). */
99
+ fullRadius?: boolean | undefined;
100
+ }
101
+ export interface MeasuredSpec {
102
+ story: string;
103
+ parts: MeasuredPart[];
104
+ /** Part id -> field -> token path (declared token), number (px or unitless literal) or null (no paint). */
105
+ values: SpecVariant['values'];
106
+ /** Part id -> field -> the computed value (`rgb(31, 41, 55)`, 16). Colors without a token only live here. */
107
+ raw: Record<string, Partial<Record<SpecField, string | number>>>;
108
+ /** Part id -> field -> the token evidence (declared chain or value match). */
109
+ tokens: Record<string, Partial<Record<SpecField, MeasuredToken>>>;
110
+ /** Part id -> its measured box. */
111
+ boxes: Record<string, MeasuredBox>;
112
+ /** Fields read, and how many are tied to a declared token, to a value match, or to none. */
113
+ coverage: {
114
+ fields: number;
115
+ declared: number;
116
+ matched: number;
117
+ literal: number;
118
+ };
119
+ /**
120
+ * Part id -> the SVG an icon or vector part draws, `currentColor` resolved to the part's color, and the value of each
121
+ * shape's stroke in order. The pull draws it in place of an empty icon frame.
122
+ */
123
+ vectors?: Record<string, SpecVector> | undefined;
124
+ /** Part id -> the width and height its CSS sets (px): keep them fixed, do not hug (a 40x40 icon button around a 16 px icon). */
125
+ sized?: Record<string, {
126
+ width?: number | undefined;
127
+ height?: number | undefined;
128
+ }> | undefined;
129
+ /**
130
+ * Part id -> extra space before it in its parent's auto layout (px), when the gaps between children are not uniform
131
+ * (margins): the parent's itemSpacing is the smallest gap, this is what a child adds on top.
132
+ */
133
+ spacers?: Record<string, number> | undefined;
134
+ }
135
+ export interface FieldDiff {
136
+ part: string;
137
+ field: SpecField;
138
+ /** The static spec's value (token path, number, null), undefined when the static spec has no value there. */
139
+ static?: SpecValue | undefined;
140
+ /** The measured value: token path when declared, else the raw value. Undefined when the field was not measured. */
141
+ measured?: SpecValue | undefined;
142
+ /** Same token, or same resolved value. */
143
+ same: boolean;
144
+ }
145
+ export interface SpecComparison {
146
+ /** Static parts matched to a measured part (by CSS class, then by kind and order). */
147
+ partsMatched: number;
148
+ staticParts: number;
149
+ measuredParts: number;
150
+ /** Fields both sides have. */
151
+ compared: number;
152
+ same: number;
153
+ /** Fields where both name a token and it is the same token. */
154
+ sameToken: number;
155
+ diffs: FieldDiff[];
156
+ /** Static parts no measured part matches (hidden optional parts, or parts the static guess invented). */
157
+ unmatchedParts: string[];
158
+ /** Static fields with no measured counterpart, measured fields the static spec misses. */
159
+ staticOnly: number;
160
+ measuredOnly: number;
161
+ /** Width and height, root part: static (when a number) vs measured, px. */
162
+ rootSize?: {
163
+ static: {
164
+ width?: number | undefined;
165
+ height?: number | undefined;
166
+ };
167
+ measured: {
168
+ width: number;
169
+ height: number;
170
+ };
171
+ } | undefined;
172
+ }
173
+ /** A spec calc() of token paths (`calc(control.height.sm - border-width.default * 2)`) in px, from resolved tokens. */
174
+ export declare function evalCalc(expr: string, resolve: (tokenPath: string) => string | number | undefined): number | undefined;
175
+ export interface PairOptions {
176
+ /** The component's properties: a text part bound to a TEXT property is paired by that property's default text. */
177
+ properties?: {
178
+ name: string;
179
+ type: string;
180
+ default?: unknown;
181
+ }[] | undefined;
182
+ }
183
+ /**
184
+ * The parts without the wrappers the pull adds around one part (`<part>-wrapper`: a margin Figma's one gap per frame
185
+ * cannot give). The render has no such element: the part inside stands for it, under the wrapper's parent.
186
+ */
187
+ export declare function withoutAddedWrappers(parts: SpecPart[], measured: Pick<MeasuredSpec, 'parts'>): SpecPart[];
188
+ /**
189
+ * Pairs static parts with measured parts: root to root, text layers by their characters (a TEXT property's default, or
190
+ * fixed characters), then CSS class under the paired parent, then kind and order under the paired parent. A part whose
191
+ * parent the render does not show is not shown either (an error row's icon is not the checkbox's check).
192
+ */
193
+ export declare function pairParts(staticParts: SpecPart[], measured: Pick<MeasuredSpec, 'parts'>, o?: PairOptions): Map<string, string>;
194
+ export declare function compareSpecToMeasured(staticParts: SpecPart[], staticValues: SpecVariant['values'], measured: MeasuredSpec, resolve?: (tokenPath: string) => string | number | undefined, o?: PairOptions): SpecComparison;
195
+ /** One component prop as Storybook knows it (argTypes, docgen), read in the preview page. */
196
+ export interface MeasuredArgType {
197
+ /** `enum`: a closed list of options (a Figma VARIANT axis); `boolean` (a BOOLEAN property or a Disabled state); `text`; `number`; `other` (functions, nodes). */
198
+ kind: 'enum' | 'boolean' | 'text' | 'number' | 'other';
199
+ options?: string[] | undefined;
200
+ /** The component's default (docgen `defaultValue`, or the argType's `table.defaultValue`). */
201
+ default?: string | number | boolean | undefined;
202
+ /** Control type (`select`, `radio`, `boolean`, `text`...). */
203
+ control?: string | undefined;
204
+ }
205
+ /** The props a story rendered with: its args over the component defaults, and the component's prop list. */
206
+ export interface MeasuredProps {
207
+ /** Args with the component defaults applied (`{ variant: 'primary', size: 'md', disabled: false }`). Plain values only (no null). */
208
+ props: Record<string, string | number | boolean>;
209
+ /** The story's own args (initial args plus URL overrides), plain values only. */
210
+ args: Record<string, string | number | boolean>;
211
+ argTypes: Record<string, MeasuredArgType>;
212
+ /** Component display name, when the story names one. */
213
+ component?: string | undefined;
214
+ }
215
+ export type MeasuredState = 'hover' | 'focus-visible' | 'active';
216
+ export interface MeasuredSpecsStory {
217
+ id: string;
218
+ title: string;
219
+ name: string;
220
+ url: string;
221
+ ms: number;
222
+ error?: string | undefined;
223
+ spec?: MeasuredSpec | undefined;
224
+ /** The props the story rendered with (args over component defaults). */
225
+ props?: MeasuredProps['props'] | undefined;
226
+ /** Arg overrides Bridge passed to reach a variant (`{ size: 'lg', disabled: true }`); absent for the story as written. */
227
+ overrides?: Record<string, string | number | boolean> | undefined;
228
+ /** Pseudo state forced on the component (Chrome DevTools forced :hover / :focus-visible / :active). */
229
+ state?: MeasuredState | undefined;
230
+ /** The story is a gallery (several instances): `spec` is its first instance, a fallback when no single-instance story renders the variant. */
231
+ gallery?: boolean | undefined;
232
+ /** A story that renders the component several times: one spec per instance (`spec` is the first). */
233
+ instances?: MeasuredSpec[] | undefined;
234
+ /** Screenshot of the measured root (PNG, the device scale of the run), relative to measured-specs.json. */
235
+ shot?: {
236
+ file: string;
237
+ width: number;
238
+ height: number;
239
+ } | undefined;
240
+ /** Popup stories: how the popup came to show. */
241
+ opened?: 'already' | 'click' | 'hover' | 'focus' | 'none' | undefined;
242
+ }
243
+ /** Per Storybook component (title): its prop list, from the first story measured. */
244
+ export interface MeasuredSpecsComponent {
245
+ title: string;
246
+ name: string;
247
+ argTypes: Record<string, MeasuredArgType>;
248
+ component?: string | undefined;
249
+ /**
250
+ * With --variants: the args crossed, the args left out and why (`no visual effect`: changing it from its default
251
+ * changed nothing the measure reads; `not taken`: the story does not pass it on), and whether the cap cut the product.
252
+ */
253
+ variantPlan?: {
254
+ axes: string[];
255
+ ignored?: Record<string, string> | undefined;
256
+ combos: number;
257
+ capped?: boolean | undefined;
258
+ } | undefined;
259
+ /** Token path -> its value in the measured page (colors `rgb()`, lengths px): the tokens the Figma side names. */
260
+ resolved?: Record<string, string> | undefined;
261
+ }
262
+ export interface MeasuredSpecsFile {
263
+ version: 1;
264
+ storybook: string;
265
+ measuredAt: string;
266
+ stories: MeasuredSpecsStory[];
267
+ components?: MeasuredSpecsComponent[] | undefined;
268
+ /** With --check: one status per component for the contract screen. */
269
+ statuses?: ComponentStatus[] | undefined;
270
+ /** Storybook titles measured to the end, for --resume. */
271
+ done?: string[] | undefined;
272
+ /** With --tokens: every CSS custom property the library defines, resolved per mode, in two tiers. */
273
+ tokens?: MeasuredTokens | undefined;
274
+ }
275
+ /** A Storybook global that switches a theme (light / dark), a brand or a density: one Figma mode per value. */
276
+ export interface MeasuredMode {
277
+ /** Storybook global ("theme", "colorScheme"), or the page attribute a theme hangs on (`data-carbon-theme`). */
278
+ global: string;
279
+ /** Set when the mode is an attribute on the page root, not a Storybook global. */
280
+ attribute?: boolean | undefined;
281
+ /** Its values, the default first. */
282
+ values: string[];
283
+ default: string;
284
+ }
285
+ export interface MeasuredTokenProperty {
286
+ /** The CSS custom property (`--cds-background`). */
287
+ name: string;
288
+ /** Variable name for Figma: the property split on dashes and camel case, library prefix dropped (`background`, `color/fg/default`). */
289
+ path: string;
290
+ /** Two tiers: a literal value is a primitive; a property that is another property (`var(--x)`) is semantic. */
291
+ tier: 'primitive' | 'semantic';
292
+ /** `expression`: a calc() or a function of variables; a primitive holding its resolved value. */
293
+ kind: 'literal' | 'alias' | 'expression';
294
+ type: 'color' | 'length' | 'number' | 'string';
295
+ /** Declared value in the default mode (`var(--color-blue-500)`, `#0969da`, `calc(var(--a) * 2)`). */
296
+ raw: string;
297
+ /** Semantic: the property it aliases in the default mode (`--color-blue-500`). */
298
+ aliasOf?: string | undefined;
299
+ /** Resolved value in the default mode: colors `rgb()`/`rgba()`, lengths in px (number), others as written. */
300
+ value: string | number;
301
+ /** Per mode (`theme:dark`), for the globals that change this property only (every value of that global listed); `value` holds in the others. */
302
+ values?: Record<string, string | number> | undefined;
303
+ /** Per mode: what a semantic property aliases there, when it changes with the mode. */
304
+ aliasOfByMode?: Record<string, string> | undefined;
305
+ /** Selectors besides the root that declare it (a provider, a theme class): `.cds--g100`, `[data-color-mode=dark]`. */
306
+ scopes?: string[] | undefined;
307
+ /**
308
+ * Semantic by value: the CSS writes a literal per theme (compiled themes: Primer, Carbon), and in every mode a
309
+ * primitive holds that same value, so the property is an alias of those primitives.
310
+ */
311
+ inferred?: boolean | undefined;
312
+ /** A measured story's value is tied to it, directly or as the target of an alias it goes through. */
313
+ used?: boolean | undefined;
314
+ }
315
+ export interface MeasuredTokens {
316
+ /** Story the variables were read in. */
317
+ story: string;
318
+ /** Library prefix stripped from paths (`cds`, `chakra`), when one is shared by most properties. */
319
+ prefix?: string | undefined;
320
+ modes: MeasuredMode[];
321
+ properties: MeasuredTokenProperty[];
322
+ counts: {
323
+ properties: number;
324
+ primitives: number;
325
+ semantic: number;
326
+ used: number;
327
+ scoped: number;
328
+ inferred?: number | undefined;
329
+ };
330
+ }
331
+ /**
332
+ * Figma variable path of a custom property: dashes and camel case split into groups, a shared library prefix dropped
333
+ * (`--color-fg-default` -> color/fg/default, `--cds-layer-01` with prefix cds -> layer/01, `--fgColor-muted` -> fg/color/muted).
334
+ */
335
+ export declare function tokenVariablePath(name: string, prefix?: string): string;
336
+ /** The prefix most properties share (`cds`, `chakra`, `bridge`), when at least 60% of 20 or more carry it. */
337
+ export declare function sharedTokenPrefix(names: string[]): string | undefined;
338
+ /**
339
+ * Marks the properties measured stories use: every variable a value's declaration chain names, then every alias
340
+ * target of a used property, transitively (a semantic token needs its primitive). Returns how many are used.
341
+ */
342
+ export declare function markUsedTokens(tokens: MeasuredTokens, stories: Pick<MeasuredSpecsStory, 'spec' | 'instances'>[]): number;
343
+ export declare class MeasuredSpecsError extends Error {
344
+ }
345
+ /**
346
+ * Reads measured-specs.json (text or parsed JSON) and checks its shape: version 1, a storybook URL, stories with ids,
347
+ * and specs with parts and values. Throws MeasuredSpecsError with what is wrong.
348
+ */
349
+ export declare function parseMeasuredSpecsFile(input: string | unknown): MeasuredSpecsFile;
@@ -0,0 +1,25 @@
1
+ import type { MeasuredSpecsFile, MeasuredTokens } from './measured-spec';
2
+ export interface TokenRepoFromMeasure {
3
+ /** Files relative to `root` (`primitives/measured.tokens.json`, `semantic/<mode>.tokens.json`). */
4
+ files: Record<string, string>;
5
+ /** bridge.config.json for them. */
6
+ config: Record<string, unknown>;
7
+ /** CSS custom property -> token path written (`--cds-layer-01` -> layer.01). */
8
+ paths: Map<string, string>;
9
+ report: {
10
+ primitives: number;
11
+ semantic: number;
12
+ palette: number;
13
+ modes: string[];
14
+ skipped: string[];
15
+ };
16
+ }
17
+ /** The two-tier repo for a token harvest (see the top of this file). */
18
+ export declare function tokenRepoFromMeasure(t: MeasuredTokens): TokenRepoFromMeasure;
19
+ /**
20
+ * The measured specs with their values pointing at the tokens `tokenRepoFromMeasure` wrote: a value the measure named
21
+ * after its CSS variable (`cds.layer.01`) becomes the written path (`layer.01`), and a field whose declaration is a
22
+ * variable alone (`var(--cds-button-primary, #0f62fe)`) gets the written path of the first variable of its chain. Other
23
+ * values are kept: a calc() of a token, or a value that only matches one, stays a literal.
24
+ */
25
+ export declare function withRepoTokenPaths(file: MeasuredSpecsFile, paths: Map<string, string>): MeasuredSpecsFile;
@@ -0,0 +1,51 @@
1
+ import { type ComponentSpec, type SpecCoverage, type SpecTransition } from './component-spec';
2
+ /** A motion token as the page shows it: the token name (mono) and its value in words ("75 ms"). */
3
+ export interface MotionValue {
4
+ token?: string | undefined;
5
+ value: string;
6
+ }
7
+ export interface MotionRow {
8
+ /** The part that moves, when the component has several ("Popup", "Checkbox item"). */
9
+ part?: string | undefined;
10
+ /** What makes it move, designer words ("Hover", "Open", "Check and uncheck"). */
11
+ when: string;
12
+ /** What changes ("Background and text color"). */
13
+ what: string;
14
+ duration: MotionValue;
15
+ easing: MotionValue | null;
16
+ }
17
+ export interface MotionDocs {
18
+ /** One sentence: what animates, or that nothing does. */
19
+ summary: string;
20
+ rows: MotionRow[];
21
+ /** What reduced motion does, one sentence; null when nothing animates. */
22
+ reduced: string | null;
23
+ /** Whether to show a Part column (several parts move). */
24
+ showPart: boolean;
25
+ /** Motion tokens the component's CSS uses for motion the rows do not list (a tab indicator sliding). */
26
+ unlisted: string[];
27
+ }
28
+ /** CSS properties in designer words, joined: ["background-color", "color"] -> "Background and text color". */
29
+ export declare function propertyWords(props: string[]): string;
30
+ /** A duration in ms, with its token. */
31
+ export declare const durationValue: (t: Pick<SpecTransition, "duration" | "durationToken">) => MotionValue;
32
+ /** An easing in words, with its token: motion.easing.enter -> "starts fast, lands softly". */
33
+ export declare function easingValue(t: Pick<SpecTransition, 'easing' | 'easingToken'>): MotionValue;
34
+ /** The part a set draws, in words: "Combobox/Popup" -> "Popup", "MenuCheckboxItem" -> "Checkbox item". */
35
+ export declare function partLabel(spec: Pick<ComponentSpec, 'name' | 'component' | 'view'>, component: string): string;
36
+ /** A moment a set moves: what makes it move ("Hover", "Open"), the transition, the properties it animates. */
37
+ export interface MotionMoment {
38
+ when: string;
39
+ t: SpecTransition;
40
+ props: string[];
41
+ }
42
+ /**
43
+ * The moments a set moves, from its interactions and its opening and closing: one per trigger and speed (Hover,
44
+ * Press, Check, Uncheck, Open, Close). Instant changes are left out.
45
+ */
46
+ export declare function motionMoments(spec: Pick<ComponentSpec, 'name' | 'variants' | 'interactions' | 'motion'>): MotionMoment[];
47
+ /**
48
+ * The section for one component: its sets (specs whose `component`, or name, is the component), and its Figma coverage
49
+ * entry for the components the generator does not read (drafted, layout helpers).
50
+ */
51
+ export declare function motionDocs(component: string, specs: ComponentSpec[], coverage?: Pick<SpecCoverage, 'status' | 'reason'>, codeTokens?: string[]): MotionDocs;
@@ -1,6 +1,6 @@
1
1
  import { type BridgeConfig } from '../config';
2
2
  import { LayeredTokenSet } from '../layered';
3
- import { type CssFixEdit } from '../audit/report';
3
+ import { type CssFixEdit, type CssFixKept } from '../audit/report';
4
4
  import { DesignSystemIndex } from '../audit/ds-index';
5
5
  import type { AllowlistEntry, AuditReport } from '../audit/types';
6
6
  export interface LoadedDesignSystem {
@@ -40,8 +40,16 @@ export interface RunAuditOptions {
40
40
  export declare function loadAllowlist(path: string): AllowlistEntry[];
41
41
  /** Audit a product folder against a design system. */
42
42
  export declare function runAudit(target: string, opts?: RunAuditOptions): AuditReport;
43
- /** Plan (and optionally write) the safe CSS autofix for every CSS/SCSS/Less file under `target`. */
44
- export declare function fixCss(target: string, ds: DesignSystemIndex, write: boolean): {
43
+ /**
44
+ * Plan (and optionally write) the safe CSS autofix for every CSS/SCSS/Less file under `target`, with the audit's own
45
+ * rules: the files bridge.config.json excludes from the audit (audit.exclude) are left alone, and so are the values an
46
+ * ignore comment or the allowlist keeps (returned in `kept`).
47
+ */
48
+ export declare function fixCss(target: string, ds: DesignSystemIndex, write: boolean, opts?: {
49
+ exclude?: string[] | undefined;
50
+ allowlist?: AllowlistEntry[] | undefined;
51
+ }): {
45
52
  file: string;
46
53
  edits: CssFixEdit[];
54
+ kept: CssFixKept[];
47
55
  }[];
@@ -6,3 +6,4 @@ export * from './spec-css';
6
6
  export * from './spec-motion';
7
7
  export * from './suggestion-apply-node';
8
8
  export * from './fs-source';
9
+ export * from './measure';