@cfasim-ui/docs 0.4.10 → 0.4.12

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.
@@ -0,0 +1,507 @@
1
+ /**
2
+ * Date axis support: parsing, auto-detection, tick selection, and
3
+ * formatting for chart x-axes that carry temporal data. All functions
4
+ * are pure (no Vue reactivity, no DOM); chart components call into this
5
+ * module from their computed setup.
6
+ *
7
+ * Design notes:
8
+ * - Parsing is regex-based, not `Date.parse`. The ES spec parses bare
9
+ * `YYYY-MM-DD` as UTC but offset-less `YYYY-MM-DDTHH:mm:ss` as local,
10
+ * which makes a `timezone` prop incoherent. Manual parsing keeps the
11
+ * timezone interpretation consistent.
12
+ * - `isDateLike` deliberately rejects plain numbers so existing numeric
13
+ * demos (generation indices, day counters) aren't misclassified.
14
+ * - Tick stepping for month/year (and day/week in local mode) goes
15
+ * through `Date` field math so DST and month-length irregularities
16
+ * don't drift the tick boundaries.
17
+ */
18
+
19
+ export type DateTickUnit =
20
+ | "year"
21
+ | "month"
22
+ | "week"
23
+ | "day"
24
+ | "hour"
25
+ | "minute"
26
+ | "second";
27
+
28
+ export type DateTimezone = "utc" | "local";
29
+
30
+ export type DateFormatPreset =
31
+ | "iso"
32
+ | "iso-datetime"
33
+ | "year"
34
+ | "month-year"
35
+ | "month-day"
36
+ | "day"
37
+ | "time"
38
+ | "datetime"
39
+ | "medium";
40
+
41
+ /**
42
+ * How to render a tick label on a date axis. Accepts:
43
+ * - A preset name (`"iso"`, `"month-year"`, ...).
44
+ * - An `Intl.DateTimeFormatOptions` literal for full control.
45
+ * - A function receiving the tick's epoch-ms and the tick unit the
46
+ * chart picked. Useful for unit-aware custom formatting.
47
+ */
48
+ export type DateFormat =
49
+ | DateFormatPreset
50
+ | Intl.DateTimeFormatOptions
51
+ | ((ms: number, unit?: DateTickUnit) => string);
52
+
53
+ const ISO_DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
54
+ const ISO_DATETIME_RE =
55
+ /^(\d{4})-(\d{2})-(\d{2})[Tt ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3}))?)?(Z|[+-]\d{2}:?\d{2})?$/;
56
+
57
+ const MS_PER_SECOND = 1000;
58
+ const MS_PER_MINUTE = 60 * MS_PER_SECOND;
59
+ const MS_PER_HOUR = 60 * MS_PER_MINUTE;
60
+ const MS_PER_DAY = 24 * MS_PER_HOUR;
61
+ const MS_PER_WEEK = 7 * MS_PER_DAY;
62
+ const MS_PER_MONTH_APPROX = 30 * MS_PER_DAY;
63
+ const MS_PER_YEAR_APPROX = 365 * MS_PER_DAY;
64
+
65
+ /**
66
+ * Candidate tick intervals sorted by ascending duration. `pickInterval`
67
+ * walks this list in order and returns the smallest entry whose `ms`
68
+ * is at least the rough per-tick duration the caller is targeting,
69
+ * giving at most ~`targetCount` ticks. Year step set is locked to
70
+ * `{1,2,5,10,25,50,100}` (no "3-year" step).
71
+ */
72
+ interface TickInterval {
73
+ unit: DateTickUnit;
74
+ step: number;
75
+ ms: number;
76
+ }
77
+ const TICK_INTERVALS: readonly TickInterval[] = [
78
+ { unit: "second", step: 1, ms: 1 * MS_PER_SECOND },
79
+ { unit: "second", step: 5, ms: 5 * MS_PER_SECOND },
80
+ { unit: "second", step: 15, ms: 15 * MS_PER_SECOND },
81
+ { unit: "second", step: 30, ms: 30 * MS_PER_SECOND },
82
+ { unit: "minute", step: 1, ms: 1 * MS_PER_MINUTE },
83
+ { unit: "minute", step: 5, ms: 5 * MS_PER_MINUTE },
84
+ { unit: "minute", step: 15, ms: 15 * MS_PER_MINUTE },
85
+ { unit: "minute", step: 30, ms: 30 * MS_PER_MINUTE },
86
+ { unit: "hour", step: 1, ms: 1 * MS_PER_HOUR },
87
+ { unit: "hour", step: 3, ms: 3 * MS_PER_HOUR },
88
+ { unit: "hour", step: 6, ms: 6 * MS_PER_HOUR },
89
+ { unit: "hour", step: 12, ms: 12 * MS_PER_HOUR },
90
+ { unit: "day", step: 1, ms: 1 * MS_PER_DAY },
91
+ { unit: "day", step: 2, ms: 2 * MS_PER_DAY },
92
+ { unit: "week", step: 1, ms: 1 * MS_PER_WEEK },
93
+ { unit: "month", step: 1, ms: 1 * MS_PER_MONTH_APPROX },
94
+ { unit: "month", step: 3, ms: 3 * MS_PER_MONTH_APPROX },
95
+ { unit: "month", step: 6, ms: 6 * MS_PER_MONTH_APPROX },
96
+ { unit: "year", step: 1, ms: 1 * MS_PER_YEAR_APPROX },
97
+ { unit: "year", step: 2, ms: 2 * MS_PER_YEAR_APPROX },
98
+ { unit: "year", step: 5, ms: 5 * MS_PER_YEAR_APPROX },
99
+ { unit: "year", step: 10, ms: 10 * MS_PER_YEAR_APPROX },
100
+ { unit: "year", step: 25, ms: 25 * MS_PER_YEAR_APPROX },
101
+ { unit: "year", step: 50, ms: 50 * MS_PER_YEAR_APPROX },
102
+ { unit: "year", step: 100, ms: 100 * MS_PER_YEAR_APPROX },
103
+ ];
104
+
105
+ const MAX_TICK_ITER = 1000;
106
+
107
+ /**
108
+ * Parse `v` into an epoch-ms timestamp under the given timezone.
109
+ * Accepts `Date` instances and ISO-shaped strings; returns `null` for
110
+ * anything else (including plain `number`s — see `isDateLike`).
111
+ */
112
+ export function parseDate(v: unknown, tz: DateTimezone): number | null {
113
+ if (v instanceof Date) {
114
+ const t = v.getTime();
115
+ return Number.isFinite(t) ? t : null;
116
+ }
117
+ if (typeof v !== "string") return null;
118
+
119
+ const dm = ISO_DATE_RE.exec(v);
120
+ if (dm) {
121
+ const y = +dm[1];
122
+ const mo = +dm[2] - 1;
123
+ const d = +dm[3];
124
+ if (tz === "utc") return Date.UTC(y, mo, d);
125
+ return new Date(y, mo, d).getTime();
126
+ }
127
+
128
+ const tm = ISO_DATETIME_RE.exec(v);
129
+ if (tm) {
130
+ const y = +tm[1];
131
+ const mo = +tm[2] - 1;
132
+ const d = +tm[3];
133
+ const h = +tm[4];
134
+ const mi = +tm[5];
135
+ const se = tm[6] ? +tm[6] : 0;
136
+ // Regex caps the fractional-second group at 3 digits, so this is
137
+ // always 0..999.
138
+ const ms = tm[7] ? Number("0." + tm[7]) * 1000 : 0;
139
+ const offset = tm[8];
140
+ if (offset) {
141
+ // Explicit offset overrides the prop's tz interpretation.
142
+ if (offset === "Z" || offset === "z") {
143
+ return Date.UTC(y, mo, d, h, mi, se, ms);
144
+ }
145
+ const sign = offset[0] === "+" ? 1 : -1;
146
+ const offHour = +offset.slice(1, 3);
147
+ const offMin = +offset.slice(-2);
148
+ const offsetMs = sign * (offHour * 60 + offMin) * MS_PER_MINUTE;
149
+ return Date.UTC(y, mo, d, h, mi, se, ms) - offsetMs;
150
+ }
151
+ if (tz === "utc") return Date.UTC(y, mo, d, h, mi, se, ms);
152
+ return new Date(y, mo, d, h, mi, se, ms).getTime();
153
+ }
154
+
155
+ return null;
156
+ }
157
+
158
+ /**
159
+ * Whether `v` looks like a date value to the auto-detector. Strict:
160
+ * `Date` instances or ISO-shaped strings only. Plain numbers are *not*
161
+ * considered date-like so numeric demos can't be silently promoted to
162
+ * a date axis.
163
+ */
164
+ export function isDateLike(v: unknown): boolean {
165
+ if (v instanceof Date) return Number.isFinite(v.getTime());
166
+ if (typeof v !== "string") return false;
167
+ return ISO_DATE_RE.test(v) || ISO_DATETIME_RE.test(v);
168
+ }
169
+
170
+ /**
171
+ * Whether every entry of `values` is date-like and parses cleanly. An
172
+ * empty array is *not* considered all-dates (auto-detection should
173
+ * stay opt-in by content).
174
+ */
175
+ export function isAllDates(
176
+ values: ArrayLike<unknown>,
177
+ tz: DateTimezone,
178
+ ): boolean {
179
+ if (values.length === 0) return false;
180
+ for (let i = 0; i < values.length; i++) {
181
+ const v = values[i];
182
+ if (!isDateLike(v)) return false;
183
+ if (parseDate(v, tz) === null) return false;
184
+ }
185
+ return true;
186
+ }
187
+
188
+ /**
189
+ * Pick the smallest tick interval whose duration is at least the rough
190
+ * per-tick budget (`span / targetCount`). Guarantees at most
191
+ * ~`targetCount` ticks.
192
+ */
193
+ function chooseInterval(spanMs: number, targetCount: number): TickInterval {
194
+ const rough = spanMs / Math.max(1, targetCount);
195
+ for (const candidate of TICK_INTERVALS) {
196
+ if (rough <= candidate.ms) return candidate;
197
+ }
198
+ return TICK_INTERVALS[TICK_INTERVALS.length - 1];
199
+ }
200
+
201
+ function snapToUnit(ms: number, unit: DateTickUnit, tz: DateTimezone): number {
202
+ const d = new Date(ms);
203
+ if (tz === "utc") {
204
+ switch (unit) {
205
+ case "second":
206
+ return Math.floor(ms / MS_PER_SECOND) * MS_PER_SECOND;
207
+ case "minute":
208
+ return Math.floor(ms / MS_PER_MINUTE) * MS_PER_MINUTE;
209
+ case "hour":
210
+ return Math.floor(ms / MS_PER_HOUR) * MS_PER_HOUR;
211
+ case "day":
212
+ return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
213
+ case "week": {
214
+ // ISO 8601 week starts Monday. JS day: Sun=0..Sat=6.
215
+ const dayIndex = d.getUTCDay();
216
+ const daysSinceMonday = (dayIndex + 6) % 7;
217
+ return Date.UTC(
218
+ d.getUTCFullYear(),
219
+ d.getUTCMonth(),
220
+ d.getUTCDate() - daysSinceMonday,
221
+ );
222
+ }
223
+ case "month":
224
+ return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
225
+ case "year":
226
+ return Date.UTC(d.getUTCFullYear(), 0, 1);
227
+ }
228
+ }
229
+ switch (unit) {
230
+ case "second":
231
+ return Math.floor(ms / MS_PER_SECOND) * MS_PER_SECOND;
232
+ case "minute":
233
+ return Math.floor(ms / MS_PER_MINUTE) * MS_PER_MINUTE;
234
+ case "hour":
235
+ return new Date(
236
+ d.getFullYear(),
237
+ d.getMonth(),
238
+ d.getDate(),
239
+ d.getHours(),
240
+ ).getTime();
241
+ case "day":
242
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
243
+ case "week": {
244
+ const dayIndex = d.getDay();
245
+ const daysSinceMonday = (dayIndex + 6) % 7;
246
+ return new Date(
247
+ d.getFullYear(),
248
+ d.getMonth(),
249
+ d.getDate() - daysSinceMonday,
250
+ ).getTime();
251
+ }
252
+ case "month":
253
+ return new Date(d.getFullYear(), d.getMonth(), 1).getTime();
254
+ case "year":
255
+ return new Date(d.getFullYear(), 0, 1).getTime();
256
+ }
257
+ }
258
+
259
+ function addUnit(
260
+ ms: number,
261
+ unit: DateTickUnit,
262
+ step: number,
263
+ tz: DateTimezone,
264
+ ): number {
265
+ if (unit === "second") return ms + step * MS_PER_SECOND;
266
+ if (unit === "minute") return ms + step * MS_PER_MINUTE;
267
+ if (unit === "hour" && tz === "utc") return ms + step * MS_PER_HOUR;
268
+ if (unit === "week" && tz === "utc") return ms + step * MS_PER_WEEK;
269
+
270
+ const d = new Date(ms);
271
+ if (tz === "utc") {
272
+ switch (unit) {
273
+ case "day":
274
+ return Date.UTC(
275
+ d.getUTCFullYear(),
276
+ d.getUTCMonth(),
277
+ d.getUTCDate() + step,
278
+ d.getUTCHours(),
279
+ d.getUTCMinutes(),
280
+ d.getUTCSeconds(),
281
+ d.getUTCMilliseconds(),
282
+ );
283
+ case "month":
284
+ return Date.UTC(
285
+ d.getUTCFullYear(),
286
+ d.getUTCMonth() + step,
287
+ d.getUTCDate(),
288
+ d.getUTCHours(),
289
+ d.getUTCMinutes(),
290
+ d.getUTCSeconds(),
291
+ d.getUTCMilliseconds(),
292
+ );
293
+ case "year":
294
+ return Date.UTC(
295
+ d.getUTCFullYear() + step,
296
+ d.getUTCMonth(),
297
+ d.getUTCDate(),
298
+ d.getUTCHours(),
299
+ d.getUTCMinutes(),
300
+ d.getUTCSeconds(),
301
+ d.getUTCMilliseconds(),
302
+ );
303
+ }
304
+ }
305
+ // Local mode: Date field math handles DST and month length.
306
+ switch (unit) {
307
+ case "hour":
308
+ return new Date(
309
+ d.getFullYear(),
310
+ d.getMonth(),
311
+ d.getDate(),
312
+ d.getHours() + step,
313
+ d.getMinutes(),
314
+ d.getSeconds(),
315
+ d.getMilliseconds(),
316
+ ).getTime();
317
+ case "day":
318
+ return new Date(
319
+ d.getFullYear(),
320
+ d.getMonth(),
321
+ d.getDate() + step,
322
+ d.getHours(),
323
+ d.getMinutes(),
324
+ d.getSeconds(),
325
+ d.getMilliseconds(),
326
+ ).getTime();
327
+ case "week":
328
+ return new Date(
329
+ d.getFullYear(),
330
+ d.getMonth(),
331
+ d.getDate() + step * 7,
332
+ d.getHours(),
333
+ d.getMinutes(),
334
+ d.getSeconds(),
335
+ d.getMilliseconds(),
336
+ ).getTime();
337
+ case "month":
338
+ return new Date(
339
+ d.getFullYear(),
340
+ d.getMonth() + step,
341
+ d.getDate(),
342
+ d.getHours(),
343
+ d.getMinutes(),
344
+ d.getSeconds(),
345
+ d.getMilliseconds(),
346
+ ).getTime();
347
+ case "year":
348
+ return new Date(
349
+ d.getFullYear() + step,
350
+ d.getMonth(),
351
+ d.getDate(),
352
+ d.getHours(),
353
+ d.getMinutes(),
354
+ d.getSeconds(),
355
+ d.getMilliseconds(),
356
+ ).getTime();
357
+ }
358
+ // Unreachable — the early returns above cover second/minute/hour-utc/week-utc.
359
+ return ms;
360
+ }
361
+
362
+ /**
363
+ * Choose tick values for a date axis spanning `[minMs, maxMs]`. The
364
+ * returned `unit` lets the default formatter pick a unit-appropriate
365
+ * preset (year ticks → "year", month → "month-year", day → "month-day",
366
+ * etc.) — same trick Vega-Lite uses.
367
+ */
368
+ export function pickDateTicks(
369
+ minMs: number,
370
+ maxMs: number,
371
+ targetCount: number,
372
+ tz: DateTimezone,
373
+ ): { values: number[]; unit: DateTickUnit } {
374
+ if (
375
+ !Number.isFinite(minMs) ||
376
+ !Number.isFinite(maxMs) ||
377
+ minMs >= maxMs ||
378
+ targetCount < 1
379
+ ) {
380
+ return { values: [], unit: "day" };
381
+ }
382
+ const span = maxMs - minMs;
383
+ const { unit, step } = chooseInterval(span, targetCount);
384
+
385
+ let v = snapToUnit(minMs, unit, tz);
386
+ let safety = 0;
387
+ while (v < minMs && safety < MAX_TICK_ITER) {
388
+ v = addUnit(v, unit, step, tz);
389
+ safety++;
390
+ }
391
+
392
+ const values: number[] = [];
393
+ for (let i = 0; i < MAX_TICK_ITER && v <= maxMs; i++) {
394
+ values.push(v);
395
+ v = addUnit(v, unit, step, tz);
396
+ }
397
+ return { values, unit };
398
+ }
399
+
400
+ const PRESET_OPTIONS: Record<DateFormatPreset, Intl.DateTimeFormatOptions> = {
401
+ // "iso" and "iso-datetime" route through manual formatters below so
402
+ // the output stays exactly YYYY-MM-DD regardless of locale.
403
+ iso: { year: "numeric", month: "2-digit", day: "2-digit" },
404
+ "iso-datetime": {
405
+ year: "numeric",
406
+ month: "2-digit",
407
+ day: "2-digit",
408
+ hour: "2-digit",
409
+ minute: "2-digit",
410
+ second: "2-digit",
411
+ hourCycle: "h23",
412
+ },
413
+ year: { year: "numeric" },
414
+ "month-year": { month: "short", year: "numeric" },
415
+ "month-day": { month: "short", day: "numeric" },
416
+ day: { day: "numeric" },
417
+ time: { hour: "2-digit", minute: "2-digit", hourCycle: "h23" },
418
+ datetime: {
419
+ month: "short",
420
+ day: "numeric",
421
+ hour: "2-digit",
422
+ minute: "2-digit",
423
+ hourCycle: "h23",
424
+ },
425
+ medium: { dateStyle: "medium" } as Intl.DateTimeFormatOptions,
426
+ };
427
+
428
+ const UNIT_DEFAULT_PRESET: Record<DateTickUnit, DateFormatPreset> = {
429
+ year: "year",
430
+ month: "month-year",
431
+ week: "month-day",
432
+ day: "month-day",
433
+ hour: "time",
434
+ minute: "time",
435
+ second: "time",
436
+ };
437
+
438
+ /** All valid preset names. Exported for the disjointness invariant test. */
439
+ export const DATE_FORMAT_PRESETS = Object.keys(
440
+ PRESET_OPTIONS,
441
+ ) as readonly DateFormatPreset[];
442
+
443
+ function pad2(n: number): string {
444
+ return n < 10 ? "0" + n : String(n);
445
+ }
446
+
447
+ function formatIso(ms: number, tz: DateTimezone): string {
448
+ const d = new Date(ms);
449
+ if (tz === "utc") {
450
+ return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;
451
+ }
452
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
453
+ }
454
+
455
+ function formatIsoDateTime(ms: number, tz: DateTimezone): string {
456
+ const d = new Date(ms);
457
+ if (tz === "utc") {
458
+ return (
459
+ `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}` +
460
+ `T${pad2(d.getUTCHours())}:${pad2(d.getUTCMinutes())}:${pad2(d.getUTCSeconds())}Z`
461
+ );
462
+ }
463
+ return (
464
+ `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}` +
465
+ `T${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`
466
+ );
467
+ }
468
+
469
+ function isPreset(name: string): name is DateFormatPreset {
470
+ return name in PRESET_OPTIONS;
471
+ }
472
+
473
+ /**
474
+ * Format an epoch-ms timestamp into a tick label. When `format` is
475
+ * undefined, picks a preset based on the tick `unit` (Vega-Lite style:
476
+ * year ticks read as "2024", month ticks as "Jan 2024", etc.).
477
+ */
478
+ export function formatDate(
479
+ ms: number,
480
+ format: DateFormat | undefined,
481
+ tz: DateTimezone,
482
+ unit?: DateTickUnit,
483
+ ): string {
484
+ if (typeof format === "function") return format(ms, unit);
485
+
486
+ let presetName: DateFormatPreset | null = null;
487
+ let options: Intl.DateTimeFormatOptions;
488
+ if (format === undefined) {
489
+ presetName = unit ? UNIT_DEFAULT_PRESET[unit] : "iso";
490
+ options = PRESET_OPTIONS[presetName];
491
+ } else if (typeof format === "string") {
492
+ if (!isPreset(format)) {
493
+ throw new Error(`Unknown date format preset: "${format}"`);
494
+ }
495
+ presetName = format;
496
+ options = PRESET_OPTIONS[presetName];
497
+ } else {
498
+ options = format;
499
+ }
500
+
501
+ if (presetName === "iso") return formatIso(ms, tz);
502
+ if (presetName === "iso-datetime") return formatIsoDateTime(ms, tz);
503
+
504
+ const finalOpts: Intl.DateTimeFormatOptions =
505
+ tz === "utc" ? { ...options, timeZone: "UTC" } : options;
506
+ return new Intl.DateTimeFormat(undefined, finalOpts).format(ms);
507
+ }
@@ -0,0 +1,51 @@
1
+ /* Shared chart styles for the Expand / fullscreen menu item.
2
+ Bundled into @cfasim-ui/charts/style.css via index.ts so it ships
3
+ once for the whole package instead of repeating in every chart SFC. */
4
+
5
+ .line-chart-wrapper:hover .chart-menu-button,
6
+ .bar-chart-wrapper:hover .chart-menu-button,
7
+ .choropleth-wrapper:hover .chart-menu-button,
8
+ .line-chart-wrapper:focus-within .chart-menu-button,
9
+ .bar-chart-wrapper:focus-within .chart-menu-button,
10
+ .choropleth-wrapper:focus-within .chart-menu-button,
11
+ .line-chart-wrapper.is-fullscreen .chart-menu-button,
12
+ .bar-chart-wrapper.is-fullscreen .chart-menu-button,
13
+ .choropleth-wrapper.is-fullscreen .chart-menu-button {
14
+ opacity: 1;
15
+ }
16
+
17
+ .line-chart-wrapper.is-fullscreen,
18
+ .bar-chart-wrapper.is-fullscreen,
19
+ .choropleth-wrapper.is-fullscreen {
20
+ position: fixed;
21
+ inset: 0;
22
+ z-index: var(--cfasim-z-fullscreen, 1000);
23
+ background: var(--color-bg-0, #fff);
24
+ color: var(--color-text, inherit);
25
+ padding: 2em;
26
+ box-sizing: border-box;
27
+ display: flex;
28
+ flex-direction: column;
29
+ justify-content: center;
30
+ }
31
+
32
+ /* ChoroplethMap doesn't go through useChartFoundation, so its SVG keeps
33
+ its prop-driven width/height. Stretch it to fill the expanded box. */
34
+ .choropleth-wrapper.is-fullscreen svg {
35
+ flex: 1 1 auto;
36
+ min-height: 0;
37
+ height: 100%;
38
+ width: 100%;
39
+ }
40
+
41
+ .chart-sr-only {
42
+ position: absolute;
43
+ width: 1px;
44
+ height: 1px;
45
+ padding: 0;
46
+ margin: -1px;
47
+ overflow: hidden;
48
+ clip: rect(0, 0, 0, 0);
49
+ white-space: nowrap;
50
+ border: 0;
51
+ }
@@ -16,16 +16,26 @@ export {
16
16
  export { useChartSize, type ChartSizeOptions } from "./useChartSize.js";
17
17
  export {
18
18
  useChartPadding,
19
- INLINE_LEGEND_HEIGHT,
19
+ resolveLabelStyle,
20
+ INLINE_LEGEND_ROW_HEIGHT,
21
+ TITLE_LINE_HEIGHT,
22
+ TITLE_FONT_SIZE,
23
+ TITLE_FONT_WEIGHT,
24
+ AXIS_LABEL_FONT_SIZE,
25
+ TICK_LABEL_FONT_SIZE,
26
+ TICK_LABEL_OPACITY,
27
+ LEGEND_FONT_SIZE,
20
28
  type ChartPaddingOptions,
21
29
  type ChartPadding,
22
30
  type ChartBounds,
31
+ type PositionedLegendItem,
23
32
  } from "./useChartPadding.js";
24
33
  export {
25
34
  useChartTooltip,
26
35
  type ChartTooltipOptions,
27
36
  } from "./useChartTooltip.js";
28
37
  export { useChartMenu, type ChartMenuOptions } from "./useChartMenu.js";
38
+ export { useChartFullscreen } from "./useChartFullscreen.js";
29
39
  export { seriesToCsv, categoricalToCsv, type CsvSeries } from "./seriesCsv.js";
30
40
  export { default as ChartAnnotations } from "./ChartAnnotations.vue";
31
41
  export type { ChartAnnotation } from "./annotations.js";
@@ -39,4 +49,18 @@ export type {
39
49
  ChartHoverPayload,
40
50
  ChartTooltipValue,
41
51
  ChartTooltipBaseProps,
52
+ TitleStyle,
53
+ LabelStyle,
42
54
  } from "./chartProps.js";
55
+ export {
56
+ parseDate,
57
+ isDateLike,
58
+ isAllDates,
59
+ pickDateTicks,
60
+ formatDate,
61
+ DATE_FORMAT_PRESETS,
62
+ type DateFormat,
63
+ type DateFormatPreset,
64
+ type DateTickUnit,
65
+ type DateTimezone,
66
+ } from "./dateAxis.js";