@sentropic/design-system-tokens 0.10.0 → 0.10.2
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/dist/anatomy.d.ts +58 -1
- package/dist/anatomy.d.ts.map +1 -1
- package/dist/anatomy.js +1 -1
- package/dist/component.d.ts +341 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/component.js +564 -36
- package/dist/component.js.map +1 -1
- package/package.json +1 -1
package/dist/component.js
CHANGED
|
@@ -26,7 +26,10 @@ const FALLBACK = {
|
|
|
26
26
|
focus: { strategy: "outline", width: "2px", offset: "2px", color: "var(--st-semantic-border-interactive)", inset: "0" },
|
|
27
27
|
// Field style fallback = boxed outline (base Sent Tech). underlineColor /
|
|
28
28
|
// underlineWidth are inert for outline; they only drive filled-underline.
|
|
29
|
-
|
|
29
|
+
// radiusTop "" = inherit the theme's shape radius (resolved in fieldOf).
|
|
30
|
+
// v1.4.0: selectAppearance "auto" (native arrow, base unchanged), no chevron,
|
|
31
|
+
// and the prior 2rem right arrow gap.
|
|
32
|
+
field: { style: "outline", fillBg: "", underlineColor: "", underlineWidth: "1px", radiusTop: "", selectAppearance: "auto", selectChevron: "none", selectPaddingRight: "2rem" }
|
|
30
33
|
};
|
|
31
34
|
function densityOf(f, size) {
|
|
32
35
|
const base = FALLBACK.density[size];
|
|
@@ -40,6 +43,305 @@ function densityOf(f, size) {
|
|
|
40
43
|
fontSize: themed.fontSize ?? base.fontSize
|
|
41
44
|
};
|
|
42
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Button density (F9): the shared control density for `size`, overlaid with any
|
|
48
|
+
* BUTTON-specific override (`buttonDensity`). Adds an optional `paddingInlineEnd`
|
|
49
|
+
* leaf so a button can be asymmetric (Carbon's large trailing gutter) without
|
|
50
|
+
* touching the shared density the 100%-fidelity fields read. When the theme omits
|
|
51
|
+
* `buttonDensity` (base/DSFR), this is identical to `densityOf` → no change, and
|
|
52
|
+
* `paddingInlineEnd` mirrors `paddingInline` (symmetric).
|
|
53
|
+
*/
|
|
54
|
+
function buttonDensityOf(f, size) {
|
|
55
|
+
const base = densityOf(f, size);
|
|
56
|
+
const override = f.buttonDensity?.[size] ?? {};
|
|
57
|
+
const paddingInline = override.paddingInline ?? base.paddingInline;
|
|
58
|
+
return {
|
|
59
|
+
controlHeight: override.controlHeight ?? base.controlHeight,
|
|
60
|
+
paddingBlock: override.paddingBlock ?? base.paddingBlock,
|
|
61
|
+
paddingInline,
|
|
62
|
+
gap: override.gap ?? base.gap,
|
|
63
|
+
minWidth: override.minWidth ?? base.minWidth,
|
|
64
|
+
fontSize: override.fontSize ?? base.fontSize,
|
|
65
|
+
// Trailing inline padding: an explicit asymmetric value (Carbon) or = paddingInline.
|
|
66
|
+
paddingInlineEnd: override.paddingInlineEnd ?? paddingInline
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Tabs ACTIVE-tab resolution (F7/F8). Resolves the per-theme selected-tab
|
|
71
|
+
* primitive into a flat, CSS-ready set the Tabs component consumes verbatim.
|
|
72
|
+
* Every leaf DEFAULTS to the prior base render (12px/4px padding, inherited
|
|
73
|
+
* font-size, control weight/line-height, transparent active bg, primary text,
|
|
74
|
+
* BOTTOM indicator) so the base Sent Tech tab is byte-identical; DSFR / Carbon
|
|
75
|
+
* override the real selected-tab metrics. `indicatorSide` resolves into two
|
|
76
|
+
* border-width channels so a theme can put its accent on the top edge (DSFR,
|
|
77
|
+
* which then has NO bottom border) or the bottom edge (base / Carbon).
|
|
78
|
+
*/
|
|
79
|
+
function tabsOf(f, controlTypography, indicatorWidth, indicatorColor, activeTextDefault) {
|
|
80
|
+
const t = f.tabs ?? {};
|
|
81
|
+
const indicatorSide = t.indicatorSide ?? "bottom";
|
|
82
|
+
const indicatorMode = t.indicatorMode ?? "border";
|
|
83
|
+
// The indicator lives on ONE edge; the opposite edge collapses to 0 so the
|
|
84
|
+
// active tab matches the reference (DSFR active = border-bottom 0 / top accent).
|
|
85
|
+
const onTop = indicatorSide === "top";
|
|
86
|
+
// "shadow" mode draws the accent as an inset box-shadow so BOTH border sides
|
|
87
|
+
// stay 0 (DSFR, whose real accent is a background-image filet, not a border).
|
|
88
|
+
// "border" mode keeps the real per-side border (base / Carbon) and no shadow.
|
|
89
|
+
const isShadow = indicatorMode === "shadow";
|
|
90
|
+
const shadowOffset = onTop ? indicatorWidth : `-${indicatorWidth}`;
|
|
91
|
+
return {
|
|
92
|
+
activeText: t.activeText || activeTextDefault,
|
|
93
|
+
activeBackground: t.activeBackground || "transparent",
|
|
94
|
+
// G2: resting-tab fill. Default "transparent" (base/Carbon unchanged); DSFR
|
|
95
|
+
// sets a light grey-blue fill so the white active tab reads as raised.
|
|
96
|
+
inactiveBackground: t.inactiveBackground || "transparent",
|
|
97
|
+
activeWeight: t.activeWeight ?? controlTypography.weight,
|
|
98
|
+
paddingBlock: t.paddingBlock ?? "0.75rem",
|
|
99
|
+
paddingInline: t.paddingInline ?? "0.25rem",
|
|
100
|
+
fontSize: t.fontSize ?? "inherit",
|
|
101
|
+
lineHeight: t.lineHeight ?? controlTypography.lineHeight,
|
|
102
|
+
indicatorSide,
|
|
103
|
+
activeBorderTopWidth: isShadow ? "0" : onTop ? indicatorWidth : "0",
|
|
104
|
+
activeBorderBottomWidth: isShadow ? "0" : onTop ? "0" : indicatorWidth,
|
|
105
|
+
activeShadow: isShadow ? `inset 0 ${shadowOffset} 0 0 ${indicatorColor}` : "none"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Button SECONDARY-variant resolution (G1). Resolves the per-theme secondary
|
|
110
|
+
* button surface into a flat, CSS-ready set the Button component consumes
|
|
111
|
+
* verbatim (background / border colour / hover background). Every leaf DEFAULTS
|
|
112
|
+
* to the prior base render (filled `action.secondary`, `border.subtle` stroke,
|
|
113
|
+
* `action.secondaryHover` hover) so the base Sent Tech secondary button is
|
|
114
|
+
* byte-identical; DSFR overrides them to render its OUTLINED secondary button
|
|
115
|
+
* (transparent fill + Bleu France border + light fill on hover).
|
|
116
|
+
*/
|
|
117
|
+
function buttonSecondaryOf(semantic, f) {
|
|
118
|
+
const b = f.buttonSecondary ?? {};
|
|
119
|
+
return {
|
|
120
|
+
background: b.background || semantic.action.secondary,
|
|
121
|
+
border: b.border || semantic.border.subtle,
|
|
122
|
+
hoverBackground: b.hoverBackground || semantic.action.secondaryHover || semantic.action.secondary
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Pagination resolution (F10). Resolves the per-theme pagination primitive into
|
|
127
|
+
* a flat, CSS-ready set the Pagination component consumes verbatim. Every leaf
|
|
128
|
+
* DEFAULTS to the prior base render (1px subtle stroke, radius.md, 0 block /
|
|
129
|
+
* 12px inline padding, 36px min size, filled action.primary active page,
|
|
130
|
+
* inherited font metrics) so the base Sent Tech pagination is byte-identical.
|
|
131
|
+
* DSFR / Carbon override the real active-page metrics.
|
|
132
|
+
*/
|
|
133
|
+
function paginationOf(semantic, f, thin, radiusMd) {
|
|
134
|
+
const p = f.pagination ?? {};
|
|
135
|
+
const border = p.border || semantic.border.subtle;
|
|
136
|
+
const borderWidth = p.borderWidth ?? thin;
|
|
137
|
+
return {
|
|
138
|
+
background: p.background || semantic.surface.default,
|
|
139
|
+
border,
|
|
140
|
+
borderWidth,
|
|
141
|
+
text: p.text || semantic.text.primary,
|
|
142
|
+
radius: p.radius ?? radiusMd,
|
|
143
|
+
activeBackground: p.activeBackground || semantic.action.primary,
|
|
144
|
+
activeText: p.activeText || semantic.action.primaryText,
|
|
145
|
+
// The active page can drop its border (DSFR/Carbon active page has none);
|
|
146
|
+
// default = the resting page border so the base render is unchanged.
|
|
147
|
+
activeBorder: p.activeBorder || border,
|
|
148
|
+
activeBorderWidth: p.activeBorderWidth ?? borderWidth,
|
|
149
|
+
activeWeight: p.activeWeight ?? "inherit",
|
|
150
|
+
disabledText: p.disabledText || semantic.text.muted,
|
|
151
|
+
paddingBlock: p.paddingBlock ?? "0",
|
|
152
|
+
paddingInline: p.paddingInline ?? "0.75rem",
|
|
153
|
+
minSize: p.minSize ?? "2.25rem",
|
|
154
|
+
fontSize: p.fontSize ?? "inherit",
|
|
155
|
+
lineHeight: p.lineHeight ?? "normal",
|
|
156
|
+
letterSpacing: p.letterSpacing ?? "normal"
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Breadcrumb resolution (F10). Resolves the per-theme breadcrumb primitive into
|
|
161
|
+
* a flat set the Breadcrumb component consumes verbatim. Every leaf DEFAULTS to
|
|
162
|
+
* the prior base render (link = text.link, no explicit font metrics → inherited
|
|
163
|
+
* 16px / normal, current 600 weight on the current page). DSFR / Carbon pin the
|
|
164
|
+
* real breadcrumb link colour + typography.
|
|
165
|
+
*/
|
|
166
|
+
function breadcrumbOf(semantic, f) {
|
|
167
|
+
const b = f.breadcrumb ?? {};
|
|
168
|
+
return {
|
|
169
|
+
text: b.text || semantic.text.secondary,
|
|
170
|
+
linkText: b.linkText || semantic.text.link,
|
|
171
|
+
currentText: b.currentText || semantic.text.primary,
|
|
172
|
+
separator: b.separator || semantic.text.muted,
|
|
173
|
+
fontSize: b.fontSize ?? "inherit",
|
|
174
|
+
lineHeight: b.lineHeight ?? "normal",
|
|
175
|
+
letterSpacing: b.letterSpacing ?? "normal",
|
|
176
|
+
currentWeight: b.currentWeight ?? "600"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Alert resolution (P-B). Resolves the per-theme alert primitive into a flat,
|
|
181
|
+
* CSS-ready set the Alert component consumes verbatim. Every leaf DEFAULTS to the
|
|
182
|
+
* prior base render (surface.raised fill, 1px subtle box on top/right/bottom, a
|
|
183
|
+
* 4px left accent edge, 16px padding all sides, inherited font / `normal`
|
|
184
|
+
* line-height) so the base Sent Tech alert is byte-identical. DSFR drops the box
|
|
185
|
+
* + fill (accent becomes a `::before` filet → left border 0); Carbon paints a
|
|
186
|
+
* dark banner with a 3px coloured left bar (a real border).
|
|
187
|
+
*/
|
|
188
|
+
function alertOf(semantic, f, thin, borderStyle) {
|
|
189
|
+
const a = f.alert ?? {};
|
|
190
|
+
// The base box border = 1px subtle on top/right/bottom (the left edge is the
|
|
191
|
+
// accent, sized by accentWidth and coloured per severity by the component).
|
|
192
|
+
const box = `${thin} ${borderStyle} ${semantic.border.subtle}`;
|
|
193
|
+
return {
|
|
194
|
+
background: a.background || semantic.surface.raised,
|
|
195
|
+
text: a.text || semantic.text.primary,
|
|
196
|
+
borderTop: a.borderTop || box,
|
|
197
|
+
borderRight: a.borderRight || box,
|
|
198
|
+
borderBottom: a.borderBottom || box,
|
|
199
|
+
accentWidth: a.accentWidth ?? "0.25rem", // 4px (current)
|
|
200
|
+
filetWidth: a.filetWidth ?? "0", // no filet (base/Carbon use a real left border)
|
|
201
|
+
paddingTop: a.paddingTop ?? "1rem",
|
|
202
|
+
paddingRight: a.paddingRight ?? "1rem",
|
|
203
|
+
paddingBottom: a.paddingBottom ?? "1rem",
|
|
204
|
+
paddingLeft: a.paddingLeft ?? "1rem",
|
|
205
|
+
fontSize: a.fontSize ?? "inherit",
|
|
206
|
+
lineHeight: a.lineHeight ?? "normal",
|
|
207
|
+
letterSpacing: a.letterSpacing ?? "normal",
|
|
208
|
+
accentInfo: a.accentInfo || semantic.feedback.info,
|
|
209
|
+
accentSuccess: a.accentSuccess || semantic.feedback.success,
|
|
210
|
+
accentWarning: a.accentWarning || semantic.feedback.warning,
|
|
211
|
+
accentError: a.accentError || semantic.feedback.error
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Accordion resolution (P-B). Resolves the per-theme accordion-trigger primitive
|
|
216
|
+
* into a flat set the Accordion component consumes verbatim. Every leaf DEFAULTS
|
|
217
|
+
* to the prior base render (14px block / 8px inline padding, inherited font-size,
|
|
218
|
+
* weight 600, `normal` line-height, primary text) so the base Sent Tech accordion
|
|
219
|
+
* is byte-identical. DSFR / Carbon pin the real header metrics.
|
|
220
|
+
*/
|
|
221
|
+
function accordionOf(semantic, f) {
|
|
222
|
+
const a = f.accordion ?? {};
|
|
223
|
+
return {
|
|
224
|
+
text: a.text || semantic.text.primary,
|
|
225
|
+
paddingBlock: a.paddingBlock ?? "0.875rem", // 14px (current)
|
|
226
|
+
paddingInline: a.paddingInline ?? "0.5rem", // 8px (current)
|
|
227
|
+
fontSize: a.fontSize ?? "inherit",
|
|
228
|
+
fontWeight: a.fontWeight ?? "600",
|
|
229
|
+
lineHeight: a.lineHeight ?? "normal"
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Tag resolution (P-C). Resolves the per-theme tag primitive into a flat,
|
|
234
|
+
* CSS-ready set the Tag component consumes verbatim. Every leaf DEFAULTS to the
|
|
235
|
+
* prior base render (pill radius 999px, 4px/10px padding, 12px font, weight 600,
|
|
236
|
+
* line-height 1, no transform, no min-height, NEUTRAL tone = surface.subtle fill
|
|
237
|
+
* + text.secondary text) so the base Sent Tech tag is byte-identical. DSFR /
|
|
238
|
+
* Carbon override the real `.fr-tag` / `.bx--tag` metrics + neutral colours.
|
|
239
|
+
*/
|
|
240
|
+
function tagOf(semantic, f) {
|
|
241
|
+
const t = f.tag ?? {};
|
|
242
|
+
return {
|
|
243
|
+
radius: t.radius ?? "999px",
|
|
244
|
+
paddingBlock: t.paddingBlock ?? "0.25rem", // 4px (current md)
|
|
245
|
+
paddingInline: t.paddingInline ?? "0.625rem", // 10px (current md)
|
|
246
|
+
fontSize: t.fontSize ?? "0.75rem", // 12px (current md)
|
|
247
|
+
fontWeight: t.fontWeight ?? "600",
|
|
248
|
+
lineHeight: t.lineHeight ?? "1",
|
|
249
|
+
letterSpacing: t.letterSpacing ?? "normal",
|
|
250
|
+
textTransform: t.textTransform ?? "none",
|
|
251
|
+
minHeight: t.minHeight ?? "0",
|
|
252
|
+
neutralBackground: t.neutralBackground || semantic.surface.subtle,
|
|
253
|
+
neutralText: t.neutralText || semantic.text.secondary
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Badge resolution (P-C). Resolves the per-theme badge primitive into a flat,
|
|
258
|
+
* CSS-ready set the Badge component consumes verbatim. Every leaf DEFAULTS to
|
|
259
|
+
* the prior base render (pill radius 999px, 4px/8px padding, 12px font, weight
|
|
260
|
+
* 650, line-height 1, no transform, no min-height; tone colours stay the per-tone
|
|
261
|
+
* feedback mix) so the base Sent Tech badge is byte-identical. DSFR overrides the
|
|
262
|
+
* real `.fr-badge` metrics + recolours the INFO tone (the bench-rendered one) to
|
|
263
|
+
* the measured grey badge.
|
|
264
|
+
*/
|
|
265
|
+
function badgeOf(semantic, f) {
|
|
266
|
+
const b = f.badge ?? {};
|
|
267
|
+
return {
|
|
268
|
+
radius: b.radius ?? "999px",
|
|
269
|
+
paddingBlock: b.paddingBlock ?? "0.25rem", // 4px (current)
|
|
270
|
+
paddingInline: b.paddingInline ?? "0.5rem", // 8px (current)
|
|
271
|
+
fontSize: b.fontSize ?? "0.75rem", // 12px (current)
|
|
272
|
+
fontWeight: b.fontWeight ?? "650",
|
|
273
|
+
lineHeight: b.lineHeight ?? "1",
|
|
274
|
+
letterSpacing: b.letterSpacing ?? "normal",
|
|
275
|
+
textTransform: b.textTransform ?? "none",
|
|
276
|
+
minHeight: b.minHeight ?? "0",
|
|
277
|
+
// Default INFO fill reproduces the current `color-mix(... feedback.info 14%,
|
|
278
|
+
// white)`; a theme can replace it with a flat measured colour.
|
|
279
|
+
infoBackground: b.infoBackground || `color-mix(in srgb, ${semantic.feedback.info} 14%, white)`,
|
|
280
|
+
infoText: b.infoText || semantic.feedback.info
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Choice (Checkbox/Radio) LABEL resolution (P-D). Resolves the per-theme label
|
|
285
|
+
* typography into a flat, CSS-ready set the `.st-choice__label` consumes
|
|
286
|
+
* verbatim. Every leaf DEFAULTS to the prior base render (15px font, `normal`
|
|
287
|
+
* line-height + letter-spacing, primary text) so the base Sent Tech
|
|
288
|
+
* checkbox/radio is byte-identical. `radioLineHeight` defaults to the checkbox
|
|
289
|
+
* line-height (single value) so a theme that does not split them stays
|
|
290
|
+
* consistent; Carbon splits 18px (checkbox) / 20px (radio).
|
|
291
|
+
*/
|
|
292
|
+
function choiceOf(semantic, f) {
|
|
293
|
+
const c = f.choice ?? {};
|
|
294
|
+
const labelLineHeight = c.labelLineHeight ?? "normal";
|
|
295
|
+
return {
|
|
296
|
+
labelFontSize: c.labelFontSize ?? "0.9375rem", // 15px (current)
|
|
297
|
+
labelLineHeight,
|
|
298
|
+
radioLineHeight: c.radioLineHeight ?? labelLineHeight,
|
|
299
|
+
labelLetterSpacing: c.labelLetterSpacing ?? "normal",
|
|
300
|
+
labelColor: c.labelColor || semantic.text.primary
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Search FIELD resolution (P-D). Resolves the per-theme search-box padding +
|
|
305
|
+
* input typography into a flat set the `.st-search` consumes verbatim. Every
|
|
306
|
+
* leaf DEFAULTS to the prior base render (0 padding on the wrapper, inherited
|
|
307
|
+
* 16px / `normal` typography) so the base Sent Tech search is byte-identical.
|
|
308
|
+
* The field box (fill / borders / radius) is the shared field anatomy, unchanged.
|
|
309
|
+
*/
|
|
310
|
+
function searchOf(f) {
|
|
311
|
+
const s = f.search ?? {};
|
|
312
|
+
return {
|
|
313
|
+
paddingBlock: s.paddingBlock ?? "0",
|
|
314
|
+
paddingInline: s.paddingInline ?? "0",
|
|
315
|
+
fontSize: s.fontSize ?? "1rem", // 16px (current inherited)
|
|
316
|
+
lineHeight: s.lineHeight ?? "normal",
|
|
317
|
+
letterSpacing: s.letterSpacing ?? "normal"
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Toggle / Switch resolution (P-D). Resolves the per-theme track geometry +
|
|
322
|
+
* colours + label typography into a flat set the Toggle/Switch components
|
|
323
|
+
* consume verbatim. Every leaf DEFAULTS to the prior base render (pill radius
|
|
324
|
+
* 999px, 2px inner padding, 36×20 md track, 16px md thumb, border.strong resting
|
|
325
|
+
* track, action.primary checked track, surface.default thumb, inherited `normal`
|
|
326
|
+
* typography, primary text) so the base Sent Tech toggle is byte-identical.
|
|
327
|
+
*/
|
|
328
|
+
function toggleOf(semantic, f) {
|
|
329
|
+
const t = f.toggle ?? {};
|
|
330
|
+
return {
|
|
331
|
+
trackRadius: t.trackRadius ?? "999px",
|
|
332
|
+
trackPadding: t.trackPadding ?? "0.125rem", // 2px (current)
|
|
333
|
+
trackWidth: t.trackWidth ?? "2.25rem", // 36px (current md)
|
|
334
|
+
trackHeight: t.trackHeight ?? "1.25rem", // 20px (current md)
|
|
335
|
+
thumbSize: t.thumbSize ?? "1rem", // 16px (current md)
|
|
336
|
+
trackColor: t.trackColor || semantic.border.strong,
|
|
337
|
+
trackCheckedColor: t.trackCheckedColor || semantic.action.primary,
|
|
338
|
+
thumbColor: t.thumbColor || semantic.surface.default,
|
|
339
|
+
fontSize: t.fontSize ?? "inherit",
|
|
340
|
+
lineHeight: t.lineHeight ?? "normal",
|
|
341
|
+
letterSpacing: t.letterSpacing ?? "normal",
|
|
342
|
+
textColor: t.textColor || semantic.text.primary
|
|
343
|
+
};
|
|
344
|
+
}
|
|
43
345
|
function typographyOf(f, role) {
|
|
44
346
|
// Widen to TypographyAnatomy so the optional textDecorationHover leaf is
|
|
45
347
|
// readable across all roles (only `link` carries it in the FALLBACK literal).
|
|
@@ -102,25 +404,79 @@ function focusOf(f) {
|
|
|
102
404
|
* borders all = `<borderWidth.thin> solid <border.subtle>`. This reproduces
|
|
103
405
|
* the existing boxed input EXACTLY → no Sent Tech regression.
|
|
104
406
|
* - `filled-underline` (DSFR / Carbon): `fillBg` = the theme's field fill tone,
|
|
105
|
-
* top/right/left = `none`, only
|
|
106
|
-
*
|
|
107
|
-
*
|
|
407
|
+
* top/right/left = `none`, the bottom rule is the only stroke. HOW the bottom
|
|
408
|
+
* rule is drawn depends on the theme's real technique:
|
|
409
|
+
* · DSFR (`underlineAsShadow: true`) draws it as a `box-shadow inset` (its
|
|
410
|
+
* real CSS), so `borderBottom` is `none` and the rule adds no box height.
|
|
411
|
+
* · Carbon (default) genuinely uses a real `border-bottom: 1px solid` — so
|
|
412
|
+
* we keep the geometric `borderBottom` and leave `underline` = `none` to
|
|
413
|
+
* stay pixel-identical to the official `.bx--text-input`.
|
|
414
|
+
*
|
|
415
|
+
* v1.3.0 (additive): `radiusTop` rounds only the field's TOP corners (defaults
|
|
416
|
+
* to the theme's `shapeRadius` so a boxed field stays uniform — no regression);
|
|
417
|
+
* `underline` carries the filled-underline bottom rule as an inset box-shadow
|
|
418
|
+
* when `underlineAsShadow` is set; `focusShadow` composes it with the focus ring.
|
|
108
419
|
*/
|
|
109
|
-
function fieldOf(semantic, f, bw, borderStyle) {
|
|
420
|
+
function fieldOf(semantic, f, bw, borderStyle, shapeRadius, focusBoxShadow) {
|
|
110
421
|
const themed = f.field ?? {};
|
|
111
422
|
const style = (themed.style ?? FALLBACK.field.style);
|
|
112
423
|
const thin = bw.thin ?? "1px";
|
|
424
|
+
// v1.4.0 (F5/F9) — native <select> rendering. These are independent of the
|
|
425
|
+
// outline/filled-underline branch, so resolve them once and spread into each
|
|
426
|
+
// returned FieldAnatomy. selectAppearance "auto" keeps the base native arrow
|
|
427
|
+
// (and its UA-forced `line-height: normal`); "none" lets the anatomy
|
|
428
|
+
// line-height take effect, the chevron then drawn by selectChevron.
|
|
429
|
+
const selectAppearance = themed.selectAppearance ?? FALLBACK.field.selectAppearance;
|
|
430
|
+
const selectChevron = themed.selectChevron ?? FALLBACK.field.selectChevron;
|
|
431
|
+
const selectPaddingRight = themed.selectPaddingRight ?? FALLBACK.field.selectPaddingRight;
|
|
432
|
+
const selectLeaves = { selectAppearance, selectChevron, selectPaddingRight };
|
|
433
|
+
// Top corners inherit the theme's shape radius unless the theme rounds them
|
|
434
|
+
// explicitly (DSFR field = 4px top). Bottom corners always keep shapeRadius.
|
|
435
|
+
const radiusTop = themed.radiusTop || shapeRadius;
|
|
436
|
+
// Compose the field focus box-shadow so the resting underline is never lost
|
|
437
|
+
// incoherently: an outline-strategy theme (focusBoxShadow === "none") keeps
|
|
438
|
+
// the underline; an inset/ring theme stacks its ring + the underline.
|
|
439
|
+
const composeFocus = (underline) => {
|
|
440
|
+
const ring = focusBoxShadow && focusBoxShadow !== "none" ? focusBoxShadow : "";
|
|
441
|
+
if (underline === "none")
|
|
442
|
+
return ring || "none";
|
|
443
|
+
if (!ring)
|
|
444
|
+
return underline; // outline theme: keep the underline at focus
|
|
445
|
+
return `${ring}, ${underline}`; // inset/ring theme: ring + underline
|
|
446
|
+
};
|
|
113
447
|
if (style === "filled-underline") {
|
|
114
448
|
const fillBg = themed.fillBg || semantic.surface.subtle;
|
|
115
449
|
const underlineColor = themed.underlineColor || semantic.border.strong;
|
|
116
450
|
const underlineWidth = themed.underlineWidth || thin;
|
|
451
|
+
// DSFR draws the rule as an inset box-shadow (its real technique, cf. rule
|
|
452
|
+
// `underline-hardcoded-border`); Carbon keeps a real geometric border-bottom
|
|
453
|
+
// (its real technique) so it stays pixel-identical to `.bx--text-input`.
|
|
454
|
+
if (themed.underlineMode === "shadow") {
|
|
455
|
+
const underline = `inset 0 -${underlineWidth} 0 0 ${underlineColor}`;
|
|
456
|
+
return {
|
|
457
|
+
style,
|
|
458
|
+
fillBg,
|
|
459
|
+
borderTop: "none",
|
|
460
|
+
borderRight: "none",
|
|
461
|
+
borderBottom: "none",
|
|
462
|
+
borderLeft: "none",
|
|
463
|
+
radiusTop,
|
|
464
|
+
underline,
|
|
465
|
+
focusShadow: composeFocus(underline),
|
|
466
|
+
...selectLeaves
|
|
467
|
+
};
|
|
468
|
+
}
|
|
117
469
|
return {
|
|
118
470
|
style,
|
|
119
471
|
fillBg,
|
|
120
472
|
borderTop: "none",
|
|
121
473
|
borderRight: "none",
|
|
122
474
|
borderBottom: `${underlineWidth} ${borderStyle} ${underlineColor}`,
|
|
123
|
-
borderLeft: "none"
|
|
475
|
+
borderLeft: "none",
|
|
476
|
+
radiusTop,
|
|
477
|
+
underline: "none",
|
|
478
|
+
focusShadow: composeFocus("none"),
|
|
479
|
+
...selectLeaves
|
|
124
480
|
};
|
|
125
481
|
}
|
|
126
482
|
// outline (default): boxed, 4 equal borders — identical to the prior look.
|
|
@@ -132,7 +488,11 @@ function fieldOf(semantic, f, bw, borderStyle) {
|
|
|
132
488
|
borderTop: border,
|
|
133
489
|
borderRight: border,
|
|
134
490
|
borderBottom: border,
|
|
135
|
-
borderLeft: border
|
|
491
|
+
borderLeft: border,
|
|
492
|
+
radiusTop,
|
|
493
|
+
underline: "none",
|
|
494
|
+
focusShadow: composeFocus("none"),
|
|
495
|
+
...selectLeaves
|
|
136
496
|
};
|
|
137
497
|
}
|
|
138
498
|
/**
|
|
@@ -154,7 +514,10 @@ export function createComponent(semantic, foundation) {
|
|
|
154
514
|
// foundation (radius/density/typography/focus) → the brand reaches anatomy.
|
|
155
515
|
const buttonAnatomy = {
|
|
156
516
|
shape: { radius: foundation.radius.md, borderWidth: bw.thin, borderStyle },
|
|
157
|
-
|
|
517
|
+
// F9: button-specific density (shared control density + optional button-only
|
|
518
|
+
// override) so Carbon's tall, asymmetric primary button doesn't regress the
|
|
519
|
+
// fields that share the control density. Base/DSFR get the shared density.
|
|
520
|
+
density: { sm: buttonDensityOf(foundation, "sm"), md: buttonDensityOf(foundation, "md"), lg: buttonDensityOf(foundation, "lg") },
|
|
158
521
|
typography: typographyOf(foundation, "control"),
|
|
159
522
|
focus,
|
|
160
523
|
icon: { size: icon.md, gap: densityOf(foundation, "md").gap },
|
|
@@ -172,7 +535,9 @@ export function createComponent(semantic, foundation) {
|
|
|
172
535
|
typography: typographyOf(foundation, "field"),
|
|
173
536
|
focus,
|
|
174
537
|
// Field style (v1.2.0): outline (boxed, base) vs filled-underline (DSFR/Carbon).
|
|
175
|
-
|
|
538
|
+
// v1.3.0: radiusTop defaults to the field's own shape radius (radius.md);
|
|
539
|
+
// the underline is an inset box-shadow, composed with the focus ring.
|
|
540
|
+
field: fieldOf(semantic, foundation, bw, borderStyle, foundation.radius.md, focus.boxShadow),
|
|
176
541
|
states: {
|
|
177
542
|
hover: { border: semantic.border.strong },
|
|
178
543
|
focus: { border: semantic.border.interactive },
|
|
@@ -193,30 +558,77 @@ export function createComponent(semantic, foundation) {
|
|
|
193
558
|
disabled: { text: semantic.text.muted, decoration: "none", opacity: disabledOpacity }
|
|
194
559
|
}
|
|
195
560
|
};
|
|
561
|
+
// Card surface (additive): borderWidth defaults to the base `thin` stroke so
|
|
562
|
+
// Sent Tech is unchanged; DSFR/Carbon set it to 0 (their cards/tiles have no
|
|
563
|
+
// border). The fill defaults to surface.raised (base), Carbon overrides it to
|
|
564
|
+
// its $layer-01 tone via `card.background`.
|
|
565
|
+
const cardBorderWidth = foundation.card?.borderWidth ?? bw.thin;
|
|
566
|
+
const cardBackground = foundation.card?.background || semantic.surface.raised;
|
|
567
|
+
// F5 (additive): the card body typography. The base `.st-card` carries NO
|
|
568
|
+
// explicit font-size / line-height / letter-spacing, so the defaults here
|
|
569
|
+
// REPRODUCE that exact render (inherit / normal / normal). DSFR/Carbon pin
|
|
570
|
+
// their real tile body metrics so the card text matches the measured
|
|
571
|
+
// reference instead of `normal`. Family/weight stay on the field role (no
|
|
572
|
+
// visible change — the card already inherits the brand sans + 400).
|
|
573
|
+
const cardTypographyBase = typographyOf(foundation, "field");
|
|
574
|
+
const cardTypography = {
|
|
575
|
+
...cardTypographyBase,
|
|
576
|
+
size: foundation.card?.fontSize ?? "inherit",
|
|
577
|
+
lineHeight: foundation.card?.lineHeight ?? "normal",
|
|
578
|
+
letterSpacing: foundation.card?.letterSpacing ?? "normal"
|
|
579
|
+
};
|
|
196
580
|
const cardAnatomy = {
|
|
197
|
-
shape: { radius: foundation.radius.lg, borderWidth:
|
|
198
|
-
typography:
|
|
581
|
+
shape: { radius: foundation.radius.lg, borderWidth: cardBorderWidth, borderStyle },
|
|
582
|
+
typography: cardTypography,
|
|
199
583
|
focus,
|
|
200
584
|
states: {
|
|
201
585
|
hover: { transform: "translateY(-1px)" }
|
|
202
586
|
}
|
|
203
587
|
};
|
|
588
|
+
const tabsControlTypography = typographyOf(foundation, "control");
|
|
204
589
|
const tabsAnatomy = {
|
|
205
590
|
shape: { radius: foundation.radius.none ?? "0", borderWidth: bw.thin, borderStyle },
|
|
206
591
|
density: { md: densityOf(foundation, "md") },
|
|
207
|
-
typography:
|
|
592
|
+
typography: tabsControlTypography,
|
|
208
593
|
focus,
|
|
209
594
|
states: {
|
|
210
595
|
hover: { text: semantic.text.primary },
|
|
211
596
|
disabled: { opacity: disabledOpacity }
|
|
212
597
|
}
|
|
213
598
|
};
|
|
599
|
+
// F7/F8 — active-tab metrics (additive, per-theme; base render unchanged).
|
|
600
|
+
// The indicator width is the tab's stroke width (thin); `tabsOf` resolves it
|
|
601
|
+
// onto the top edge (DSFR) or the bottom edge (base/Carbon), as a real border
|
|
602
|
+
// (base/Carbon) or an inset box-shadow accent (DSFR).
|
|
603
|
+
const tabsResolved = tabsOf(foundation, tabsControlTypography, bw.thin, semantic.action.primary, semantic.text.primary);
|
|
604
|
+
// G1 — secondary button surface (per theme; base render unchanged). DSFR
|
|
605
|
+
// overrides it to a transparent fill + Bleu France border + text; base/Carbon
|
|
606
|
+
// keep the filled neutral default.
|
|
607
|
+
const buttonSecondary = buttonSecondaryOf(semantic, foundation);
|
|
608
|
+
// F10 — Pagination / Breadcrumb anatomy (per theme; base render unchanged).
|
|
609
|
+
const paginationResolved = paginationOf(semantic, foundation, bw.thin, foundation.radius.md);
|
|
610
|
+
const breadcrumbResolved = breadcrumbOf(semantic, foundation);
|
|
611
|
+
// P-B — Alert / Accordion anatomy (per theme; base render unchanged).
|
|
612
|
+
const alertResolved = alertOf(semantic, foundation, bw.thin, borderStyle);
|
|
613
|
+
const accordionResolved = accordionOf(semantic, foundation);
|
|
614
|
+
// P-C — Tag / Badge anatomy (per theme; base render unchanged).
|
|
615
|
+
const tagResolved = tagOf(semantic, foundation);
|
|
616
|
+
const badgeResolved = badgeOf(semantic, foundation);
|
|
617
|
+
// P-D — Choice (Checkbox/Radio) / Search / Toggle anatomy (per theme; base
|
|
618
|
+
// render unchanged via the resolver defaults).
|
|
619
|
+
const choiceResolved = choiceOf(semantic, foundation);
|
|
620
|
+
const searchResolved = searchOf(foundation);
|
|
621
|
+
const toggleResolved = toggleOf(semantic, foundation);
|
|
214
622
|
return {
|
|
215
623
|
button: {
|
|
216
624
|
radius: foundation.radius.md,
|
|
217
625
|
primaryBackground: semantic.action.primary,
|
|
218
626
|
primaryText: semantic.action.primaryText,
|
|
219
|
-
|
|
627
|
+
// G1: the secondary surface is resolved per theme (transparent + bordered
|
|
628
|
+
// for DSFR's outlined secondary; filled neutral for base/Carbon).
|
|
629
|
+
secondaryBackground: buttonSecondary.background,
|
|
630
|
+
secondaryBorder: buttonSecondary.border,
|
|
631
|
+
secondaryHoverBackground: buttonSecondary.hoverBackground,
|
|
220
632
|
secondaryText: semantic.action.secondaryText,
|
|
221
633
|
anatomy: buttonAnatomy
|
|
222
634
|
},
|
|
@@ -228,17 +640,74 @@ export function createComponent(semantic, foundation) {
|
|
|
228
640
|
anatomy: linkAnatomy
|
|
229
641
|
},
|
|
230
642
|
alert: {
|
|
231
|
-
background
|
|
232
|
-
text
|
|
643
|
+
// Existing leaves keep their names (consumers/docs unchanged); background
|
|
644
|
+
// and text now resolve through `alertOf` (identical defaults = unchanged base).
|
|
645
|
+
background: alertResolved.background,
|
|
646
|
+
text: alertResolved.text,
|
|
233
647
|
border: semantic.border.subtle,
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
648
|
+
// Per-severity accent colours now resolve through `alertOf` (default = the
|
|
649
|
+
// matching feedback role → base unchanged; Carbon overrides accentInfo).
|
|
650
|
+
infoBorder: alertResolved.accentInfo,
|
|
651
|
+
successBorder: alertResolved.accentSuccess,
|
|
652
|
+
warningBorder: alertResolved.accentWarning,
|
|
653
|
+
errorBorder: alertResolved.accentError,
|
|
654
|
+
radius: foundation.radius.lg,
|
|
655
|
+
// P-B additive leaves — per-theme alert anatomy (base = unchanged).
|
|
656
|
+
borderTop: alertResolved.borderTop,
|
|
657
|
+
borderRight: alertResolved.borderRight,
|
|
658
|
+
borderBottom: alertResolved.borderBottom,
|
|
659
|
+
// Left accent: a real left border of `accentWidth` (base/Carbon) OR a
|
|
660
|
+
// `::before` filet of `filetWidth` drawn inside the box (DSFR) so the
|
|
661
|
+
// measured left border stays 0. Both coloured per severity by the component.
|
|
662
|
+
accentWidth: alertResolved.accentWidth,
|
|
663
|
+
filetWidth: alertResolved.filetWidth,
|
|
664
|
+
paddingTop: alertResolved.paddingTop,
|
|
665
|
+
paddingRight: alertResolved.paddingRight,
|
|
666
|
+
paddingBottom: alertResolved.paddingBottom,
|
|
667
|
+
paddingLeft: alertResolved.paddingLeft,
|
|
668
|
+
fontSize: alertResolved.fontSize,
|
|
669
|
+
lineHeight: alertResolved.lineHeight,
|
|
670
|
+
letterSpacing: alertResolved.letterSpacing
|
|
671
|
+
},
|
|
672
|
+
accordion: {
|
|
673
|
+
// P-B — per-theme accordion-trigger anatomy (base = unchanged).
|
|
674
|
+
text: accordionResolved.text,
|
|
675
|
+
paddingBlock: accordionResolved.paddingBlock,
|
|
676
|
+
paddingInline: accordionResolved.paddingInline,
|
|
677
|
+
fontSize: accordionResolved.fontSize,
|
|
678
|
+
fontWeight: accordionResolved.fontWeight,
|
|
679
|
+
lineHeight: accordionResolved.lineHeight
|
|
680
|
+
},
|
|
681
|
+
tag: {
|
|
682
|
+
// P-C — per-theme tag anatomy (base = unchanged via resolver defaults).
|
|
683
|
+
radius: tagResolved.radius,
|
|
684
|
+
paddingBlock: tagResolved.paddingBlock,
|
|
685
|
+
paddingInline: tagResolved.paddingInline,
|
|
686
|
+
fontSize: tagResolved.fontSize,
|
|
687
|
+
fontWeight: tagResolved.fontWeight,
|
|
688
|
+
lineHeight: tagResolved.lineHeight,
|
|
689
|
+
letterSpacing: tagResolved.letterSpacing,
|
|
690
|
+
textTransform: tagResolved.textTransform,
|
|
691
|
+
minHeight: tagResolved.minHeight,
|
|
692
|
+
neutralBackground: tagResolved.neutralBackground,
|
|
693
|
+
neutralText: tagResolved.neutralText
|
|
694
|
+
},
|
|
695
|
+
badge: {
|
|
696
|
+
// P-C — per-theme badge anatomy (base = unchanged via resolver defaults).
|
|
697
|
+
radius: badgeResolved.radius,
|
|
698
|
+
paddingBlock: badgeResolved.paddingBlock,
|
|
699
|
+
paddingInline: badgeResolved.paddingInline,
|
|
700
|
+
fontSize: badgeResolved.fontSize,
|
|
701
|
+
fontWeight: badgeResolved.fontWeight,
|
|
702
|
+
lineHeight: badgeResolved.lineHeight,
|
|
703
|
+
letterSpacing: badgeResolved.letterSpacing,
|
|
704
|
+
textTransform: badgeResolved.textTransform,
|
|
705
|
+
minHeight: badgeResolved.minHeight,
|
|
706
|
+
infoBackground: badgeResolved.infoBackground,
|
|
707
|
+
infoText: badgeResolved.infoText
|
|
239
708
|
},
|
|
240
709
|
card: {
|
|
241
|
-
background:
|
|
710
|
+
background: cardBackground,
|
|
242
711
|
border: semantic.border.subtle,
|
|
243
712
|
radius: foundation.radius.lg,
|
|
244
713
|
shadow: foundation.shadow.subtle,
|
|
@@ -305,9 +774,38 @@ export function createComponent(semantic, foundation) {
|
|
|
305
774
|
checkedBackground: semantic.action.primary,
|
|
306
775
|
checkedText: semantic.action.primaryText,
|
|
307
776
|
border: semantic.border.subtle,
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
777
|
+
// Existing switch colour leaves now resolve through `toggleOf` (identical
|
|
778
|
+
// defaults = unchanged base; DSFR/Carbon set their measured track colours).
|
|
779
|
+
switchTrack: toggleResolved.trackColor,
|
|
780
|
+
switchTrackChecked: toggleResolved.trackCheckedColor,
|
|
781
|
+
switchThumb: toggleResolved.thumbColor,
|
|
782
|
+
// P-D additive — Choice (Checkbox/Radio) label typography (base = unchanged).
|
|
783
|
+
choiceLabelFontSize: choiceResolved.labelFontSize,
|
|
784
|
+
choiceLabelLineHeight: choiceResolved.labelLineHeight,
|
|
785
|
+
choiceRadioLineHeight: choiceResolved.radioLineHeight,
|
|
786
|
+
choiceLabelLetterSpacing: choiceResolved.labelLetterSpacing,
|
|
787
|
+
choiceLabelColor: choiceResolved.labelColor,
|
|
788
|
+
// P-D additive — Toggle/Switch track geometry + label typography (base =
|
|
789
|
+
// unchanged via the resolver defaults).
|
|
790
|
+
toggleTrackRadius: toggleResolved.trackRadius,
|
|
791
|
+
toggleTrackPadding: toggleResolved.trackPadding,
|
|
792
|
+
toggleTrackWidth: toggleResolved.trackWidth,
|
|
793
|
+
toggleTrackHeight: toggleResolved.trackHeight,
|
|
794
|
+
toggleThumbSize: toggleResolved.thumbSize,
|
|
795
|
+
toggleFontSize: toggleResolved.fontSize,
|
|
796
|
+
toggleLineHeight: toggleResolved.lineHeight,
|
|
797
|
+
toggleLetterSpacing: toggleResolved.letterSpacing,
|
|
798
|
+
toggleTextColor: toggleResolved.textColor
|
|
799
|
+
},
|
|
800
|
+
search: {
|
|
801
|
+
// P-D additive — Search field box padding + input typography (base =
|
|
802
|
+
// unchanged via the resolver defaults). The field box (fill/border/radius)
|
|
803
|
+
// stays the shared `control.anatomy.field` already mapped like Input.
|
|
804
|
+
paddingBlock: searchResolved.paddingBlock,
|
|
805
|
+
paddingInline: searchResolved.paddingInline,
|
|
806
|
+
fontSize: searchResolved.fontSize,
|
|
807
|
+
lineHeight: searchResolved.lineHeight,
|
|
808
|
+
letterSpacing: searchResolved.letterSpacing
|
|
311
809
|
},
|
|
312
810
|
overlay: {
|
|
313
811
|
backdrop: semantic.surface.overlay,
|
|
@@ -367,27 +865,57 @@ export function createComponent(semantic, foundation) {
|
|
|
367
865
|
radius: foundation.radius.lg
|
|
368
866
|
},
|
|
369
867
|
tabs: {
|
|
370
|
-
|
|
868
|
+
// F7/F8: active-tab roles/metrics resolved per theme (base render = current).
|
|
869
|
+
activeText: tabsResolved.activeText,
|
|
870
|
+
activeBackground: tabsResolved.activeBackground,
|
|
871
|
+
// G2: resting-tab fill (default transparent; DSFR = light grey-blue).
|
|
872
|
+
inactiveBackground: tabsResolved.inactiveBackground,
|
|
873
|
+
activeWeight: tabsResolved.activeWeight,
|
|
371
874
|
inactiveText: semantic.text.secondary,
|
|
372
875
|
border: semantic.border.subtle,
|
|
373
876
|
indicator: semantic.action.primary,
|
|
374
877
|
panelBackground: semantic.surface.default,
|
|
878
|
+
tabPaddingBlock: tabsResolved.paddingBlock,
|
|
879
|
+
tabPaddingInline: tabsResolved.paddingInline,
|
|
880
|
+
tabFontSize: tabsResolved.fontSize,
|
|
881
|
+
tabLineHeight: tabsResolved.lineHeight,
|
|
882
|
+
activeBorderTopWidth: tabsResolved.activeBorderTopWidth,
|
|
883
|
+
activeBorderBottomWidth: tabsResolved.activeBorderBottomWidth,
|
|
884
|
+
activeShadow: tabsResolved.activeShadow,
|
|
375
885
|
anatomy: tabsAnatomy
|
|
376
886
|
},
|
|
377
887
|
pagination: {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
888
|
+
// Existing leaves keep their names (consumers/docs unchanged); they now
|
|
889
|
+
// resolve through `paginationOf` (identical defaults = unchanged base).
|
|
890
|
+
background: paginationResolved.background,
|
|
891
|
+
border: paginationResolved.border,
|
|
892
|
+
text: paginationResolved.text,
|
|
893
|
+
activeBackground: paginationResolved.activeBackground,
|
|
894
|
+
activeText: paginationResolved.activeText,
|
|
895
|
+
disabledText: paginationResolved.disabledText,
|
|
896
|
+
radius: paginationResolved.radius,
|
|
897
|
+
// F10 additive leaves — per-theme active-page metrics (base = unchanged).
|
|
898
|
+
borderWidth: paginationResolved.borderWidth,
|
|
899
|
+
activeBorder: paginationResolved.activeBorder,
|
|
900
|
+
activeBorderWidth: paginationResolved.activeBorderWidth,
|
|
901
|
+
activeWeight: paginationResolved.activeWeight,
|
|
902
|
+
paddingBlock: paginationResolved.paddingBlock,
|
|
903
|
+
paddingInline: paginationResolved.paddingInline,
|
|
904
|
+
minSize: paginationResolved.minSize,
|
|
905
|
+
fontSize: paginationResolved.fontSize,
|
|
906
|
+
lineHeight: paginationResolved.lineHeight,
|
|
907
|
+
letterSpacing: paginationResolved.letterSpacing
|
|
385
908
|
},
|
|
386
909
|
breadcrumb: {
|
|
387
|
-
text:
|
|
388
|
-
currentText:
|
|
389
|
-
separator:
|
|
390
|
-
linkText:
|
|
910
|
+
text: breadcrumbResolved.text,
|
|
911
|
+
currentText: breadcrumbResolved.currentText,
|
|
912
|
+
separator: breadcrumbResolved.separator,
|
|
913
|
+
linkText: breadcrumbResolved.linkText,
|
|
914
|
+
// F10 additive leaves — per-theme breadcrumb typography (base = unchanged).
|
|
915
|
+
fontSize: breadcrumbResolved.fontSize,
|
|
916
|
+
lineHeight: breadcrumbResolved.lineHeight,
|
|
917
|
+
letterSpacing: breadcrumbResolved.letterSpacing,
|
|
918
|
+
currentWeight: breadcrumbResolved.currentWeight
|
|
391
919
|
},
|
|
392
920
|
sideNav: {
|
|
393
921
|
background: semantic.surface.default,
|