hazo_dataviz 0.6.2 → 0.7.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.
package/CHANGE_LOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # hazo_dataviz — Change Log
2
2
 
3
+ ## 0.7.0 — 2026-09-21
4
+
5
+ i18n adoption — closes the workspace-wide `audit:i18n` gap for this package (it was missing from the original migration list; every other `hazo_*` package now has this bridge).
6
+
7
+ - **New `src/locales/en.json`** — a flat, literal-dotted-key catalog with 20 strings extracted from chart/visualizer components: empty states (`chart_frame.no_data`, `table.no_data`, `line_chart.no_data`, `multi_line_chart.no_data`, `time_series_chart.no_data`), the `TimeSeriesChart` multi-series fallback label (`time_series_chart.series_label`, `{{n}}` interpolated) and its "today" reference-line marker (`time_series_chart.reference_today`), `ChartControls`' grain/chart-type segmented-control labels (Daily/Weekly/Monthly/Quarterly/Yearly, Line/Bar), and every builtin visualizer's display `label` (Table, Single Stat, Area/Bar/Line/Stacked Bar Chart).
8
+ - **New `t` export** from `src/lib/index.ts` (re-exported from `./client` and the default server entry), wired via `createPackageT('hazo_dataviz', en)` from `hazo_core/i18n`. Uses a plain `import en from '../locales/en.json'` (not `createRequire`) — this catalog module is bundled into client/browser code via `index.client.ts`, and `createRequire` is Node-only; a plain JSON import works under this package's `"module": "Node16"` tsconfig with `resolveJsonModule: true` and is browser-safe. `tsc` copies `src/locales/en.json` into `dist/locales/en.json` automatically, no manual build-step copy needed.
9
+ - **Call sites updated**: `chart_frame.tsx` (`EmptyState`), `table.tsx`, `line_chart.tsx`, `multi_line_chart.tsx`, `time_series_chart.tsx`, `chart_controls.tsx`, and the `label` field of every builtin visualizer (`line.tsx`, `bar.tsx`, `stacked_bar.tsx`, `area.tsx`, `table.tsx`, `single_stat.tsx`) now call `t()` instead of embedding English literals. Several of these files already used a local variable named `t` for the resolved `ChartTheme` — the i18n import is aliased to `translate` in `chart_controls.tsx`, `line_chart.tsx`, and `time_series_chart.tsx` to avoid the collision.
10
+ - **`hazo_i18n` added as an optional peer** (`^0.5.0`, `peerDependenciesMeta.optional: true`) — mirrors the guarded, fire-and-forget registration `hazo_core/i18n` already performs; this package never imports `hazo_i18n` directly. `hazo_core` peer floor raised `^2.3.0` → `^2.4.0` (the version that ships `hazo_core/i18n`).
11
+ - **New `/autotest` scenario group** (`hazo_dataviz_i18n` in `test-app/app/autotest/hazo_dataviz_scenarios.ts`): catalog loads, all 20 known keys resolve via `t.has()`/`t.raw()`, `{{n}}` interpolation on the series-label fallback, missing-key bare-key fallback, and a check that every builtin visualizer's `.label` matches `t()`'s rendering of its own key (i.e. actually wired, not still hardcoded).
12
+ - **Fix (unrelated, pre-existing build break)**: `lib/format.ts`'s `currency` case called `formatCurrency(Number(value), format.ccy)` — a string second argument — which no longer type-checks against `hazo_core`'s `formatCurrency(amount, options: FormatCurrencyOptions)` signature (a breaking change landed in `hazo_core` outside this package). Fixed to `formatCurrency(Number(value), { currency: format.ccy })` so `npm run build` passes again; unrelated to the i18n work but was blocking verification.
13
+ - Bumped `test-app`'s `hazo_dataviz` dep range `^0.6.0` → `^0.7.0`.
14
+
3
15
  ## 0.6.2 — 2026-09-07
4
16
 
5
17
  - **Fix (`TimeSeriesChart` Y-axis label clipping)**: `CHART_MARGIN.left` was `-4` and the Y axis was hardcoded to `width={40}`, both tuned for short labels — a 3-digit price label like `"360$"` overflowed 40px and got clipped on the left edge. `CHART_MARGIN.left` is now `4`, and the axis width defaults to `50` via a new `yAxisWidth?: number` prop (`TimeSeriesChartProps`), so consumers with longer tick labels (bigger numbers, longer units) can widen it further without patching the chart.
@@ -1 +1 @@
1
- {"version":3,"file":"chart_controls.d.ts","sourceRoot":"","sources":["../../src/charts/chart_controls.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGzD,YAAY,EAAE,SAAS,EAAE,CAAC;AAI1B,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IACtC,iBAAiB,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,sEAAsE;IACtE,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+ID,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,MAAuB,EACvB,UAAgC,EAChC,KAAK,EACL,SAAS,GACV,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CA+BzC"}
1
+ {"version":3,"file":"chart_controls.d.ts","sourceRoot":"","sources":["../../src/charts/chart_controls.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAIzD,YAAY,EAAE,SAAS,EAAE,CAAC;AAI1B,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IACtC,iBAAiB,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAC1C,sEAAsE;IACtE,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+ID,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,MAAuB,EACvB,UAAgC,EAChC,KAAK,EACL,SAAS,GACV,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CA+BzC"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { t as translate } from '../lib/index.js';
3
4
  // ── Constants ─────────────────────────────────────────────────────────────────
4
5
  const DEFAULT_THEME = {
5
6
  ink: '#2f2a25',
@@ -11,15 +12,15 @@ const DEFAULT_THEME = {
11
12
  const DEFAULT_GRAINS = ['day', 'week', 'month', 'year'];
12
13
  const DEFAULT_CHART_TYPES = ['line', 'bar'];
13
14
  const GRAIN_LABELS = {
14
- day: 'Daily',
15
- week: 'Weekly',
16
- month: 'Monthly',
17
- quarter: 'Quarterly',
18
- year: 'Yearly',
15
+ day: translate('chart_controls.grain_day'),
16
+ week: translate('chart_controls.grain_week'),
17
+ month: translate('chart_controls.grain_month'),
18
+ quarter: translate('chart_controls.grain_quarter'),
19
+ year: translate('chart_controls.grain_year'),
19
20
  };
20
21
  const CHART_TYPE_LABELS = {
21
- line: 'Line',
22
- bar: 'Bar',
22
+ line: translate('chart_controls.type_line'),
23
+ bar: translate('chart_controls.type_bar'),
23
24
  };
24
25
  // ── Tiny SVG icons (optional visual hint beside each label) ───────────────────
25
26
  function LineIcon() {
@@ -1 +1 @@
1
- {"version":3,"file":"line_chart.d.ts","sourceRoot":"","sources":["../../src/charts/line_chart.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,IAAS,EACT,WAAkB,EAClB,KAAK,EACL,UAAU,EACV,KAAK,EACL,SAAS,GACV,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CA6GrC"}
1
+ {"version":3,"file":"line_chart.d.ts","sourceRoot":"","sources":["../../src/charts/line_chart.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,IAAS,EACT,WAAkB,EAClB,KAAK,EACL,UAAU,EACV,KAAK,EACL,SAAS,GACV,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CA6GrC"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { LineChart as RechartsLineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, } from 'recharts';
4
4
  import { ChartLegend, ChartTooltip, resolveChartTheme, } from './chart_common.js';
5
+ import { t as translate } from '../lib/index.js';
5
6
  /** See `TimeSeriesChart`'s copy — same reasoning, same numbers. */
6
7
  const CHART_MARGIN = { top: 8, right: 8, bottom: 0, left: -4 };
7
8
  export function LineChart({ data, dates, color, width, height, unit = '', showTooltip = true, label, showLegend, theme, className, }) {
@@ -16,7 +17,7 @@ export function LineChart({ data, dates, color, width, height, unit = '', showTo
16
17
  height: chartHeight,
17
18
  color: t.muted,
18
19
  fontSize: 14,
19
- }, children: "No data" }));
20
+ }, children: translate('line_chart.no_data') }));
20
21
  }
21
22
  const chartData = dates.map((d, i) => ({ x: d, value: data[i] ?? null }));
22
23
  const legendVisible = showLegend ?? label != null;
@@ -1 +1 @@
1
- {"version":3,"file":"multi_line_chart.d.ts","sourceRoot":"","sources":["../../src/charts/multi_line_chart.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,WAAkB,EAClB,UAAiB,EACjB,SAAS,GACV,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CAuE1C"}
1
+ {"version":3,"file":"multi_line_chart.d.ts","sourceRoot":"","sources":["../../src/charts/multi_line_chart.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,KAAK,EACL,KAAK,EACL,MAAM,EACN,WAAkB,EAClB,UAAiB,EACjB,SAAS,GACV,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CAuE1C"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { LineChart as RechartsLineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from 'recharts';
4
+ import { t } from '../lib/index.js';
4
5
  export function MultiLineChart({ series, dates, width, height, showTooltip = true, showLegend = true, className, }) {
5
6
  const chartHeight = height ?? 130;
6
7
  // Empty series or all-empty guard — render a placeholder, never throw
@@ -14,7 +15,7 @@ export function MultiLineChart({ series, dates, width, height, showTooltip = tru
14
15
  height: chartHeight,
15
16
  color: '#9ca3af',
16
17
  fontSize: 14,
17
- }, children: "No data" }));
18
+ }, children: t('multi_line_chart.no_data') }));
18
19
  }
19
20
  // Build wide rows: { x: date, [seriesLabel]: value | null, ... }
20
21
  const chartData = dates.map((d, i) => {
@@ -42,6 +42,12 @@ export interface TimeSeriesChartProps {
42
42
  * into the `height` you asked for.
43
43
  */
44
44
  showLegend?: boolean;
45
+ /**
46
+ * Width (px) reserved for the Y axis tick labels. Default 50 — enough for
47
+ * a 3-digit price plus a currency symbol (e.g. "360$") without clipping.
48
+ * Widen it further for longer labels (large numbers, longer units).
49
+ */
50
+ yAxisWidth?: number;
45
51
  className?: string;
46
52
  }
47
53
  export declare function TimeSeriesChart(props: TimeSeriesChartProps): React.ReactElement;
@@ -1 +1 @@
1
- {"version":3,"file":"time_series_chart.d.ts","sourceRoot":"","sources":["../../src/charts/time_series_chart.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAQjE,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,kEAAkE;IAClE,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wBAAwB;IACxB,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,qEAAqE;IACrE,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IACvC,iBAAiB,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAC3C,uGAAuG;IACvG,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mFAAmF;IACnF,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAYD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CAiQ/E"}
1
+ {"version":3,"file":"time_series_chart.d.ts","sourceRoot":"","sources":["../../src/charts/time_series_chart.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAQjE,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKzD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,eAAe,CAAC;IACtB,kEAAkE;IAClE,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wBAAwB;IACxB,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,qEAAqE;IACrE,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IACvC,iBAAiB,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAC3C,uGAAuG;IACvG,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mFAAmF;IACnF,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAeD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CAkQ/E"}
@@ -5,16 +5,19 @@ import { LineChart as RLineChart, Line, BarChart as RBarChart, Bar, XAxis, YAxis
5
5
  import { aggregateSeries } from '../lib/time_bucket.js';
6
6
  import { ChartControls } from './chart_controls.js';
7
7
  import { ChartLegend, ChartTooltip, resolveChartTheme, } from './chart_common.js';
8
+ import { t as translate } from '../lib/index.js';
8
9
  // ── TimeSeriesChart ────────────────────────────────────────────────────────────
10
+ /** Default width (px) reserved for the Y axis; see `yAxisWidth` prop. */
11
+ const DEFAULT_Y_AXIS_WIDTH = 50;
9
12
  /**
10
13
  * Breathing room round the plot. `top: 8` stops a peak's stroke being clipped
11
14
  * by the container edge; `right: 8` does the same for the last point's active
12
- * dot; `left: -4` claws back the gap recharts leaves beside a `width: 40`
13
- * Y axis whose labels are short.
15
+ * dot; `left: 4` gives the Y axis tick labels room so they aren't clipped by
16
+ * the container edge.
14
17
  */
15
- const CHART_MARGIN = { top: 8, right: 8, bottom: 0, left: -4 };
18
+ const CHART_MARGIN = { top: 8, right: 8, bottom: 0, left: 4 };
16
19
  export function TimeSeriesChart(props) {
17
- const { dates, series, data, color, label, agg, height = 220, unit, theme, referenceDate, grain: grainProp, chartType: chartTypeProp, onGrainChange, onChartTypeChange, grains, showLegend, className, } = props;
20
+ const { dates, series, data, color, label, agg, height = 220, unit, theme, referenceDate, grain: grainProp, chartType: chartTypeProp, onGrainChange, onChartTypeChange, grains, showLegend, yAxisWidth, className, } = props;
18
21
  // ── Controlled vs uncontrolled ────────────────────────────────────────────
19
22
  const isControlled = grainProp !== undefined && chartTypeProp !== undefined;
20
23
  const [grainState, setGrainState] = React.useState(grainProp ?? 'day');
@@ -57,7 +60,7 @@ export function TimeSeriesChart(props) {
57
60
  height,
58
61
  color: t.muted,
59
62
  fontSize: 14,
60
- }, children: "No data" }));
63
+ }, children: translate('time_series_chart.no_data') }));
61
64
  }
62
65
  // ── Roll-up ───────────────────────────────────────────────────────────────
63
66
  const rolled = resolvedSeries.map((s) => aggregateSeries(dates, s.data, activeGrain, s.agg ?? 'sum'));
@@ -66,7 +69,7 @@ export function TimeSeriesChart(props) {
66
69
  const seriesMeta = resolvedSeries.map((s, i) => ({
67
70
  key: `s${i}`,
68
71
  color: s.color,
69
- label: s.label ?? (resolvedSeries.length > 1 ? `Series ${i + 1}` : ''),
72
+ label: s.label ?? (resolvedSeries.length > 1 ? translate('time_series_chart.series_label', { n: i + 1 }) : ''),
70
73
  }));
71
74
  const chartRows = bucketDates.map((d, i) => {
72
75
  const row = { x: d };
@@ -99,7 +102,7 @@ export function TimeSeriesChart(props) {
99
102
  axisLine: false,
100
103
  tickLine: false,
101
104
  tickMargin: 8,
102
- width: 40,
105
+ width: yAxisWidth ?? DEFAULT_Y_AXIS_WIDTH,
103
106
  tickFormatter: yTickFmt,
104
107
  };
105
108
  // Vertical gridlines carry no information a time axis doesn't already
@@ -118,7 +121,7 @@ export function TimeSeriesChart(props) {
118
121
  .filter((s) => s.label !== '')
119
122
  .map((s) => ({ label: s.label, color: s.color }));
120
123
  const legendVisible = showLegend ?? (legendEntries.length > 1 && legendEntries.length === seriesMeta.length);
121
- const referenceEl = showReference ? (_jsx(ReferenceLine, { x: referenceDate, stroke: "#fbbf24", strokeDasharray: "4 3", label: { value: 'today', position: 'insideTopRight', fontSize: 10, fill: '#fbbf24' } })) : null;
124
+ const referenceEl = showReference ? (_jsx(ReferenceLine, { x: referenceDate, stroke: "#fbbf24", strokeDasharray: "4 3", label: { value: translate('time_series_chart.reference_today'), position: 'insideTopRight', fontSize: 10, fill: '#fbbf24' } })) : null;
122
125
  // ── Render ────────────────────────────────────────────────────────────────
123
126
  return (_jsxs("div", { className: className, children: [showControls && (_jsx("div", { style: { marginBottom: 8 }, children: _jsx(ChartControls, { grain: activeGrain, chartType: activeType, onGrainChange: handleGrain, onChartTypeChange: handleType, grains: grains, theme: theme }) })), _jsx("div", { style: { height, width: '100%' }, children: mounted && activeType === 'bar' ? (_jsx(ResponsiveContainer, { width: "100%", height: height, children: _jsxs(RBarChart, { data: chartRows, margin: CHART_MARGIN, barGap: 2, children: [gridEl, _jsx(XAxis, { ...xAxisProps }), _jsx(YAxis, { ...yAxisProps }), tooltipEl, referenceEl, seriesMeta.map((s) => (_jsx(Bar, { dataKey: s.key, name: s.label, fill: s.color, radius: [3, 3, 0, 0], maxBarSize: 28, isAnimationActive: false }, s.key)))] }) })) : mounted ? (_jsx(ResponsiveContainer, { width: "100%", height: height, children: _jsxs(RLineChart, { data: chartRows, margin: CHART_MARGIN, children: [gridEl, _jsx(XAxis, { ...xAxisProps }), _jsx(YAxis, { ...yAxisProps }), tooltipEl, referenceEl, seriesMeta.map((s) => (_jsx(Line, { type: "monotone", dataKey: s.key, name: s.label, stroke: s.color, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", dot: false,
124
127
  // A hover dot ringed in the chart surface reads as a marker
@@ -1,4 +1,5 @@
1
1
  export { CONTRACT_VERSION } from './lib/contract-version.js';
2
+ export { t } from './lib/index.js';
2
3
  export { parseDescriptor } from './schema/descriptor.js';
3
4
  export { parseQuery } from './schema/query.js';
4
5
  export { derivePickerOptions } from './lib/picker.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,KAAK,EACL,GAAG,EACH,SAAS,EACT,MAAM,EACN,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACnF,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC7F,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGjF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAK3D,OAAO,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC5F,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,KAAK,EACL,GAAG,EACH,SAAS,EACT,MAAM,EACN,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACnF,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC7F,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGjF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAK3D,OAAO,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,YAAY,EAAE,kBAAkB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC5F,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -1,5 +1,6 @@
1
1
  // Client-safe entry — no Node.js builtins.
2
2
  export { CONTRACT_VERSION } from './lib/contract-version.js';
3
+ export { t } from './lib/index.js';
3
4
  export { parseDescriptor } from './schema/descriptor.js';
4
5
  export { parseQuery } from './schema/query.js';
5
6
  export { derivePickerOptions } from './lib/picker.js';
@@ -25,7 +25,7 @@ export function formatValue(value, format) {
25
25
  return '';
26
26
  switch (format.kind) {
27
27
  case 'currency':
28
- return formatCurrency(Number(value), format.ccy);
28
+ return formatCurrency(Number(value), { currency: format.ccy });
29
29
  case 'number':
30
30
  return formatNumber(Number(value), format.decimals);
31
31
  case 'percent':
@@ -1,3 +1,4 @@
1
1
  export { CONTRACT_VERSION } from './contract-version.js';
2
2
  export { derivePickerOptions } from './picker.js';
3
+ export declare const t: import("hazo_core/i18n").TFunc;
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAoBlD,eAAO,MAAM,CAAC,gCAAqC,CAAC"}
package/dist/lib/index.js CHANGED
@@ -1,2 +1,20 @@
1
1
  export { CONTRACT_VERSION } from './contract-version.js';
2
2
  export { derivePickerOptions } from './picker.js';
3
+ // ---------------------------------------------------------------------------
4
+ // i18n
5
+ // ---------------------------------------------------------------------------
6
+ //
7
+ // Uses a plain `import ... from '../locales/en.json'` (resolveJsonModule),
8
+ // NOT `createRequire` — this package's client entry (index.client.ts)
9
+ // re-exports the chart/visualizer components that call `t()`, so this
10
+ // catalog module ends up bundled into browser code. `createRequire` is
11
+ // Node-only and would break there; a plain JSON import works under this
12
+ // package's "module": "Node16" tsconfig (no import-attribute syntax needed)
13
+ // and is bundler/browser-safe.
14
+ import en from '../locales/en.json';
15
+ import { createPackageT } from 'hazo_core/i18n';
16
+ // Namespaced translator for this package's own baked-in strings (chart
17
+ // empty states, axis/legend labels, visualizer display names). `en.json` is
18
+ // a flat { "key": "English text" } catalog — add keys there as they come
19
+ // up, then call t('key', { var: value }) for {{var}} interpolation.
20
+ export const t = createPackageT('hazo_dataviz', en);
@@ -0,0 +1,22 @@
1
+ {
2
+ "chart_frame.no_data": "No data to display",
3
+ "table.no_data": "No data to display",
4
+ "line_chart.no_data": "No data",
5
+ "multi_line_chart.no_data": "No data",
6
+ "time_series_chart.no_data": "No data",
7
+ "time_series_chart.series_label": "Series {{n}}",
8
+ "time_series_chart.reference_today": "today",
9
+ "chart_controls.grain_day": "Daily",
10
+ "chart_controls.grain_week": "Weekly",
11
+ "chart_controls.grain_month": "Monthly",
12
+ "chart_controls.grain_quarter": "Quarterly",
13
+ "chart_controls.grain_year": "Yearly",
14
+ "chart_controls.type_line": "Line",
15
+ "chart_controls.type_bar": "Bar",
16
+ "visualizer.table_label": "Table",
17
+ "visualizer.single_stat_label": "Single Stat",
18
+ "visualizer.area_label": "Area Chart",
19
+ "visualizer.bar_label": "Bar Chart",
20
+ "visualizer.line_label": "Line Chart",
21
+ "visualizer.stacked_bar_label": "Stacked Bar Chart"
22
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../src/visualizers/area.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AA+CtF,eAAO,MAAM,IAAI,EAAE,UAgFlB,CAAC"}
1
+ {"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../src/visualizers/area.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAgDtF,eAAO,MAAM,IAAI,EAAE,UAgFlB,CAAC"}
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from 'recharts';
4
4
  import { classifyShape } from '../lib/shape.js';
5
5
  import { pickColor } from './palette.js';
6
+ import { t } from '../lib/index.js';
6
7
  import { makeFormatter, makeTooltip, EmptyState, axisProps, gridProps, legendProps, CHART_MARGIN, CHART_THEME, } from './chart_frame.js';
7
8
  function pivotData(result, encoding) {
8
9
  if (!encoding.series) {
@@ -29,7 +30,7 @@ function pivotData(result, encoding) {
29
30
  }
30
31
  export const area = {
31
32
  id: 'area',
32
- label: 'Area Chart',
33
+ label: t('visualizer.area_label'),
33
34
  accepts(descriptor, query) {
34
35
  const shape = classifyShape(descriptor, query);
35
36
  if (shape.temporalDims.length >= 1 && shape.measureCount >= 1)
@@ -1 +1 @@
1
- {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/visualizers/bar.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAetF,eAAO,MAAM,GAAG,EAAE,UA+DjB,CAAC"}
1
+ {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../src/visualizers/bar.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAgBtF,eAAO,MAAM,GAAG,EAAE,UA+DjB,CAAC"}
@@ -3,10 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from 'recharts';
4
4
  import { classifyShape } from '../lib/shape.js';
5
5
  import { pickColor } from './palette.js';
6
+ import { t } from '../lib/index.js';
6
7
  import { makeFormatter, makeTooltip, EmptyState, axisProps, gridProps, legendProps, CHART_MARGIN, } from './chart_frame.js';
7
8
  export const bar = {
8
9
  id: 'bar',
9
- label: 'Bar Chart',
10
+ label: t('visualizer.bar_label'),
10
11
  accepts(descriptor, query) {
11
12
  const shape = classifyShape(descriptor, query);
12
13
  if (shape.dimCount === 1 && shape.categoricalDims.length === 1 && shape.measureCount >= 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"chart_frame.d.ts","sourceRoot":"","sources":["../../src/visualizers/chart_frame.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;IACtB,sCAAsC;;IAEtC,iDAAiD;;IAEjD,8CAA8C;;IAE9C,oCAAoC;;IAEpC,6BAA6B;;IAE7B,2BAA2B;;IAE3B,mCAAmC;;CAE3B,CAAC;AAEX,yEAAyE;AACzE,eAAO,MAAM,YAAY;;;;;CAAsD,CAAC;AAEhF,uFAAuF;AACvF,eAAO,MAAM,SAAS;;;;;;;;;;CAKZ,CAAC;AAEX,sFAAsF;AACtF,eAAO,MAAM,SAAS;;;CAGZ,CAAC;AAEX;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAYhF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAK3G;AAED,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AAMH,wBAAgB,WAAW,CACzB,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,EACtC,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GACrC,CAAC,KAAK,EAAE,kBAAkB,KAAK,GAAG,CAqEpC;AAED,wDAAwD;AACxD,eAAO,MAAM,WAAW;;;;;;;CAOvB,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,IAAI,KAAK,CAAC,YAAY,CAqB/C"}
1
+ {"version":3,"file":"chart_frame.d.ts","sourceRoot":"","sources":["../../src/visualizers/chart_frame.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;IACtB,sCAAsC;;IAEtC,iDAAiD;;IAEjD,8CAA8C;;IAE9C,oCAAoC;;IAEpC,6BAA6B;;IAE7B,2BAA2B;;IAE3B,mCAAmC;;CAE3B,CAAC;AAEX,yEAAyE;AACzE,eAAO,MAAM,YAAY;;;;;CAAsD,CAAC;AAEhF,uFAAuF;AACvF,eAAO,MAAM,SAAS;;;;;;;;;;CAKZ,CAAC;AAEX,sFAAsF;AACtF,eAAO,MAAM,SAAS;;;CAGZ,CAAC;AAEX;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAYhF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAK3G;AAED,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAED,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AAMH,wBAAgB,WAAW,CACzB,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,EACtC,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,GACrC,CAAC,KAAK,EAAE,kBAAkB,KAAK,GAAG,CAqEpC;AAED,wDAAwD;AACxD,eAAO,MAAM,WAAW;;;;;;;CAOvB,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,IAAI,KAAK,CAAC,YAAY,CAqB/C"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { formatValue } from '../lib/format.js';
4
+ import { t } from '../lib/index.js';
4
5
  /**
5
6
  * "Studio" chart theme — a warm, editorial token set shared by every recharts
6
7
  * visualizer so the package renders one coherent look out of the box.
@@ -142,5 +143,5 @@ export function EmptyState() {
142
143
  height: 120,
143
144
  color: CHART_THEME.muted,
144
145
  fontSize: 13,
145
- }, children: [_jsxs("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: CHART_THEME.hairline, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M3 3v18h18" }), _jsx("path", { d: "M7 15l3-3 3 2 5-6" })] }), _jsx("span", { children: "No data to display" })] }));
146
+ }, children: [_jsxs("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: CHART_THEME.hairline, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("path", { d: "M3 3v18h18" }), _jsx("path", { d: "M7 15l3-3 3 2 5-6" })] }), _jsx("span", { children: t('chart_frame.no_data') })] }));
146
147
  }
@@ -1 +1 @@
1
- {"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/visualizers/line.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAiDtF,eAAO,MAAM,IAAI,EAAE,UAsElB,CAAC"}
1
+ {"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/visualizers/line.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAkDtF,eAAO,MAAM,IAAI,EAAE,UAsElB,CAAC"}
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from 'recharts';
4
4
  import { classifyShape } from '../lib/shape.js';
5
5
  import { pickColor } from './palette.js';
6
+ import { t } from '../lib/index.js';
6
7
  import { makeFormatter, makeTooltip, EmptyState, axisProps, gridProps, legendProps, CHART_MARGIN, CHART_THEME, } from './chart_frame.js';
7
8
  function pivotData(result, encoding) {
8
9
  if (!encoding.series) {
@@ -31,7 +32,7 @@ function pivotData(result, encoding) {
31
32
  }
32
33
  export const line = {
33
34
  id: 'line',
34
- label: 'Line Chart',
35
+ label: t('visualizer.line_label'),
35
36
  accepts(descriptor, query) {
36
37
  const shape = classifyShape(descriptor, query);
37
38
  if (shape.temporalDims.length >= 1 && shape.measureCount >= 1)
@@ -1 +1 @@
1
- {"version":3,"file":"single_stat.d.ts","sourceRoot":"","sources":["../../src/visualizers/single_stat.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAOtF,eAAO,MAAM,UAAU,EAAE,UAmFxB,CAAC"}
1
+ {"version":3,"file":"single_stat.d.ts","sourceRoot":"","sources":["../../src/visualizers/single_stat.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAQtF,eAAO,MAAM,UAAU,EAAE,UAmFxB,CAAC"}
@@ -3,9 +3,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { classifyShape } from '../lib/shape.js';
4
4
  import { makeFormatter, CHART_THEME } from './chart_frame.js';
5
5
  import { pickColor } from './palette.js';
6
+ import { t } from '../lib/index.js';
6
7
  export const singleStat = {
7
8
  id: 'single_stat',
8
- label: 'Single Stat',
9
+ label: t('visualizer.single_stat_label'),
9
10
  accepts(descriptor, query) {
10
11
  const shape = classifyShape(descriptor, query);
11
12
  if (shape.measureCount === 1 && shape.dimCount === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"stacked_bar.d.ts","sourceRoot":"","sources":["../../src/visualizers/stacked_bar.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AA8CtF,eAAO,MAAM,UAAU,EAAE,UAmFxB,CAAC"}
1
+ {"version":3,"file":"stacked_bar.d.ts","sourceRoot":"","sources":["../../src/visualizers/stacked_bar.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AA+CtF,eAAO,MAAM,UAAU,EAAE,UAmFxB,CAAC"}
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, } from 'recharts';
4
4
  import { classifyShape } from '../lib/shape.js';
5
5
  import { pickColor } from './palette.js';
6
+ import { t } from '../lib/index.js';
6
7
  import { makeFormatter, makeTooltip, EmptyState, axisProps, gridProps, legendProps, CHART_MARGIN, } from './chart_frame.js';
7
8
  function pivotData(result, encoding) {
8
9
  if (!encoding.series) {
@@ -29,7 +30,7 @@ function pivotData(result, encoding) {
29
30
  }
30
31
  export const stackedBar = {
31
32
  id: 'stacked_bar',
32
- label: 'Stacked Bar Chart',
33
+ label: t('visualizer.stacked_bar_label'),
33
34
  accepts(descriptor, query) {
34
35
  const shape = classifyShape(descriptor, query);
35
36
  // A stacked bar needs two dimensions and at least one categorical dimension to
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/visualizers/table.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAKtF,eAAO,MAAM,KAAK,EAAE,UAiGnB,CAAC"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/visualizers/table.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAoC,MAAM,mBAAmB,CAAC;AAMtF,eAAO,MAAM,KAAK,EAAE,UAiGnB,CAAC"}
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { makeFormatter, CHART_THEME } from './chart_frame.js';
4
+ import { t } from '../lib/index.js';
4
5
  export const table = {
5
6
  id: 'table',
6
- label: 'Table',
7
+ label: t('visualizer.table_label'),
7
8
  accepts(_descriptor, _query) {
8
9
  return 0.1;
9
10
  },
@@ -16,7 +17,7 @@ export const table = {
16
17
  height: 80,
17
18
  color: CHART_THEME.muted,
18
19
  fontSize: 13,
19
- }, children: "No data to display" }));
20
+ }, children: t('table.no_data') }));
20
21
  }
21
22
  const formatters = result.columns.map((col) => makeFormatter(col));
22
23
  return (_jsx("div", { style: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_dataviz",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Headless data visualization primitives for hazo apps",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
@@ -45,10 +45,11 @@
45
45
  "zod": "^4.1.12"
46
46
  },
47
47
  "peerDependencies": {
48
- "hazo_api": "^2.6.1",
49
- "hazo_connect": "^4.1.0",
50
- "hazo_core": "^2.2.0",
51
- "hazo_ui": "^6.11.2",
48
+ "hazo_api": "^2.8.0",
49
+ "hazo_connect": "^4.3.0",
50
+ "hazo_core": "^2.4.0",
51
+ "hazo_i18n": "^0.5.0",
52
+ "hazo_ui": "^6.12.0",
52
53
  "react": "^18.0.0 || ^19.0.0",
53
54
  "react-dom": "^18.0.0 || ^19.0.0",
54
55
  "recharts": "^2.15.4 || ^3.0.0"
@@ -57,6 +58,9 @@
57
58
  "hazo_connect": {
58
59
  "optional": true
59
60
  },
61
+ "hazo_i18n": {
62
+ "optional": true
63
+ },
60
64
  "hazo_ui": {
61
65
  "optional": true
62
66
  },