@octane-xplat/charts 0.0.0-stage → 0.10.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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/dist/macos/Chart.macos.tsrx.js +351 -0
  3. package/dist/macos/core/axes.js +146 -0
  4. package/dist/macos/core/hit.js +131 -0
  5. package/dist/macos/core/marks.js +262 -0
  6. package/dist/macos/core/scales.js +99 -0
  7. package/dist/macos/core/scene.js +120 -0
  8. package/dist/macos/core/svg.js +40 -0
  9. package/dist/macos/index.js +2 -0
  10. package/dist/macos/octane-client-build.json +8 -0
  11. package/dist/macos/svg-image.macos.js +14 -0
  12. package/dist/native/Chart.tsrx.js +340 -0
  13. package/dist/native/core/axes.js +146 -0
  14. package/dist/native/core/hit.js +131 -0
  15. package/dist/native/core/marks.js +262 -0
  16. package/dist/native/core/scales.js +99 -0
  17. package/dist/native/core/scene.js +120 -0
  18. package/dist/native/core/svg.js +40 -0
  19. package/dist/native/index.js +2 -0
  20. package/dist/native/octane-client-build.json +8 -0
  21. package/dist/web/Chart.web.tsrx.js +488 -0
  22. package/dist/web/core/axes.js +146 -0
  23. package/dist/web/core/hit.js +131 -0
  24. package/dist/web/core/marks.js +262 -0
  25. package/dist/web/core/scales.js +99 -0
  26. package/dist/web/core/scene.js +120 -0
  27. package/dist/web/core/svg.js +40 -0
  28. package/dist/web/index.js +2 -0
  29. package/dist/web/octane-client-build.json +8 -0
  30. package/package.json +91 -3
  31. package/src/Chart.macos.tsrx +134 -0
  32. package/src/Chart.tsrx +174 -0
  33. package/src/Chart.web.tsrx +215 -0
  34. package/src/core/axes.ts +211 -0
  35. package/src/core/hit.ts +201 -0
  36. package/src/core/marks.ts +380 -0
  37. package/src/core/scales.ts +168 -0
  38. package/src/core/scene.ts +145 -0
  39. package/src/core/svg.ts +84 -0
  40. package/src/index.macos.ts +12 -0
  41. package/src/index.ts +12 -0
  42. package/src/index.web.ts +12 -0
  43. package/src/props.ts +90 -0
  44. package/src/svg-image.macos.ts +34 -0
  45. package/types/index.d.ts +17 -0
  46. package/types/props.d.ts +83 -0
  47. package/README.md +0 -3
@@ -0,0 +1,84 @@
1
+ import type { Mark } from './marks'
2
+ import type { PlotBox } from './scales'
3
+
4
+ /** Mark[] → one `<svg>` markup string. Emits only the androidsvg ∩ SVGKit
5
+ * subset: `<svg>`/`<g>` structure, path/rect/circle/line shapes, solid fills
6
+ * and strokes, `translate` transforms, opacity attributes. Never `<text>`,
7
+ * filters, masks, patterns, or gradients — labels are real elements in the
8
+ * leaf overlay (docs/notes/primitive-notes.md). */
9
+
10
+ function num(v: number): string {
11
+ if (!Number.isFinite(v)) {
12
+ return '0'
13
+ }
14
+
15
+ return Number.isInteger(v) ? String(v) : String(+v.toFixed(2))
16
+ }
17
+
18
+ function esc(v: string): string {
19
+ return v
20
+ .replaceAll('&', '&amp;')
21
+ .replaceAll('"', '&quot;')
22
+ .replaceAll('<', '&lt;')
23
+ .replaceAll('>', '&gt;')
24
+ }
25
+
26
+ function paintAttrs(m: Mark): string {
27
+ let out = ''
28
+ if (m.fill !== undefined) {
29
+ out += ` fill="${esc(m.fill)}"`
30
+ }
31
+
32
+ if (m.fillOpacity !== undefined) {
33
+ out += ` fill-opacity="${num(m.fillOpacity)}"`
34
+ }
35
+
36
+ if (m.stroke !== undefined) {
37
+ out += ` stroke="${esc(m.stroke)}"`
38
+ }
39
+
40
+ if (m.strokeOpacity !== undefined) {
41
+ out += ` stroke-opacity="${num(m.strokeOpacity)}"`
42
+ }
43
+
44
+ if (m.strokeWidth !== undefined) {
45
+ out += ` stroke-width="${num(m.strokeWidth)}"`
46
+ }
47
+
48
+ if (m.strokeLinecap !== undefined) {
49
+ out += ` stroke-linecap="${m.strokeLinecap}"`
50
+ }
51
+
52
+ if (m.transform !== undefined) {
53
+ out += ` transform="${esc(m.transform)}"`
54
+ }
55
+
56
+ return out
57
+ }
58
+
59
+ function markXml(m: Mark): string {
60
+ switch (m.kind) {
61
+ case 'path':
62
+ return `<path d="${esc(m.d)}"${paintAttrs(m)}/>`
63
+ case 'rect':
64
+ return `<rect x="${num(m.x)}" y="${num(m.y)}" width="${num(m.width)}" height="${num(m.height)}"${paintAttrs(m)}/>`
65
+ case 'circle':
66
+ return `<circle cx="${num(m.cx)}" cy="${num(m.cy)}" r="${num(m.r)}"${paintAttrs(m)}/>`
67
+ case 'line':
68
+ return `<line x1="${num(m.x1)}" y1="${num(m.y1)}" x2="${num(m.x2)}" y2="${num(m.y2)}"${paintAttrs(m)}/>`
69
+ }
70
+ }
71
+
72
+ /** Chart marks are plot-space; axis rules are chart-space. Paint order:
73
+ * gridlines under the translated marks group, frame (spine + stubs) over. */
74
+ export function svgDocument(
75
+ marks: Mark[],
76
+ grid: Mark[],
77
+ frame: Mark[],
78
+ plot: PlotBox,
79
+ width: number,
80
+ height: number,
81
+ ): string {
82
+ const body = `${grid.map(markXml).join('')}<g transform="translate(${num(plot.x)} ${num(plot.y)})">${marks.map(markXml).join('')}</g>${frame.map(markXml).join('')}`
83
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${num(width)} ${num(height)}" width="${num(width)}" height="${num(height)}">${body}</svg>`
84
+ }
@@ -0,0 +1,12 @@
1
+ // Platform barrels — explicit .tsrx leaf specifiers (moduleSuffixes don't
2
+ // reach .tsrx; same convention as @octane-xplat/ui index.*.ts).
3
+ export { Chart } from './Chart.macos.tsrx'
4
+ export type {
5
+ AxisSpec,
6
+ ChartDatum,
7
+ ChartHit,
8
+ ChartMargin,
9
+ ChartProps,
10
+ ChartType,
11
+ SeriesSpec,
12
+ } from './props'
package/src/index.ts ADDED
@@ -0,0 +1,12 @@
1
+ // Platform barrels — explicit .tsrx leaf specifiers (moduleSuffixes don't
2
+ // reach .tsrx; same convention as @octane-xplat/ui index.*.ts).
3
+ export { Chart } from './Chart.tsrx'
4
+ export type {
5
+ AxisSpec,
6
+ ChartDatum,
7
+ ChartHit,
8
+ ChartMargin,
9
+ ChartProps,
10
+ ChartType,
11
+ SeriesSpec,
12
+ } from './props'
@@ -0,0 +1,12 @@
1
+ // Platform barrels — explicit .tsrx leaf specifiers (moduleSuffixes don't
2
+ // reach .tsrx; same convention as @octane-xplat/ui index.*.ts).
3
+ export { Chart } from './Chart.web.tsrx'
4
+ export type {
5
+ AxisSpec,
6
+ ChartDatum,
7
+ ChartHit,
8
+ ChartMargin,
9
+ ChartProps,
10
+ ChartType,
11
+ SeriesSpec,
12
+ } from './props'
package/src/props.ts ADDED
@@ -0,0 +1,90 @@
1
+ /** Shared prop/type contract for @octane-xplat/charts — the single source for
2
+ * both platform leaves and the published .d.ts. No imports: the shared
3
+ * contract stays dependency-free and platform-agnostic. */
4
+
5
+ export type ChartType = 'line' | 'area' | 'bar' | 'pie' | 'scatter'
6
+
7
+ export interface ChartDatum {
8
+ /** Bar/pie: the category label. Line/area/scatter: number or Date. */
9
+ x: number | string | Date
10
+ y: number
11
+ /** Per-datum color override — wins over the series color (pie slices,
12
+ * scatter points, individual bars). */
13
+ color?: string
14
+ }
15
+
16
+ export interface SeriesSpec {
17
+ name: string
18
+ /** Series color — stroke for line/scatter, fill for area/bar. Falls back
19
+ * to the built-in palette by series index. */
20
+ color?: string
21
+ values: ChartDatum[]
22
+ }
23
+
24
+ export interface ChartMargin {
25
+ top?: number
26
+ right?: number
27
+ bottom?: number
28
+ left?: number
29
+ }
30
+
31
+ /** Axis decomposition — gridline, tick stub, and label toggle independently
32
+ * (Swift Charts `AxisMarks` shape). Labels render as real positioned
33
+ * elements in the overlay, never `<text>` in markup. */
34
+ export interface AxisSpec {
35
+ /** Tick labels in the margin. Default true. */
36
+ labels?: boolean
37
+ /** Tick stubs on the axis spine. Default true. */
38
+ ticks?: boolean
39
+ /** Gridlines across the plot area. Default false. */
40
+ grid?: boolean
41
+ /** Desired tick count hint — a hint, not a guarantee. */
42
+ tickCount?: number
43
+ /** Tick label formatter; receives the domain value. */
44
+ format?: (value: number | string | Date) => string
45
+ }
46
+
47
+ /** A resolved datum reference — `x`/`y` are the datum's values, not pixels. */
48
+ export interface ChartHit {
49
+ series: number
50
+ index: number
51
+ x: number | string | Date
52
+ y: number
53
+ }
54
+
55
+ export interface ChartProps {
56
+ type: ChartType
57
+ data: SeriesSpec[]
58
+ /** Explicit size in px (web) / dips (native). Without `height`, the leaf
59
+ * fills its parent or derives height from `aspectRatio`. */
60
+ width?: number
61
+ height?: number
62
+ /** width/height ratio used when `height` is unset. */
63
+ aspectRatio?: number
64
+ /** Space reserved inside the chart box for axis labels — labels live in
65
+ * the margin band, the plot in the remainder. Defaults reserve room for
66
+ * x labels (bottom) and y labels (left) when those axes show labels. */
67
+ margin?: ChartMargin
68
+ /** Bar only: stack series instead of grouping side by side. */
69
+ stacked?: boolean
70
+ /** Pie only: 0–<1 inner-radius fraction — any positive value renders a
71
+ * donut. */
72
+ innerRadiusRatio?: number
73
+ xAxis?: AxisSpec
74
+ yAxis?: AxisSpec
75
+ /** Legend row of series swatches. `true` = 'bottom'. Pie legends list
76
+ * slices, not series. */
77
+ legend?: boolean | 'top' | 'bottom'
78
+ /** Show a value callout at the scrub/hover cursor. */
79
+ tooltip?: boolean
80
+ /** Show a snap-to-x cursor rule while scrubbing. */
81
+ crosshair?: boolean
82
+ /** Tap/click a datum. */
83
+ onPress?: (hit: ChartHit) => void
84
+ /** Scrub position changes — `null` when the gesture ends or leaves. */
85
+ onScrub?: (hit: ChartHit | null) => void
86
+ accessibilityLabel?: string
87
+ className?: any
88
+ style?: any
89
+ id?: string
90
+ }
@@ -0,0 +1,34 @@
1
+ // Kept local to avoid coupling the charts leaf to private UI helpers.
2
+ // Foundation's public ObjC API is available through the AppKit metadata bridge.
3
+ declare const NSString: {
4
+ stringWithString(value: string): {
5
+ dataUsingEncoding(encoding: number): {
6
+ base64EncodedStringWithOptions(options: number): string
7
+ } | null
8
+ }
9
+ }
10
+
11
+ export function svgDataUri(markup: string): string {
12
+ const data = NSString.stringWithString(markup).dataUsingEncoding(4) // NSUTF8StringEncoding
13
+ if (!data) {
14
+ throw new Error('Unable to encode SVG as UTF-8')
15
+ }
16
+
17
+ return `data:image/svg+xml;base64,${data.base64EncodedStringWithOptions(0)}`
18
+ }
19
+
20
+ /** Normalize bundled markup and SVG data URIs for AppKit's image host. */
21
+ export function appKitImageSource(src: string): string {
22
+ if (src.trimStart().startsWith('<svg') || src.trimStart().startsWith('<?xml')) {
23
+ return svgDataUri(src)
24
+ }
25
+
26
+ if (
27
+ /^data:image\/svg\+xml[;,]/i.test(src) &&
28
+ !src.slice(0, src.indexOf(',')).endsWith(';base64')
29
+ ) {
30
+ return svgDataUri(decodeURIComponent(src.slice(src.indexOf(',') + 1)))
31
+ }
32
+
33
+ return src
34
+ }
@@ -0,0 +1,17 @@
1
+ // Boundary types for @octane-xplat/charts — the mechanical wrapper over
2
+ // props.ts (tsrx-tsc can't emit .tsrx declarations; see ui/types/index.d.ts
3
+ // for the same pattern).
4
+ import type { UniversalComponent } from 'octane/universal'
5
+ import type { ChartProps } from './props.js'
6
+
7
+ export declare const Chart: UniversalComponent<ChartProps>
8
+
9
+ export type {
10
+ AxisSpec,
11
+ ChartDatum,
12
+ ChartHit,
13
+ ChartMargin,
14
+ ChartProps,
15
+ ChartType,
16
+ SeriesSpec,
17
+ } from './props.js'
@@ -0,0 +1,83 @@
1
+ /** Shared prop/type contract for @octane-xplat/charts — the single source for
2
+ * both platform leaves and the published .d.ts. No imports: the shared
3
+ * contract stays dependency-free and platform-agnostic. */
4
+ export type ChartType = 'line' | 'area' | 'bar' | 'pie' | 'scatter';
5
+ export interface ChartDatum {
6
+ /** Bar/pie: the category label. Line/area/scatter: number or Date. */
7
+ x: number | string | Date;
8
+ y: number;
9
+ /** Per-datum color override — wins over the series color (pie slices,
10
+ * scatter points, individual bars). */
11
+ color?: string;
12
+ }
13
+ export interface SeriesSpec {
14
+ name: string;
15
+ /** Series color — stroke for line/scatter, fill for area/bar. Falls back
16
+ * to the built-in palette by series index. */
17
+ color?: string;
18
+ values: ChartDatum[];
19
+ }
20
+ export interface ChartMargin {
21
+ top?: number;
22
+ right?: number;
23
+ bottom?: number;
24
+ left?: number;
25
+ }
26
+ /** Axis decomposition — gridline, tick stub, and label toggle independently
27
+ * (Swift Charts `AxisMarks` shape). Labels render as real positioned
28
+ * elements in the overlay, never `<text>` in markup. */
29
+ export interface AxisSpec {
30
+ /** Tick labels in the margin. Default true. */
31
+ labels?: boolean;
32
+ /** Tick stubs on the axis spine. Default true. */
33
+ ticks?: boolean;
34
+ /** Gridlines across the plot area. Default false. */
35
+ grid?: boolean;
36
+ /** Desired tick count hint — a hint, not a guarantee. */
37
+ tickCount?: number;
38
+ /** Tick label formatter; receives the domain value. */
39
+ format?: (value: number | string | Date) => string;
40
+ }
41
+ /** A resolved datum reference — `x`/`y` are the datum's values, not pixels. */
42
+ export interface ChartHit {
43
+ series: number;
44
+ index: number;
45
+ x: number | string | Date;
46
+ y: number;
47
+ }
48
+ export interface ChartProps {
49
+ type: ChartType;
50
+ data: SeriesSpec[];
51
+ /** Explicit size in px (web) / dips (native). Without `height`, the leaf
52
+ * fills its parent or derives height from `aspectRatio`. */
53
+ width?: number;
54
+ height?: number;
55
+ /** width/height ratio used when `height` is unset. */
56
+ aspectRatio?: number;
57
+ /** Space reserved inside the chart box for axis labels — labels live in
58
+ * the margin band, the plot in the remainder. Defaults reserve room for
59
+ * x labels (bottom) and y labels (left) when those axes show labels. */
60
+ margin?: ChartMargin;
61
+ /** Bar only: stack series instead of grouping side by side. */
62
+ stacked?: boolean;
63
+ /** Pie only: 0–<1 inner-radius fraction — any positive value renders a
64
+ * donut. */
65
+ innerRadiusRatio?: number;
66
+ xAxis?: AxisSpec;
67
+ yAxis?: AxisSpec;
68
+ /** Legend row of series swatches. `true` = 'bottom'. Pie legends list
69
+ * slices, not series. */
70
+ legend?: boolean | 'top' | 'bottom';
71
+ /** Show a value callout at the scrub/hover cursor. */
72
+ tooltip?: boolean;
73
+ /** Show a snap-to-x cursor rule while scrubbing. */
74
+ crosshair?: boolean;
75
+ /** Tap/click a datum. */
76
+ onPress?: (hit: ChartHit) => void;
77
+ /** Scrub position changes — `null` when the gesture ends or leaves. */
78
+ onScrub?: (hit: ChartHit | null) => void;
79
+ accessibilityLabel?: string;
80
+ className?: any;
81
+ style?: any;
82
+ id?: string;
83
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.