@opendata-ai/openchart-core 8.0.0-rc.8 → 8.0.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 (82) hide show
  1. package/dist/index.d.ts +461 -56
  2. package/dist/index.js +62 -24
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +1 -1
  5. package/dist/styles.css.map +1 -1
  6. package/package.json +1 -2
  7. package/schema/chart.schema.json +373 -67
  8. package/schema/table.schema.json +35 -1
  9. package/schema/vizspec.schema.json +950 -152
  10. package/src/accessibility/__tests__/alt-text.test.ts +0 -110
  11. package/src/accessibility/__tests__/aria.test.ts +0 -125
  12. package/src/accessibility/alt-text.ts +0 -155
  13. package/src/accessibility/aria.ts +0 -75
  14. package/src/accessibility/index.ts +0 -6
  15. package/src/colors/__tests__/colorblind.test.ts +0 -75
  16. package/src/colors/__tests__/contrast.test.ts +0 -119
  17. package/src/colors/__tests__/palettes.test.ts +0 -74
  18. package/src/colors/colorblind.ts +0 -131
  19. package/src/colors/contrast.ts +0 -143
  20. package/src/colors/index.ts +0 -36
  21. package/src/colors/palettes.ts +0 -206
  22. package/src/helpers/__tests__/deep-merge.test.ts +0 -54
  23. package/src/helpers/__tests__/spec-builders.test.ts +0 -338
  24. package/src/helpers/deep-merge.ts +0 -29
  25. package/src/helpers/spec-builders.ts +0 -479
  26. package/src/index.ts +0 -215
  27. package/src/labels/__tests__/collision.test.ts +0 -310
  28. package/src/labels/collision.ts +0 -249
  29. package/src/labels/index.ts +0 -13
  30. package/src/layout/__tests__/chrome.test.ts +0 -208
  31. package/src/layout/__tests__/text-measure.test.ts +0 -57
  32. package/src/layout/chrome.ts +0 -470
  33. package/src/layout/index.ts +0 -18
  34. package/src/layout/text-measure.ts +0 -404
  35. package/src/layout/text-wrap.ts +0 -93
  36. package/src/locale/__tests__/format.test.ts +0 -606
  37. package/src/locale/format.ts +0 -459
  38. package/src/locale/index.ts +0 -21
  39. package/src/responsive/__tests__/breakpoints.test.ts +0 -146
  40. package/src/responsive/__tests__/metrics.test.ts +0 -52
  41. package/src/responsive/breakpoints.ts +0 -172
  42. package/src/responsive/index.ts +0 -53
  43. package/src/responsive/metrics.ts +0 -299
  44. package/src/schema/__tests__/generated-artifacts.test.ts +0 -42
  45. package/src/schema/__tests__/schema.test.ts +0 -179
  46. package/src/styles/__tests__/reduced-motion-selectors.test.ts +0 -28
  47. package/src/styles/animation.css +0 -208
  48. package/src/styles/base.css +0 -102
  49. package/src/styles/chrome.css +0 -174
  50. package/src/styles/dark.css +0 -44
  51. package/src/styles/graph.css +0 -135
  52. package/src/styles/index.css +0 -28
  53. package/src/styles/keyframes.css +0 -151
  54. package/src/styles/legend.css +0 -18
  55. package/src/styles/reduced-motion.css +0 -67
  56. package/src/styles/series-search.css +0 -153
  57. package/src/styles/sparkline.css +0 -16
  58. package/src/styles/table-animation.css +0 -93
  59. package/src/styles/table.css +0 -398
  60. package/src/styles/token-definitions.ts +0 -199
  61. package/src/styles/tokens.css +0 -156
  62. package/src/styles/tooltip.css +0 -126
  63. package/src/styles/you-draw-it.css +0 -126
  64. package/src/theme/__tests__/dark-mode.test.ts +0 -232
  65. package/src/theme/__tests__/defaults.test.ts +0 -73
  66. package/src/theme/__tests__/resolve.test.ts +0 -277
  67. package/src/theme/dark-mode.ts +0 -258
  68. package/src/theme/defaults.ts +0 -110
  69. package/src/theme/index.ts +0 -8
  70. package/src/theme/presets.ts +0 -64
  71. package/src/theme/resolve.ts +0 -312
  72. package/src/types/__tests__/encoding.test.ts +0 -368
  73. package/src/types/__tests__/gradient.test.ts +0 -95
  74. package/src/types/__tests__/spec.test.ts +0 -499
  75. package/src/types/encoding.ts +0 -280
  76. package/src/types/events.ts +0 -154
  77. package/src/types/index.ts +0 -289
  78. package/src/types/layout.ts +0 -2001
  79. package/src/types/schema-roots.ts +0 -32
  80. package/src/types/spec.ts +0 -2906
  81. package/src/types/table.ts +0 -108
  82. package/src/types/theme.ts +0 -209
@@ -1,470 +0,0 @@
1
- /**
2
- * Chrome layout computation.
3
- *
4
- * Takes a Chrome spec + resolved theme and produces a ResolvedChrome
5
- * with computed text positions, styles, and total chrome heights.
6
- *
7
- * Supports three chrome modes:
8
- * - full: all chrome elements rendered at normal size
9
- * - compact: title only, no subtitle/source/byline/footer
10
- * - hidden: no chrome at all (maximizes chart area)
11
- *
12
- * Font sizes scale down continuously at narrow widths to keep
13
- * chrome proportional to the container.
14
- */
15
-
16
- import type { ChromeMode } from '../responsive/breakpoints';
17
- import type {
18
- MeasureTextFn,
19
- ResolvedChrome,
20
- ResolvedChromeElement,
21
- TextStyle,
22
- } from '../types/layout';
23
- import type { Chrome, ChromeText } from '../types/spec';
24
- import type { ChromeDefaults, ResolvedTheme } from '../types/theme';
25
- import {
26
- BRAND_FONT_SIZE,
27
- BRAND_MIN_WIDTH,
28
- BRAND_RESERVE_WIDTH,
29
- COMPACT_WIDTH,
30
- estimateCharWidth,
31
- estimateTextHeight,
32
- } from './text-measure';
33
-
34
- // ---------------------------------------------------------------------------
35
- // Helpers
36
- // ---------------------------------------------------------------------------
37
-
38
- /** Normalize a chrome field to text + optional style and offset overrides. */
39
- function normalizeChromeText(
40
- value: string | ChromeText | undefined,
41
- ): { text: string; style?: ChromeText['style']; offset?: ChromeText['offset'] } | null {
42
- if (value === undefined) return null;
43
- if (typeof value === 'string') return { text: value };
44
- return { text: value.text, style: value.style, offset: value.offset };
45
- }
46
-
47
- /**
48
- * Scale a font size based on container width. Only applies to default sizes
49
- * (not user overrides). Scales from 100% at >= 500px down to 72% at <= 250px.
50
- */
51
- function scaleFontSize(baseFontSize: number, width: number): number {
52
- if (width >= 500) return baseFontSize;
53
- if (width <= 250) return Math.max(Math.round(baseFontSize * 0.72), 10);
54
- const t = (width - 250) / 250;
55
- return Math.max(Math.round(baseFontSize * (0.72 + t * 0.28)), 10);
56
- }
57
-
58
- /** Build a TextStyle from chrome defaults + optional overrides, with width-based scaling. */
59
- function buildTextStyle(
60
- defaults: ChromeDefaults,
61
- fontFamily: string,
62
- textColor: string,
63
- width: number,
64
- overrides?: ChromeText['style'],
65
- ): TextStyle {
66
- const hasExplicitSize = overrides?.fontSize !== undefined;
67
- const baseFontSize = overrides?.fontSize ?? defaults.fontSize;
68
- const fontSize = hasExplicitSize ? baseFontSize : scaleFontSize(baseFontSize, width);
69
-
70
- // No dominantBaseline: chrome y positions are top-edge coordinates and
71
- // renderers convert to the alphabetic baseline via textAscent(). WebKit
72
- // renders `hanging` from different font metrics than Blink and never
73
- // inherits it into tspans (bugs 139258/297455), which shifted wrapped
74
- // titles above the container on iOS Safari.
75
- return {
76
- fontFamily: overrides?.fontFamily ?? fontFamily,
77
- fontSize,
78
- fontWeight: overrides?.fontWeight ?? defaults.fontWeight,
79
- fill: overrides?.color ?? textColor ?? defaults.color,
80
- lineHeight: defaults.lineHeight,
81
- textAnchor: 'start',
82
- };
83
- }
84
-
85
- /**
86
- * Estimate how many lines text will wrap to, given a max width.
87
- * Uses character-count word-wrapping that matches the SVG renderer's
88
- * wrapText behavior (word-boundary breaks, same charWidth heuristic).
89
- * Returns at least 1.
90
- */
91
- function estimateLineCount(
92
- text: string,
93
- style: TextStyle,
94
- maxWidth: number,
95
- measureText?: MeasureTextFn,
96
- ): number {
97
- if (maxWidth <= 0) return 1;
98
-
99
- // Split on explicit newlines first, then estimate wrapping per segment
100
- const segments = text.split('\n');
101
- if (segments.length > 1) {
102
- return segments.reduce((total, segment) => {
103
- return (
104
- total +
105
- (segment.length === 0 ? 1 : estimateLineCount(segment, style, maxWidth, measureText))
106
- );
107
- }, 0);
108
- }
109
-
110
- // Use real text measurement when available, fall back to heuristic
111
- if (measureText) {
112
- const textWidth = measureText(text, style.fontSize, style.fontWeight).width;
113
- if (textWidth <= maxWidth) return 1;
114
-
115
- const words = text.split(' ');
116
- let lines = 1;
117
- let current = '';
118
-
119
- for (const word of words) {
120
- const candidate = current ? `${current} ${word}` : word;
121
- const candidateWidth = measureText(candidate, style.fontSize, style.fontWeight).width;
122
- if (candidateWidth > maxWidth && current) {
123
- lines++;
124
- current = word;
125
- } else {
126
- current = candidate;
127
- }
128
- }
129
-
130
- return lines;
131
- }
132
-
133
- const charWidth = estimateCharWidth(style.fontSize, style.fontWeight);
134
- const maxChars = Math.floor(maxWidth / charWidth);
135
-
136
- if (text.length <= maxChars) return 1;
137
-
138
- const words = text.split(' ');
139
- let lines = 1;
140
- let current = '';
141
-
142
- for (const word of words) {
143
- const candidate = current ? `${current} ${word}` : word;
144
- if (candidate.length > maxChars && current) {
145
- lines++;
146
- current = word;
147
- } else {
148
- current = candidate;
149
- }
150
- }
151
-
152
- return lines;
153
- }
154
-
155
- // ---------------------------------------------------------------------------
156
- // Public API
157
- // ---------------------------------------------------------------------------
158
-
159
- /**
160
- * Line-height multiplier for the auto-thinning footnote list.
161
- *
162
- * Exported because the chrome renderer steps each footnote line down by it
163
- * while the band height below is computed from it -- the two have to agree, or
164
- * the last line drifts outside the band that was reserved for it.
165
- */
166
- export const FOOTNOTE_LINE_HEIGHT = 1.3;
167
- /** Gap below the footnote list, separating it from the source row. */
168
- const FOOTNOTE_BAND_GAP = 4;
169
-
170
- /**
171
- * Vertical space a footnote list of `count` lines occupies below the plot.
172
- *
173
- * Single source of truth, deliberately: the engine reserves this band in the
174
- * bottom margin, the chrome renderer shifts the source row down by it, and the
175
- * brand watermark shifts by it too. When those three disagree the footnotes
176
- * land on top of the watermark, which is exactly the bug this centralizes away.
177
- */
178
- export function footnoteBandHeight(count: number, theme: ResolvedTheme): number {
179
- if (count <= 0) return 0;
180
- return count * theme.fonts.sizes.small * FOOTNOTE_LINE_HEIGHT + FOOTNOTE_BAND_GAP;
181
- }
182
-
183
- /**
184
- * Compute resolved chrome layout from a Chrome spec and resolved theme.
185
- *
186
- * Produces positioned text elements and total chrome heights (top and bottom).
187
- * Top chrome: title, subtitle. Bottom chrome: source, byline, footer.
188
- *
189
- * @param chrome - The Chrome spec from the user's VizSpec.
190
- * @param theme - The fully resolved theme.
191
- * @param width - Total available width in pixels.
192
- * @param measureText - Optional real text measurement function from the adapter.
193
- * @param chromeMode - Chrome display mode: full, compact (title only), or hidden.
194
- * @param padding - Override padding (for scaled padding from dimensions).
195
- * @param watermark - Whether the brand watermark renders (affects bottom space).
196
- * @param bottomLegendHeight - Reserved height for a bottom-positioned legend
197
- * (legend bounds height + gap). When > 0, source/byline/footer y positions
198
- * are shifted down by this amount so the chrome stacks BELOW the legend
199
- * rather than colliding with it. The returned `bottomHeight` includes this
200
- * reservation, so callers should not double-reserve it in margin math.
201
- */
202
- export function computeChrome(
203
- chrome: Chrome | undefined,
204
- theme: ResolvedTheme,
205
- width: number,
206
- measureText?: MeasureTextFn,
207
- chromeMode: ChromeMode = 'full',
208
- padding?: number,
209
- watermark: boolean = true,
210
- bottomLegendHeight: number = 0,
211
- ): ResolvedChrome {
212
- if (!chrome || chromeMode === 'hidden') {
213
- // Brand watermark is also skipped at cramped sizes (height < 200px triggers
214
- // hidden mode, and those containers are typically < BRAND_MIN_WIDTH), so
215
- // bottomHeight: 0 is safe here.
216
- return { topHeight: 0, bottomHeight: 0 };
217
- }
218
-
219
- const pad = padding ?? theme.spacing.padding;
220
- const chromeGap = theme.spacing.chromeGap;
221
- // Subtract a small buffer beyond padding so the heuristic char-width
222
- // estimate triggers word-wrap before the real font overflows the container.
223
- const WRAP_SAFETY_BUFFER = 5;
224
- const maxWidth = width - pad * 2 - WRAP_SAFETY_BUFFER;
225
- const fontFamily = theme.fonts.family;
226
-
227
- // Track vertical cursor for top elements
228
- let topY = pad;
229
- const topElements: Partial<Pick<ResolvedChrome, 'eyebrow' | 'title' | 'subtitle'>> = {};
230
-
231
- // Eyebrow (hidden in compact mode — same rule as subtitle, keeps the
232
- // title alone at narrow viewports).
233
- const eyebrowNorm = chromeMode === 'compact' ? null : normalizeChromeText(chrome.eyebrow);
234
- if (eyebrowNorm) {
235
- const style = buildTextStyle(
236
- theme.chrome.eyebrow,
237
- fontFamily,
238
- theme.chrome.eyebrow.color,
239
- width,
240
- eyebrowNorm.style,
241
- );
242
- const lineCount = estimateLineCount(eyebrowNorm.text, style, maxWidth, measureText);
243
- const element: ResolvedChromeElement = {
244
- text: eyebrowNorm.text,
245
- x: pad + (eyebrowNorm.offset?.dx ?? 0),
246
- y: topY + (eyebrowNorm.offset?.dy ?? 0),
247
- maxWidth,
248
- style,
249
- };
250
- topElements.eyebrow = element;
251
- topY += estimateTextHeight(style.fontSize, lineCount, style.lineHeight) + chromeGap;
252
- }
253
-
254
- // Title
255
- const titleNorm = normalizeChromeText(chrome.title);
256
- if (titleNorm) {
257
- const style = buildTextStyle(
258
- theme.chrome.title,
259
- fontFamily,
260
- theme.chrome.title.color,
261
- width,
262
- titleNorm.style,
263
- );
264
- const lineCount = estimateLineCount(titleNorm.text, style, maxWidth, measureText);
265
- const element: ResolvedChromeElement = {
266
- text: titleNorm.text,
267
- x: pad + (titleNorm.offset?.dx ?? 0),
268
- y: topY + (titleNorm.offset?.dy ?? 0),
269
- maxWidth,
270
- style,
271
- };
272
- topElements.title = element;
273
- topY += estimateTextHeight(style.fontSize, lineCount, style.lineHeight) + chromeGap;
274
- }
275
-
276
- // Subtitle (hidden in compact mode)
277
- const subtitleNorm = chromeMode === 'compact' ? null : normalizeChromeText(chrome.subtitle);
278
- if (subtitleNorm) {
279
- const style = buildTextStyle(
280
- theme.chrome.subtitle,
281
- fontFamily,
282
- theme.chrome.subtitle.color,
283
- width,
284
- subtitleNorm.style,
285
- );
286
- const lineCount = estimateLineCount(subtitleNorm.text, style, maxWidth, measureText);
287
- const element: ResolvedChromeElement = {
288
- text: subtitleNorm.text,
289
- x: pad + (subtitleNorm.offset?.dx ?? 0),
290
- y: topY + (subtitleNorm.offset?.dy ?? 0),
291
- maxWidth,
292
- style,
293
- };
294
- topElements.subtitle = element;
295
- topY += estimateTextHeight(style.fontSize, lineCount, style.lineHeight) + chromeGap;
296
- }
297
-
298
- // Add chromeToChart gap if there are any top elements. Tighten on narrow
299
- // viewports so the subtitle doesn't float far above a legend or chart area.
300
- const hasTopChrome = eyebrowNorm || titleNorm || subtitleNorm;
301
- const chromeToChart =
302
- width < COMPACT_WIDTH ? Math.min(theme.spacing.chromeToChart, 2) : theme.spacing.chromeToChart;
303
- const topHeight = hasTopChrome ? topY - pad + chromeToChart - chromeGap : 0;
304
-
305
- // Bottom chrome text hidden in compact mode, but brand watermark still
306
- // renders for wide-enough charts. Reserve space so it doesn't overflow.
307
- if (chromeMode === 'compact') {
308
- let compactBottom = 0;
309
- if (watermark && width >= BRAND_MIN_WIDTH) {
310
- const brandHeight = estimateTextHeight(BRAND_FONT_SIZE, 1);
311
- compactBottom = theme.spacing.chartToFooter + brandHeight + pad + bottomLegendHeight;
312
- } else if (bottomLegendHeight > 0) {
313
- // No bottom chrome content but a bottom legend was reserved upstream.
314
- // Surface the reservation through bottomHeight so margin math stays
315
- // additive and consistent with full mode.
316
- compactBottom = bottomLegendHeight;
317
- }
318
- return {
319
- topHeight,
320
- bottomHeight: compactBottom,
321
- ...topElements,
322
- };
323
- }
324
-
325
- // Bottom elements: source, byline, footer, and an optional custom brand
326
- // (`chrome.brand`). When a custom brand is supplied it suppresses the default
327
- // tryOpenData.ai watermark and renders right-anchored on the same baseline.
328
- const brandNorm = normalizeChromeText(chrome.brand);
329
- const showWatermark = watermark && !brandNorm;
330
- // Reserve space on the right for the brand watermark or custom brand so the
331
- // left-anchored bottom chrome items don't overlap.
332
- const shouldReserveBrandWidth = (showWatermark || !!brandNorm) && width >= BRAND_MIN_WIDTH;
333
- const bottomMaxWidth = maxWidth - (shouldReserveBrandWidth ? BRAND_RESERVE_WIDTH : 0);
334
- const bottomElements: Partial<Pick<ResolvedChrome, 'source' | 'byline' | 'footer'>> = {};
335
- let bottomHeight = 0;
336
-
337
- const bottomItems: Array<{
338
- key: 'source' | 'byline' | 'footer';
339
- norm: { text: string; style?: ChromeText['style']; offset?: ChromeText['offset'] };
340
- defaults: ChromeDefaults;
341
- }> = [];
342
-
343
- const sourceNorm = normalizeChromeText(chrome.source);
344
- if (sourceNorm) {
345
- bottomItems.push({
346
- key: 'source',
347
- norm: sourceNorm,
348
- defaults: theme.chrome.source,
349
- });
350
- }
351
-
352
- const bylineNorm = normalizeChromeText(chrome.byline);
353
- if (bylineNorm) {
354
- bottomItems.push({
355
- key: 'byline',
356
- norm: bylineNorm,
357
- defaults: theme.chrome.byline,
358
- });
359
- }
360
-
361
- const footerNorm = normalizeChromeText(chrome.footer);
362
- if (footerNorm) {
363
- bottomItems.push({
364
- key: 'footer',
365
- norm: footerNorm,
366
- defaults: theme.chrome.footer,
367
- });
368
- }
369
-
370
- if (bottomItems.length > 0) {
371
- bottomHeight += theme.spacing.chartToFooter;
372
- // Push bottom chrome below the bottom legend (if reserved). Stored y values
373
- // include this offset so renderers don't need to know about the legend band.
374
- bottomHeight += bottomLegendHeight;
375
-
376
- for (const item of bottomItems) {
377
- const style = buildTextStyle(
378
- item.defaults,
379
- fontFamily,
380
- item.defaults.color,
381
- width,
382
- item.norm.style,
383
- );
384
- const lineCount = estimateLineCount(item.norm.text, style, bottomMaxWidth, measureText);
385
- const height = estimateTextHeight(style.fontSize, lineCount, style.lineHeight);
386
-
387
- // y positions will be computed relative to the bottom of the
388
- // chart area by the engine. We store offsets from bottom start.
389
- bottomElements[item.key] = {
390
- text: item.norm.text,
391
- x: pad + (item.norm.offset?.dx ?? 0),
392
- y: bottomHeight + (item.norm.offset?.dy ?? 0), // offset from where bottom chrome starts
393
- maxWidth: bottomMaxWidth,
394
- style,
395
- };
396
-
397
- bottomHeight += height + chromeGap;
398
- }
399
-
400
- // Remove trailing gap
401
- bottomHeight -= chromeGap;
402
-
403
- // Ensure bottom height accommodates the brand watermark, which renders
404
- // at the same Y as the first bottom chrome item but is taller (20px font
405
- // vs 12px source). Without this, the brand overflows the SVG viewBox.
406
- if (showWatermark && width >= BRAND_MIN_WIDTH) {
407
- const brandHeight = estimateTextHeight(BRAND_FONT_SIZE, 1);
408
- // firstItemY is chartToFooter (the Y offset of the first bottom item).
409
- // The brand needs brandHeight below that point; bottom chrome content
410
- // needs (bottomHeight - chartToFooter). Take the max.
411
- const contentBelowFirstItem = bottomHeight - theme.spacing.chartToFooter;
412
- if (brandHeight > contentBelowFirstItem) {
413
- bottomHeight += brandHeight - contentBelowFirstItem;
414
- }
415
- }
416
-
417
- // Add bottom padding
418
- bottomHeight += pad;
419
- } else if (showWatermark && width >= BRAND_MIN_WIDTH) {
420
- // No bottom chrome items, but brand watermark still renders.
421
- // Reserve space: chartToFooter gap + brand text height + padding,
422
- // plus the bottom-legend reservation so the watermark sits below it.
423
- const brandHeight = estimateTextHeight(BRAND_FONT_SIZE, 1);
424
- bottomHeight = theme.spacing.chartToFooter + brandHeight + pad + bottomLegendHeight;
425
- } else if (bottomLegendHeight > 0) {
426
- // No bottom chrome content and no watermark, but a bottom legend was
427
- // reserved upstream. Surface the reservation so callers don't need to
428
- // re-add it on top of bottomHeight.
429
- bottomHeight = bottomLegendHeight;
430
- }
431
-
432
- // Custom brand is right-anchored on the same row as the first bottom chrome
433
- // item. Compute its style/position once we know whether bottom chrome exists.
434
- let brandElement: ResolvedChromeElement | undefined;
435
- if (brandNorm && width >= BRAND_MIN_WIDTH) {
436
- const brandStyle = buildTextStyle(
437
- theme.chrome.footer,
438
- fontFamily,
439
- theme.chrome.footer.color,
440
- width,
441
- brandNorm.style,
442
- );
443
- brandStyle.textAnchor = 'end';
444
- // Y matches the first bottom item (chartToFooter offset). When there are
445
- // no bottom items, the brand becomes the sole footer element and we need
446
- // to allocate the same baseline.
447
- const brandY =
448
- bottomItems.length > 0 ? theme.spacing.chartToFooter : theme.spacing.chartToFooter;
449
- brandElement = {
450
- text: brandNorm.text,
451
- x: width - pad + (brandNorm.offset?.dx ?? 0),
452
- y: brandY + (brandNorm.offset?.dy ?? 0),
453
- maxWidth: BRAND_RESERVE_WIDTH,
454
- style: brandStyle,
455
- };
456
- // Ensure bottomHeight reserves space when brand is the only footer item.
457
- if (bottomItems.length === 0) {
458
- const brandHeight = estimateTextHeight(brandStyle.fontSize, 1, brandStyle.lineHeight);
459
- bottomHeight = theme.spacing.chartToFooter + brandHeight + pad;
460
- }
461
- }
462
-
463
- return {
464
- topHeight,
465
- bottomHeight,
466
- ...topElements,
467
- ...bottomElements,
468
- ...(brandElement ? { brand: brandElement } : {}),
469
- };
470
- }
@@ -1,18 +0,0 @@
1
- /**
2
- * Layout module barrel export.
3
- */
4
-
5
- export { computeChrome, FOOTNOTE_LINE_HEIGHT, footnoteBandHeight } from './chrome';
6
- export {
7
- BRAND_FONT_SIZE,
8
- BRAND_MIN_WIDTH,
9
- BRAND_RESERVE_WIDTH,
10
- COMPACT_WIDTH,
11
- estimateCharWidth,
12
- estimateTextHeight,
13
- estimateTextWidth,
14
- heuristicMeasure,
15
- resolveMeasurer,
16
- textAscent,
17
- } from './text-measure';
18
- export { wrapText } from './text-wrap';