@pharos-ds/charts 0.0.0-stage → 1.0.10

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 (139) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/LICENSE +24 -0
  3. package/README.md +117 -2
  4. package/dist/Chart.d.ts +62 -0
  5. package/dist/Chart.d.ts.map +1 -0
  6. package/dist/Chart.js +401 -0
  7. package/dist/ChartAxis.d.ts +37 -0
  8. package/dist/ChartAxis.d.ts.map +1 -0
  9. package/dist/ChartAxis.js +233 -0
  10. package/dist/ChartContext.d.ts +4 -0
  11. package/dist/ChartContext.d.ts.map +1 -0
  12. package/dist/ChartContext.js +15 -0
  13. package/dist/ChartGrid.d.ts +26 -0
  14. package/dist/ChartGrid.d.ts.map +1 -0
  15. package/dist/ChartGrid.js +118 -0
  16. package/dist/ChartLegend.d.ts +14 -0
  17. package/dist/ChartLegend.d.ts.map +1 -0
  18. package/dist/ChartLegend.js +62 -0
  19. package/dist/ChartSwatch.d.ts +36 -0
  20. package/dist/ChartSwatch.d.ts.map +1 -0
  21. package/dist/ChartSwatch.js +85 -0
  22. package/dist/ChartTooltip.d.ts +46 -0
  23. package/dist/ChartTooltip.d.ts.map +1 -0
  24. package/dist/ChartTooltip.js +330 -0
  25. package/dist/charts.css +33 -0
  26. package/dist/dataTable.d.ts +56 -0
  27. package/dist/dataTable.d.ts.map +1 -0
  28. package/dist/dataTable.js +88 -0
  29. package/dist/formatters.d.ts +37 -0
  30. package/dist/formatters.d.ts.map +1 -0
  31. package/dist/formatters.js +156 -0
  32. package/dist/getChartColors.d.ts +67 -0
  33. package/dist/getChartColors.d.ts.map +1 -0
  34. package/dist/getChartColors.js +191 -0
  35. package/dist/index.d.ts +17 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +19 -0
  38. package/dist/layout.d.ts +40 -0
  39. package/dist/layout.d.ts.map +1 -0
  40. package/dist/layout.js +322 -0
  41. package/dist/legend.d.ts +17 -0
  42. package/dist/legend.d.ts.map +1 -0
  43. package/dist/legend.js +40 -0
  44. package/dist/markColor.d.ts +20 -0
  45. package/dist/markColor.d.ts.map +1 -0
  46. package/dist/markColor.js +56 -0
  47. package/dist/marks/area.d.ts +19 -0
  48. package/dist/marks/area.d.ts.map +1 -0
  49. package/dist/marks/area.js +121 -0
  50. package/dist/marks/band.d.ts +9 -0
  51. package/dist/marks/band.d.ts.map +1 -0
  52. package/dist/marks/band.js +64 -0
  53. package/dist/marks/bar.d.ts +21 -0
  54. package/dist/marks/bar.d.ts.map +1 -0
  55. package/dist/marks/bar.js +161 -0
  56. package/dist/marks/candlestick.d.ts +16 -0
  57. package/dist/marks/candlestick.d.ts.map +1 -0
  58. package/dist/marks/candlestick.js +110 -0
  59. package/dist/marks/dot.d.ts +19 -0
  60. package/dist/marks/dot.d.ts.map +1 -0
  61. package/dist/marks/dot.js +98 -0
  62. package/dist/marks/dotGL.d.ts +16 -0
  63. package/dist/marks/dotGL.d.ts.map +1 -0
  64. package/dist/marks/dotGL.js +231 -0
  65. package/dist/marks/dotGLInteractive.d.ts +35 -0
  66. package/dist/marks/dotGLInteractive.d.ts.map +1 -0
  67. package/dist/marks/dotGLInteractive.js +584 -0
  68. package/dist/marks/errorBar.d.ts +29 -0
  69. package/dist/marks/errorBar.d.ts.map +1 -0
  70. package/dist/marks/errorBar.js +95 -0
  71. package/dist/marks/heatmapGL.d.ts +27 -0
  72. package/dist/marks/heatmapGL.d.ts.map +1 -0
  73. package/dist/marks/heatmapGL.js +335 -0
  74. package/dist/marks/index.d.ts +13 -0
  75. package/dist/marks/index.d.ts.map +1 -0
  76. package/dist/marks/index.js +14 -0
  77. package/dist/marks/line.d.ts +18 -0
  78. package/dist/marks/line.d.ts.map +1 -0
  79. package/dist/marks/line.js +83 -0
  80. package/dist/marks/referenceLine.d.ts +37 -0
  81. package/dist/marks/referenceLine.d.ts.map +1 -0
  82. package/dist/marks/referenceLine.js +204 -0
  83. package/dist/marks/streamGL.d.ts +41 -0
  84. package/dist/marks/streamGL.d.ts.map +1 -0
  85. package/dist/marks/streamGL.js +317 -0
  86. package/dist/tooltip.d.ts +38 -0
  87. package/dist/tooltip.d.ts.map +1 -0
  88. package/dist/tooltip.js +57 -0
  89. package/dist/types.d.ts +193 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +70 -0
  92. package/dist/useChartColors.d.ts +16 -0
  93. package/dist/useChartColors.d.ts.map +1 -0
  94. package/dist/useChartColors.js +37 -0
  95. package/dist/utils.d.ts +15 -0
  96. package/dist/utils.d.ts.map +1 -0
  97. package/dist/utils.js +31 -0
  98. package/dist/webgl.d.ts +77 -0
  99. package/dist/webgl.d.ts.map +1 -0
  100. package/dist/webgl.js +235 -0
  101. package/package.json +71 -3
  102. package/src/Chart.doc.mjs +174 -0
  103. package/src/Chart.test.tsx +273 -0
  104. package/src/Chart.tsx +535 -0
  105. package/src/ChartAxis.tsx +289 -0
  106. package/src/ChartContext.ts +18 -0
  107. package/src/ChartGrid.tsx +136 -0
  108. package/src/ChartLegend.tsx +77 -0
  109. package/src/ChartSwatch.doc.mjs +17 -0
  110. package/src/ChartSwatch.tsx +89 -0
  111. package/src/ChartTooltip.tsx +452 -0
  112. package/src/charts.css.d.ts +3 -0
  113. package/src/dataTable.test.ts +86 -0
  114. package/src/dataTable.ts +124 -0
  115. package/src/formatters.ts +167 -0
  116. package/src/getChartColors.test.ts +114 -0
  117. package/src/getChartColors.ts +282 -0
  118. package/src/index.ts +88 -0
  119. package/src/layout.ts +372 -0
  120. package/src/legend.ts +44 -0
  121. package/src/markColor.ts +70 -0
  122. package/src/marks/area.tsx +142 -0
  123. package/src/marks/band.tsx +86 -0
  124. package/src/marks/bar.tsx +210 -0
  125. package/src/marks/candlestick.tsx +128 -0
  126. package/src/marks/dot.tsx +119 -0
  127. package/src/marks/dotGL.tsx +274 -0
  128. package/src/marks/dotGLInteractive.tsx +660 -0
  129. package/src/marks/errorBar.tsx +119 -0
  130. package/src/marks/heatmapGL.tsx +392 -0
  131. package/src/marks/index.ts +17 -0
  132. package/src/marks/line.tsx +118 -0
  133. package/src/marks/referenceLine.tsx +252 -0
  134. package/src/marks/streamGL.tsx +381 -0
  135. package/src/tooltip.ts +73 -0
  136. package/src/types.ts +212 -0
  137. package/src/useChartColors.ts +41 -0
  138. package/src/utils.ts +38 -0
  139. package/src/webgl.ts +262 -0
@@ -0,0 +1,156 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file formatters.ts
5
+ * @output Built-in, locale-aware tick/value format utilities for common data types
6
+ * @position Utility; consumed by ChartAxis via tickFormat prop
7
+ *
8
+ * Formatters degrade gracefully: non-finite numbers (NaN/±Infinity) and
9
+ * unparseable values are passed through as-is rather than producing garbage
10
+ * like "InfinityB", and no input throws. Numeric/date formatting is delegated
11
+ * to cached `Intl` formatters so output is locale-aware and rounding is correct
12
+ * across the full magnitude range (K/M/B/T and beyond).
13
+ */
14
+
15
+ /** Lazily create a value once and cache it — keeps `Intl` construction off the import path. */
16
+ function once(create) {
17
+ let cached = null;
18
+ return () => (cached ??= {
19
+ value: create()
20
+ }).value;
21
+ }
22
+ const getCompactFormat = once(() => new Intl.NumberFormat(undefined, {
23
+ notation: 'compact',
24
+ maximumFractionDigits: 1
25
+ }));
26
+ const getPercentFormat = once(() => new Intl.NumberFormat(undefined, {
27
+ style: 'percent',
28
+ maximumFractionDigits: 1
29
+ }));
30
+ const getShortDateFormat = once(() => new Intl.DateTimeFormat(undefined, {
31
+ month: 'short',
32
+ day: 'numeric'
33
+ }));
34
+ const getMonthYearFormat = once(() => new Intl.DateTimeFormat(undefined, {
35
+ month: 'short',
36
+ year: 'numeric'
37
+ }));
38
+
39
+ /**
40
+ * Compact number formatter (e.g. 1200 → "1.2K", 1500000 → "1.5M", 1e12 → "1T").
41
+ *
42
+ * Non-numeric values (e.g. category labels) and non-finite numbers pass through
43
+ * unchanged, so it is safe to use as a general-purpose tick formatter.
44
+ */
45
+ export function compactNumber(value) {
46
+ const n = Number(value);
47
+ if (!Number.isFinite(n)) {
48
+ return String(value);
49
+ }
50
+ return getCompactFormat().format(n);
51
+ }
52
+
53
+ /**
54
+ * Currency formatter factory. Returns a tick format function.
55
+ *
56
+ * The symbol prefixes the magnitude and the sign leads the symbol, so negatives
57
+ * read as "-$1.5K" rather than "$-1.5K". Large values use compact notation.
58
+ *
59
+ * @example
60
+ * ```
61
+ * <ChartAxis tickFormat={currency()} /> // $1.5K
62
+ * <ChartAxis tickFormat={currency('€')} /> // €1.5K
63
+ * <ChartAxis tickFormat={currency('¥')} /> // ¥1.5K
64
+ * ```
65
+ */
66
+ export function currency(symbol = '$') {
67
+ return value => {
68
+ const n = Number(value);
69
+ if (!Number.isFinite(n)) {
70
+ return String(value);
71
+ }
72
+ const sign = n < 0 ? '-' : '';
73
+ const abs = Math.abs(n);
74
+ const body = abs >= 1000 ? getCompactFormat().format(abs) : abs.toLocaleString();
75
+ return `${sign}${symbol}${body}`;
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Percent formatter (e.g. 0.45 → "45%", 1.2 → "120%", 0.005 → "0.5%").
81
+ *
82
+ * The input is a ratio; it is multiplied by 100 and localized. Whole percents
83
+ * render without a decimal, and up to one fractional digit is shown otherwise.
84
+ */
85
+ export function percent(value) {
86
+ const n = Number(value);
87
+ if (!Number.isFinite(n)) {
88
+ return String(value);
89
+ }
90
+ return getPercentFormat().format(n);
91
+ }
92
+
93
+ /**
94
+ * Coerce a value into a Date.
95
+ *
96
+ * Accepts a `Date`, epoch milliseconds (number or numeric string), or a date
97
+ * string (ISO 8601, RFC 2822, …). Returns an invalid Date for anything else so
98
+ * callers can pass the original value through unchanged.
99
+ *
100
+ * Date-only ISO strings (`YYYY-MM-DD`) are constructed at local midnight rather
101
+ * than the spec's UTC midnight, so the calendar day survives local formatting
102
+ * in negative-offset timezones (`"2024-01-05"` stays "Jan 5", not "Jan 4").
103
+ */
104
+ function toDate(value) {
105
+ if (value instanceof Date) {
106
+ return value;
107
+ }
108
+ if (typeof value === 'number') {
109
+ return new Date(value);
110
+ }
111
+ if (typeof value === 'string') {
112
+ const s = value.trim();
113
+ if (s === '') {
114
+ return new Date(NaN);
115
+ }
116
+ const dateOnly = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
117
+ if (dateOnly) {
118
+ const year = Number(dateOnly[1]);
119
+ const month = Number(dateOnly[2]);
120
+ const day = Number(dateOnly[3]);
121
+ const local = new Date(year, month - 1, day);
122
+ // Reject out-of-range parts (e.g. "2024-02-31") that the Date constructor
123
+ // would otherwise silently roll into a different day; treat them as
124
+ // invalid so the raw value passes through unchanged.
125
+ if (local.getFullYear() !== year || local.getMonth() !== month - 1 || local.getDate() !== day) {
126
+ return new Date(NaN);
127
+ }
128
+ return local;
129
+ }
130
+ const asNumber = Number(s);
131
+ return new Date(Number.isFinite(asNumber) ? asNumber : s);
132
+ }
133
+ return new Date(NaN);
134
+ }
135
+
136
+ /**
137
+ * Date formatter — short date (e.g. "Jan 5", "Mar 12").
138
+ */
139
+ export function shortDate(value) {
140
+ const d = toDate(value);
141
+ if (Number.isNaN(d.getTime())) {
142
+ return String(value);
143
+ }
144
+ return getShortDateFormat().format(d);
145
+ }
146
+
147
+ /**
148
+ * Date formatter — month/year (e.g. "Jan 2024", "Mar 2025").
149
+ */
150
+ export function monthYear(value) {
151
+ const d = toDate(value);
152
+ if (Number.isNaN(d.getTime())) {
153
+ return String(value);
154
+ }
155
+ return getMonthYearFormat().format(d);
156
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @file getChartColors.ts
3
+ * @output Pure function to resolve chart colors from a theme — no React required
4
+ * @position Foundation utility; consumed by useChartColors and non-React contexts
5
+ *
6
+ * Takes a token resolver function (or a defined theme + mode) and returns
7
+ * the full chart colors API. The useChartColors hook wraps this.
8
+ *
9
+ * Palettes degrade gracefully for any count: the categorical scale wraps
10
+ * around its slots, and the sequential/diverging scales pick hand-tuned token
11
+ * stops when enough exist and interpolate across the ramp when more are asked
12
+ * for. The theme entry point resolves through the canonical token resolver, so
13
+ * data tokens fall back to their defaults even when a theme doesn't override
14
+ * them.
15
+ */
16
+ import { type DefinedTheme } from '@pharos-ds/core/theme';
17
+ /** Hue names available in the sequential ramps */
18
+ export type SequentialHue = 'blue' | 'shamrock' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow' | 'gray';
19
+ /** The chart colors API returned by both getChartColors and useChartColors */
20
+ export interface ChartColorsAPI {
21
+ categorical(n: number): string[];
22
+ sequential: Record<SequentialHue, (n: number) => string[]>;
23
+ diverging: {
24
+ positiveNegative(n: number): string[];
25
+ coldHot(n: number): string[];
26
+ custom(neg: SequentialHue, pos: SequentialHue, n: number, midpoint?: string): string[];
27
+ };
28
+ semantic: {
29
+ positive: string;
30
+ negative: string;
31
+ warning: string;
32
+ neutral: string;
33
+ };
34
+ /** Structural colors for chart chrome — axes, grid, ticks, labels */
35
+ structural: {
36
+ axis: string;
37
+ grid: string;
38
+ tick: string;
39
+ label: string;
40
+ };
41
+ alpha(hex: string, opacity: number): string;
42
+ }
43
+ /** A function that resolves a token name to its current value */
44
+ export type TokenResolver = (name: string) => string;
45
+ /**
46
+ * Build chart colors from a token resolver function.
47
+ * This is the lowest-level API — pass any function that maps token names to values.
48
+ */
49
+ export declare function getChartColorsFromResolver(resolve: TokenResolver): ChartColorsAPI;
50
+ /**
51
+ * Build chart colors from a defined theme and color mode.
52
+ *
53
+ * Use this in non-React contexts — WebGL setup, SSR, tests, Node scripts.
54
+ *
55
+ * Resolves through the canonical theme token resolver, so data tokens fall back
56
+ * to their defaults when the theme doesn't override them, and both
57
+ * `light-dark()` strings and `[light, dark]` tuples are handled for `mode`.
58
+ *
59
+ * @example
60
+ * ```
61
+ * import { neutralTheme } from '@pharos-ds/theme-neutral';
62
+ * const colors = getChartColors(neutralTheme, 'light');
63
+ * colors.categorical(5)
64
+ * ```
65
+ */
66
+ export declare function getChartColors(theme: DefinedTheme, mode?: 'light' | 'dark'): ChartColorsAPI;
67
+ //# sourceMappingURL=getChartColors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getChartColors.d.ts","sourceRoot":"","sources":["../src/getChartColors.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAqB,KAAK,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAY5E,kDAAkD;AAClD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,UAAU,GACV,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,KAAK,GACL,MAAM,GACN,QAAQ,GACR,MAAM,CAAC;AAEX,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;IAC3D,SAAS,EAAE;QACT,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QACtC,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC7B,MAAM,CACJ,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,aAAa,EAClB,CAAC,EAAE,MAAM,EACT,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,EAAE,CAAC;KACb,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,qEAAqE;IACrE,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC7C;AAED,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAoGrD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,aAAa,GACrB,cAAc,CA8EhB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE,OAAO,GAAG,MAAgB,GAC/B,cAAc,CAGhB"}
@@ -0,0 +1,191 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file getChartColors.ts
5
+ * @output Pure function to resolve chart colors from a theme — no React required
6
+ * @position Foundation utility; consumed by useChartColors and non-React contexts
7
+ *
8
+ * Takes a token resolver function (or a defined theme + mode) and returns
9
+ * the full chart colors API. The useChartColors hook wraps this.
10
+ *
11
+ * Palettes degrade gracefully for any count: the categorical scale wraps
12
+ * around its slots, and the sequential/diverging scales pick hand-tuned token
13
+ * stops when enough exist and interpolate across the ramp when more are asked
14
+ * for. The theme entry point resolves through the canonical token resolver, so
15
+ * data tokens fall back to their defaults even when a theme doesn't override
16
+ * them.
17
+ */
18
+
19
+ import { resolveThemeTokens } from '@pharos-ds/core/theme';
20
+ import { parseHex, parseColor, formatHex, formatColor } from '@pharos-ds/core/utils';
21
+
22
+ // =============================================================================
23
+ // Types
24
+ // =============================================================================
25
+
26
+ /** Hue names available in the sequential ramps */
27
+
28
+ /** The chart colors API returned by both getChartColors and useChartColors */
29
+
30
+ /** A function that resolves a token name to its current value */
31
+
32
+ // =============================================================================
33
+ // Internals
34
+ // =============================================================================
35
+
36
+ const CATEGORICAL_TOKENS = ['--color-data-categorical-blue', '--color-data-categorical-purple', '--color-data-categorical-orange', '--color-data-categorical-yellow', '--color-data-categorical-gray', '--color-data-categorical-green', '--color-data-categorical-pink', '--color-data-categorical-cyan', '--color-data-categorical-red', '--color-data-categorical-teal', '--color-data-categorical-brown', '--color-data-categorical-indigo'];
37
+ const SEQUENTIAL_HUES = ['blue', 'shamrock', 'orange', 'pink', 'purple', 'red', 'teal', 'yellow', 'gray'];
38
+
39
+ /** Interpolate between two hex colors in sRGB. Non-hex input falls back to the nearer endpoint. */
40
+ function lerpHex(a, b, t) {
41
+ const ca = parseHex(a);
42
+ const cb = parseHex(b);
43
+ if (ca === null || cb === null) {
44
+ return t < 0.5 ? a : b;
45
+ }
46
+ const mix = (x, y) => x + (y - x) * t;
47
+ return formatHex(mix(ca.r, cb.r), mix(ca.g, cb.g), mix(ca.b, cb.b));
48
+ }
49
+
50
+ /**
51
+ * Sample `n` colors from an ordered ramp of stops.
52
+ * - `n <= stops.length` → picks the nearest exact stops, preserving the
53
+ * hand-tuned design-token values.
54
+ * - `n > stops.length` → interpolates across the ramp so any count is supported
55
+ * instead of silently capping at the number of stops.
56
+ * - `n === 1` → the middle stop, a single representative tone.
57
+ */
58
+ function sampleRamp(stops, n) {
59
+ const len = stops.length;
60
+ // A non-finite count (e.g. Infinity) would make the Array.from calls below
61
+ // attempt a ~2**53 element allocation and hang, so treat it as empty.
62
+ if (!Number.isFinite(n) || n <= 0 || len === 0) {
63
+ return [];
64
+ }
65
+ if (n === 1) {
66
+ return [stops[Math.floor((len - 1) / 2)]];
67
+ }
68
+ if (len === 1) {
69
+ return Array.from({
70
+ length: n
71
+ }, () => stops[0]);
72
+ }
73
+ if (n <= len) {
74
+ return Array.from({
75
+ length: n
76
+ }, (_, i) => stops[Math.round(i * (len - 1) / (n - 1))]);
77
+ }
78
+ return Array.from({
79
+ length: n
80
+ }, (_, i) => {
81
+ const t = i * (len - 1) / (n - 1);
82
+ const lo = Math.floor(t);
83
+ const frac = t - lo;
84
+ return frac === 0 ? stops[lo] : lerpHex(stops[lo], stops[lo + 1], frac);
85
+ });
86
+ }
87
+
88
+ /**
89
+ * Apply an opacity to a concrete CSS color (hex — with or without the leading
90
+ * `#` — `rgb()`/`rgba()`, named). The `opacity` argument always wins over any
91
+ * alpha already in the color. Unparseable input (e.g. `var()`) is returned
92
+ * unchanged.
93
+ */
94
+ function hexAlpha(hex, opacity) {
95
+ // parseColor requires the `#` for hex; fall back to parseHex so bare hex
96
+ // strings (`0064E0`) keep working as they did before #3739.
97
+ const rgba = parseColor(hex) ?? parseHex(hex);
98
+ if (rgba === null) {
99
+ return hex;
100
+ }
101
+ const a = Number.isFinite(opacity) ? Math.max(0, Math.min(1, opacity)) : 1;
102
+ return formatColor({
103
+ ...rgba,
104
+ a
105
+ });
106
+ }
107
+
108
+ // =============================================================================
109
+ // Public API
110
+ // =============================================================================
111
+
112
+ /**
113
+ * Build chart colors from a token resolver function.
114
+ * This is the lowest-level API — pass any function that maps token names to values.
115
+ */
116
+ export function getChartColorsFromResolver(resolve) {
117
+ const categorical = CATEGORICAL_TOKENS.map(t => resolve(t));
118
+ const ramp = hue => [5, 4, 3, 2, 1].map(step => resolve(`--color-data-${hue}-${step}`));
119
+ const gray1 = resolve('--color-data-gray-1');
120
+ function buildDiverging(negHue, posHue, n, midpoint = gray1) {
121
+ if (n <= 0) {
122
+ return [];
123
+ }
124
+ if (n === 1) {
125
+ return [midpoint];
126
+ }
127
+ const half = Math.floor(n / 2);
128
+ const hasCenter = n % 2 === 1;
129
+ const negSide = sampleRamp(ramp(negHue), half);
130
+ const posSide = sampleRamp(ramp(posHue), half).reverse();
131
+ if (hasCenter) {
132
+ return [...negSide, midpoint, ...posSide];
133
+ }
134
+ return [...negSide, ...posSide];
135
+ }
136
+ return {
137
+ categorical(n) {
138
+ // A non-finite count (e.g. Infinity) would make the wrap-around Array.from
139
+ // below attempt a ~2**53 element allocation and hang, so treat it as empty.
140
+ if (!Number.isFinite(n) || n <= 0 || categorical.length === 0) {
141
+ return [];
142
+ }
143
+ // Wrap around the palette so any series count gets a deterministic color.
144
+ return Array.from({
145
+ length: n
146
+ }, (_, i) => categorical[i % categorical.length]);
147
+ },
148
+ sequential: Object.fromEntries(SEQUENTIAL_HUES.map(hue => [hue, n => sampleRamp(ramp(hue), n)])),
149
+ diverging: {
150
+ positiveNegative: n => buildDiverging('shamrock', 'red', n),
151
+ coldHot: n => buildDiverging('blue', 'red', n),
152
+ custom: (neg, pos, n, mid) => buildDiverging(neg, pos, n, mid)
153
+ },
154
+ semantic: {
155
+ positive: resolve('--color-data-categorical-green'),
156
+ negative: resolve('--color-data-categorical-red'),
157
+ warning: resolve('--color-data-categorical-orange'),
158
+ neutral: resolve('--color-data-neutral')
159
+ },
160
+ structural: {
161
+ axis: resolve('--color-border-emphasized'),
162
+ grid: resolve('--color-border'),
163
+ tick: resolve('--color-border-emphasized'),
164
+ label: resolve('--color-text-secondary')
165
+ },
166
+ alpha: hexAlpha
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Build chart colors from a defined theme and color mode.
172
+ *
173
+ * Use this in non-React contexts — WebGL setup, SSR, tests, Node scripts.
174
+ *
175
+ * Resolves through the canonical theme token resolver, so data tokens fall back
176
+ * to their defaults when the theme doesn't override them, and both
177
+ * `light-dark()` strings and `[light, dark]` tuples are handled for `mode`.
178
+ *
179
+ * @example
180
+ * ```
181
+ * import { neutralTheme } from '@pharos-ds/theme-neutral';
182
+ * const colors = getChartColors(neutralTheme, 'light');
183
+ * colors.categorical(5)
184
+ * ```
185
+ */
186
+ export function getChartColors(theme, mode = 'light') {
187
+ const tokens = resolveThemeTokens(theme, {
188
+ mode
189
+ });
190
+ return getChartColorsFromResolver(name => tokens[name] ?? '');
191
+ }
@@ -0,0 +1,17 @@
1
+ export { Chart, type ChartProps } from './Chart';
2
+ export { ChartAxis, type ChartAxisProps } from './ChartAxis';
3
+ export { ChartGrid, type ChartGridProps } from './ChartGrid';
4
+ export { ChartLegend, type ChartLegendProps, type LegendPosition, type LegendAlignment, } from './ChartLegend';
5
+ export { type LegendItem } from './legend';
6
+ export { ChartSwatch, swatchVariantForType, type ChartSwatchProps, type ChartSwatchVariant, } from './ChartSwatch';
7
+ export { ChartTooltip, type ChartTooltipProps, type ChartTooltipPlacement, } from './ChartTooltip';
8
+ export { type TooltipSeriesValue } from './tooltip';
9
+ export { bar, line, dot, area, band, candlestick, errorBar, referenceLine, dotGL, dotGLInteractive, heatmapGL, streamGL, } from './marks';
10
+ export type { BarOptions, LineOptions, DotOptions, AreaOptions, BandOptions, CandlestickOptions, ErrorBarOptions, ReferenceLineOptions, DotGLOptions, DotGLInteractiveOptions, HeatmapGLOptions, StreamGLOptions, StreamGLHandle, } from './marks';
11
+ export { useChart } from './ChartContext';
12
+ export type { SeriesDef, ChartContext, ChartPointerEvent, ResolvedPoint, ResolvedPositions, SeriesContext, ChartMargin, ChartScale, YBaseline, ColorAccessor, } from './types';
13
+ export { useChartColors } from './useChartColors';
14
+ export { getChartColors, getChartColorsFromResolver, type ChartColorsAPI, type SequentialHue, type TokenResolver, } from './getChartColors';
15
+ export { compactNumber, currency, percent, shortDate, monthYear, } from './formatters';
16
+ export { isBandScale, xPixel } from './utils';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,KAAK,EAAE,KAAK,UAAU,EAAC,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAC,SAAS,EAAE,KAAK,cAAc,EAAC,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAC,SAAS,EAAE,KAAK,cAAc,EAAC,MAAM,aAAa,CAAC;AAC3D,OAAO,EACL,WAAW,EACX,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,KAAK,kBAAkB,EAAC,MAAM,WAAW,CAAC;AAClD,OAAO,EACL,GAAG,EACH,IAAI,EACJ,GAAG,EACH,IAAI,EACJ,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,aAAa,EACb,KAAK,EACL,gBAAgB,EAChB,SAAS,EACT,QAAQ,GACT,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,UAAU,EACV,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,YAAY,EACZ,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACxC,YAAY,EACV,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,aAAa,GACd,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,aAAa,EACb,QAAQ,EACR,OAAO,EACP,SAAS,EACT,SAAS,GACV,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAC,WAAW,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ export { Chart } from "./Chart.js";
4
+ export { ChartAxis } from "./ChartAxis.js";
5
+ export { ChartGrid } from "./ChartGrid.js";
6
+ export { ChartLegend } from "./ChartLegend.js";
7
+ export { ChartSwatch, swatchVariantForType } from "./ChartSwatch.js";
8
+ export { ChartTooltip } from "./ChartTooltip.js";
9
+ export { bar, line, dot, area, band, candlestick, errorBar, referenceLine, dotGL, dotGLInteractive, heatmapGL, streamGL } from "./marks/index.js";
10
+ export { useChart } from "./ChartContext.js";
11
+ // Color palette — theme-aware data-visualization colors
12
+ export { useChartColors } from "./useChartColors.js";
13
+ export { getChartColors, getChartColorsFromResolver } from "./getChartColors.js";
14
+
15
+ // Tick / value formatters
16
+ export { compactNumber, currency, percent, shortDate, monthYear } from "./formatters.js";
17
+
18
+ // Scale utilities
19
+ export { isBandScale, xPixel } from "./utils.js";
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file layout.ts
3
+ * @output Computes scales, stacking, grouping, then delegates to each series.resolve()
4
+ * @position Called by Chart root — the single layout pass
5
+ *
6
+ * The layout engine does NOT know about specific mark types.
7
+ * It handles cross-series coordination (scales, stacking, grouping)
8
+ * then calls each series' own resolve() method.
9
+ */
10
+ import { scaleLinear, scaleBand } from 'd3-scale';
11
+ import type { SeriesDef, ChartScale, ResolvedPoint, YBaseline } from './types';
12
+ export interface LayoutInput {
13
+ data: Record<string, unknown>[];
14
+ xKey: string;
15
+ series: SeriesDef[];
16
+ width: number;
17
+ height: number;
18
+ /** How the y-domain is derived when `yDomain` is not provided. Default 'auto'. */
19
+ yBaseline?: YBaseline;
20
+ /** Explicit y-domain [min, max]. Authoritative — no baseline/headroom/nice(). */
21
+ yDomain?: [number, number];
22
+ /**
23
+ * Explicit x-domain [min, max] for numeric/linear x. Authoritative and honored
24
+ * even when `data` is empty (stable streaming window). Ignored for band scales.
25
+ */
26
+ xDomain?: [number, number];
27
+ }
28
+ export interface LayoutResult {
29
+ xScale: ChartScale;
30
+ yScale: ReturnType<typeof scaleLinear<number, number>>;
31
+ /**
32
+ * Categorical y band scale, built when a series declares `layout.yBandKey`
33
+ * (e.g. a heatmap's rows). When present the y-axis is categorical and the
34
+ * linear `yScale` is unused.
35
+ */
36
+ yBandScale?: ReturnType<typeof scaleBand<string>>;
37
+ resolved: Map<string, ResolvedPoint[]>;
38
+ }
39
+ export declare function computeLayout({ data, xKey, series, width, height, yBaseline, yDomain, xDomain, }: LayoutInput): LayoutResult;
40
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAC,WAAW,EAAE,SAAS,EAAC,MAAM,UAAU,CAAC;AAEhD,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,aAAa,EAEb,SAAS,EACV,MAAM,SAAS,CAAC;AASjB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,iFAAiF;IACjF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD;;;;OAIG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;CACxC;AAqCD,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,OAAO,EACP,OAAO,GACR,EAAE,WAAW,GAAG,YAAY,CA6Q5B"}