@delacour/react-native-charts 0.1.0-alpha.20260925053522

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 (146) hide show
  1. package/README.md +98 -0
  2. package/package.json +61 -0
  3. package/src/animation/AGENTS.md +40 -0
  4. package/src/animation/animation.types.ts +16 -0
  5. package/src/animation/index.ts +2 -0
  6. package/src/animation/use-animated-path.ts +74 -0
  7. package/src/cartesian/AGENTS.md +110 -0
  8. package/src/cartesian/axes/chart-x-axis.tsx +52 -0
  9. package/src/cartesian/axes/chart-y-axis.tsx +56 -0
  10. package/src/cartesian/cartesian-chart.context.tsx +43 -0
  11. package/src/cartesian/cartesian-chart.tsx +132 -0
  12. package/src/cartesian/cartesian-chart.types.ts +181 -0
  13. package/src/cartesian/hooks/use-canvas-size.ts +37 -0
  14. package/src/cartesian/hooks/use-chart-model.ts +278 -0
  15. package/src/cartesian/index.ts +41 -0
  16. package/src/cartesian/marks/chart-area.tsx +83 -0
  17. package/src/cartesian/marks/chart-bar-group.tsx +132 -0
  18. package/src/cartesian/marks/chart-bar-stack.tsx +209 -0
  19. package/src/cartesian/marks/chart-bar.tsx +195 -0
  20. package/src/cartesian/marks/chart-candlestick.tsx +148 -0
  21. package/src/cartesian/marks/chart-cursor.tsx +168 -0
  22. package/src/cartesian/marks/chart-grid.tsx +46 -0
  23. package/src/cartesian/marks/chart-line.tsx +73 -0
  24. package/src/cartesian/marks/chart-scatter.tsx +71 -0
  25. package/src/core/AGENTS.md +77 -0
  26. package/src/core/animation/morph-strategy.test.ts +38 -0
  27. package/src/core/animation/morph-strategy.ts +53 -0
  28. package/src/core/animation/resample-points.test.ts +68 -0
  29. package/src/core/animation/resample-points.ts +64 -0
  30. package/src/core/chart.types.ts +62 -0
  31. package/src/core/curve/build-area.test.ts +48 -0
  32. package/src/core/curve/build-area.ts +58 -0
  33. package/src/core/curve/build-line.test.ts +64 -0
  34. package/src/core/curve/build-line.ts +53 -0
  35. package/src/core/curve/curves.test.ts +20 -0
  36. package/src/core/curve/curves.ts +48 -0
  37. package/src/core/geometry/band.test.ts +79 -0
  38. package/src/core/geometry/band.ts +111 -0
  39. package/src/core/geometry/category-domain.test.ts +33 -0
  40. package/src/core/geometry/category-domain.ts +18 -0
  41. package/src/core/geometry/chart-bounds.test.ts +36 -0
  42. package/src/core/geometry/chart-bounds.ts +47 -0
  43. package/src/core/geometry/chart-layout.test.ts +230 -0
  44. package/src/core/geometry/chart-layout.ts +162 -0
  45. package/src/core/geometry/domain.test.ts +87 -0
  46. package/src/core/geometry/domain.ts +94 -0
  47. package/src/core/geometry/grid-lines.test.ts +48 -0
  48. package/src/core/geometry/grid-lines.ts +43 -0
  49. package/src/core/geometry/stack.test.ts +151 -0
  50. package/src/core/geometry/stack.ts +109 -0
  51. package/src/core/geometry/step.test.ts +34 -0
  52. package/src/core/geometry/step.ts +21 -0
  53. package/src/core/geometry/transform-input-data.test.ts +105 -0
  54. package/src/core/geometry/transform-input-data.ts +88 -0
  55. package/src/core/geometry/x-values.test.ts +37 -0
  56. package/src/core/geometry/x-values.ts +36 -0
  57. package/src/core/index.ts +109 -0
  58. package/src/core/interaction/closest-index.test.ts +36 -0
  59. package/src/core/interaction/closest-index.ts +27 -0
  60. package/src/core/interaction/path-segments.test.ts +60 -0
  61. package/src/core/interaction/path-segments.ts +155 -0
  62. package/src/core/interaction/y-for-x.test.ts +135 -0
  63. package/src/core/interaction/y-for-x.ts +106 -0
  64. package/src/core/polar/build-slice-path.test.ts +173 -0
  65. package/src/core/polar/build-slice-path.ts +98 -0
  66. package/src/core/polar/label-position.test.ts +41 -0
  67. package/src/core/polar/label-position.ts +18 -0
  68. package/src/core/polar/pie-input.test.ts +36 -0
  69. package/src/core/polar/pie-input.ts +32 -0
  70. package/src/core/polar/polar-point.test.ts +55 -0
  71. package/src/core/polar/polar-point.ts +29 -0
  72. package/src/core/polar/polar.types.ts +47 -0
  73. package/src/core/polar/resolve-layout.test.ts +63 -0
  74. package/src/core/polar/resolve-layout.ts +55 -0
  75. package/src/core/polar/resolve-slices.test.ts +89 -0
  76. package/src/core/polar/resolve-slices.ts +58 -0
  77. package/src/core/polar/slice-index-at.test.ts +52 -0
  78. package/src/core/polar/slice-index-at.ts +42 -0
  79. package/src/core/polar/slice-opacity.test.ts +29 -0
  80. package/src/core/polar/slice-opacity.ts +12 -0
  81. package/src/core/scale/make-scale.test.ts +55 -0
  82. package/src/core/scale/make-scale.ts +78 -0
  83. package/src/core/scale/scale.test.ts +76 -0
  84. package/src/core/scale/scale.ts +65 -0
  85. package/src/core/scale/scale.types.ts +30 -0
  86. package/src/core/shape/build-bars.test.ts +203 -0
  87. package/src/core/shape/build-bars.ts +167 -0
  88. package/src/core/shape/build-candles.test.ts +156 -0
  89. package/src/core/shape/build-candles.ts +153 -0
  90. package/src/core/shape/build-scatter.test.ts +103 -0
  91. package/src/core/shape/build-scatter.ts +81 -0
  92. package/src/core/shape/rect-path.test.ts +61 -0
  93. package/src/core/shape/rect-path.ts +69 -0
  94. package/src/core/text/axis-gutters.test.ts +70 -0
  95. package/src/core/text/axis-gutters.ts +70 -0
  96. package/src/core/text/bar-label.test.ts +92 -0
  97. package/src/core/text/bar-label.ts +61 -0
  98. package/src/core/text/format-tick.test.ts +87 -0
  99. package/src/core/text/format-tick.ts +76 -0
  100. package/src/core/text/label-anchor.test.ts +59 -0
  101. package/src/core/text/label-anchor.ts +62 -0
  102. package/src/core/ticks/build-ticks.test.ts +38 -0
  103. package/src/core/ticks/build-ticks.ts +36 -0
  104. package/src/core/ticks/linear-ticks.test.ts +56 -0
  105. package/src/core/ticks/linear-ticks.ts +67 -0
  106. package/src/core/ticks/tick-count.test.ts +46 -0
  107. package/src/core/ticks/tick-count.ts +35 -0
  108. package/src/core/ticks/tick.types.ts +7 -0
  109. package/src/core/ticks/time-ticks.test.ts +61 -0
  110. package/src/core/ticks/time-ticks.ts +22 -0
  111. package/src/core/util/as-number.test.ts +45 -0
  112. package/src/core/util/as-number.ts +22 -0
  113. package/src/core/util/clamp.test.ts +21 -0
  114. package/src/core/util/clamp.ts +16 -0
  115. package/src/core/util/extent.test.ts +33 -0
  116. package/src/core/util/extent.ts +37 -0
  117. package/src/core/util/read-at.test.ts +14 -0
  118. package/src/core/util/read-at.ts +14 -0
  119. package/src/core/util/sided-number.test.ts +28 -0
  120. package/src/core/util/sided-number.ts +34 -0
  121. package/src/docs.test.ts +45 -0
  122. package/src/flat-worklet.test.ts +130 -0
  123. package/src/gesture/AGENTS.md +84 -0
  124. package/src/gesture/gesture-overlay.tsx +21 -0
  125. package/src/gesture/gesture.types.ts +143 -0
  126. package/src/gesture/index.ts +12 -0
  127. package/src/gesture/use-chart-scrub.ts +44 -0
  128. package/src/gesture/use-scrub-gesture.ts +162 -0
  129. package/src/index.ts +6 -0
  130. package/src/no-classname.test.ts +27 -0
  131. package/src/polar/AGENTS.md +55 -0
  132. package/src/polar/hooks/use-polar-model.ts +88 -0
  133. package/src/polar/index.ts +14 -0
  134. package/src/polar/marks/pie-inset.tsx +70 -0
  135. package/src/polar/marks/pie-label.tsx +71 -0
  136. package/src/polar/marks/pie-slice.tsx +82 -0
  137. package/src/polar/marks/pie-slices.tsx +60 -0
  138. package/src/polar/polar-chart.context.tsx +37 -0
  139. package/src/polar/polar-chart.tsx +91 -0
  140. package/src/polar/polar-chart.types.ts +82 -0
  141. package/src/purity.test.ts +75 -0
  142. package/src/skia/AGENTS.md +39 -0
  143. package/src/skia/build-path.ts +22 -0
  144. package/src/skia/font.ts +78 -0
  145. package/src/skia/index.ts +9 -0
  146. package/src/source-tree.test.ts +33 -0
@@ -0,0 +1,78 @@
1
+ import { matchFont, type SkFont } from "@shopify/react-native-skia";
2
+ import { useMemo } from "react";
3
+ import type { LabelMetrics } from "../core/text/label-anchor";
4
+
5
+ /** Re-exported so a consumer can hold a font without importing Skia itself. */
6
+ export type ChartFont = SkFont;
7
+
8
+ /**
9
+ * A font from a family the operating system already has.
10
+ *
11
+ * No asset ships with this package, and none needs to: `matchFont` resolves
12
+ * against the system font manager, so a chart is legible with no `expo-font`,
13
+ * no config plugin and no Metro asset resolver in the consuming app.
14
+ *
15
+ * The trade is that iOS's system font is not Android's, so the same labels
16
+ * measure differently and the plot rect differs by a few points across
17
+ * platforms. That is correct behaviour rather than a bug — but it does mean a
18
+ * screenshot baseline has to be per-platform, and an app that needs identical
19
+ * layout on both must load and pass its own font.
20
+ *
21
+ * An `undefined` family means the platform default. `matchFont` spreads the
22
+ * style it is given over its own defaults, so a `fontFamily: undefined` key
23
+ * would erase the default rather than fall through to it and throw "Value is
24
+ * undefined, expected a String" from inside Skia — which is why the key is
25
+ * omitted rather than passed.
26
+ */
27
+ export function useSystemFont(family: string | undefined, size: number): SkFont {
28
+ return useMemo(
29
+ () => matchFont(family === undefined ? { fontSize: size } : { fontFamily: family, fontSize: size }),
30
+ [family, size]
31
+ );
32
+ }
33
+
34
+ /**
35
+ * The advance width of `text`, in points.
36
+ *
37
+ * Glyph advances summed, rather than `measureText`. `measureText` returns the
38
+ * *drawn* bounds, which exclude side bearings — a tick reading "10" measures
39
+ * narrower than the space it actually occupies, and the axis gutter comes out
40
+ * a point or two too tight on every label. `getTextWidth` gives the advance
41
+ * directly but is deprecated in Skia 2.x.
42
+ */
43
+ export function measureLabelWidth(font: SkFont | null, text: string): number {
44
+ if (font === null || text === "") return 0;
45
+ let total = 0;
46
+ for (const advance of font.getGlyphWidths(font.getGlyphIDs(text))) total += advance;
47
+ return total;
48
+ }
49
+
50
+ /** Advance widths for a whole axis' worth of labels. */
51
+ export function measureLabelWidths(font: SkFont | null, labels: readonly string[]): number[] {
52
+ return labels.map((label) => measureLabelWidth(font, label));
53
+ }
54
+
55
+ /**
56
+ * Line height, from the font's own metrics.
57
+ *
58
+ * `ascent` is negative and `descent` positive, so the span between them is the
59
+ * full glyph box — which is what an axis gutter has to reserve, not the
60
+ * nominal point size.
61
+ */
62
+ export function fontLineHeight(font: SkFont | null): number {
63
+ const { ascent, descent } = fontMetrics(font);
64
+ return ascent + descent;
65
+ }
66
+
67
+ /**
68
+ * A font's ascent and descent, both as positive distances from the baseline.
69
+ *
70
+ * Skia reports `ascent` negative (it is a y offset in a downward-positive
71
+ * space) and `descent` positive. Normalising both to magnitudes here is what
72
+ * lets `anchorY` read as geometry rather than as sign juggling.
73
+ */
74
+ export function fontMetrics(font: SkFont | null): LabelMetrics {
75
+ if (font === null) return { ascent: 0, descent: 0 };
76
+ const metrics = font.getMetrics();
77
+ return { ascent: Math.abs(metrics.ascent), descent: Math.abs(metrics.descent) };
78
+ }
@@ -0,0 +1,9 @@
1
+ export { emptyPath, toSkPath } from "./build-path";
2
+ export {
3
+ type ChartFont,
4
+ fontLineHeight,
5
+ fontMetrics,
6
+ measureLabelWidth,
7
+ measureLabelWidths,
8
+ useSystemFont,
9
+ } from "./font";
@@ -0,0 +1,33 @@
1
+ import { readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ /** Every `.ts`/`.tsx` under `dir`, tests included unless `skipTests`. */
5
+ export function sourceFiles(dir: string, options: { skipTests?: boolean } = {}): string[] {
6
+ const found: string[] = [];
7
+ const walk = (current: string): void => {
8
+ for (const entry of readdirSync(current)) {
9
+ const path = join(current, entry);
10
+ if (statSync(path).isDirectory()) {
11
+ walk(path);
12
+ continue;
13
+ }
14
+ if (!/\.tsx?$/.test(entry)) continue;
15
+ if (options.skipTests && /\.test\.tsx?$/.test(entry)) continue;
16
+ found.push(path);
17
+ }
18
+ };
19
+ walk(dir);
20
+ return found;
21
+ }
22
+
23
+ export const SRC = import.meta.dir;
24
+ export const PACKAGE_ROOT = join(SRC, "..");
25
+
26
+ export function read(path: string): string {
27
+ return readFileSync(path, "utf8");
28
+ }
29
+
30
+ /** `path` relative to the package, for a failure message that can be acted on. */
31
+ export function relative(path: string): string {
32
+ return path.slice(PACKAGE_ROOT.length + 1);
33
+ }