From 495549630812c3dabfeeff00f11084e68148f705 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Tue, 10 Nov 2026 11:09:19 +0000 Subject: [PATCH 1/2] feat(docs): look up the API by name with `appkit docs NAME...` Agents writing AppKit apps need a component's props before they write code, but `appkit docs` only navigated sections and file paths: `appkit docs BarChart` answered "No section matching", so agents probed `node_modules` and `.d.ts` files instead. `appkit docs BarChart DataTable Select useAnalyticsQuery sql` now prints each name's page, part, hook section or reference page, with props one per line and no table chrome. A multi-name lookup leaves out examples and prints a prop or note that an earlier name already showed only by name, so a screen's worth of names stays short (about 9K characters for ten). An unknown name gets similar names, by name and by component description (DatePicker suggests Calendar). Some behavior was documented only in code, so agents learned it by breaking apps. The docs now state DataTable's column keys and cell formatting, which colors ECharts can draw, the `valueFormatter` signature, the chart `data` row type, and `useMemo` for `useAnalyticsQuery` parameters. Signed-off-by: Pedro Figueiredo --- docs/docs/api/appkit-ui/data/AreaChart.mdx | 6 +- docs/docs/api/appkit-ui/data/BarChart.mdx | 6 +- docs/docs/api/appkit-ui/data/DataTable.mdx | 6 + docs/docs/api/appkit-ui/data/DonutChart.mdx | 6 +- docs/docs/api/appkit-ui/data/HeatmapChart.mdx | 6 +- docs/docs/api/appkit-ui/data/LineChart.mdx | 6 +- docs/docs/api/appkit-ui/data/PieChart.mdx | 6 +- docs/docs/api/appkit-ui/data/RadarChart.mdx | 6 +- docs/docs/api/appkit-ui/data/ScatterChart.mdx | 6 +- docs/docs/plugins/analytics.md | 2 +- packages/appkit-ui/src/react/charts/types.ts | 15 +- .../appkit-ui/src/react/table/data-table.tsx | 6 + packages/shared/src/cli/commands/docs.test.ts | 140 +++++++++ packages/shared/src/cli/commands/docs.ts | 265 +++++++++++++++++- tools/dist-appkit.ts | 1 + tools/generate-component-mdx.ts | 2 +- 16 files changed, 451 insertions(+), 34 deletions(-) create mode 100644 packages/shared/src/cli/commands/docs.test.ts diff --git a/docs/docs/api/appkit-ui/data/AreaChart.mdx b/docs/docs/api/appkit-ui/data/AreaChart.mdx index f9a9084ff..59ce64da1 100644 --- a/docs/docs/api/appkit-ui/data/AreaChart.mdx +++ b/docs/docs/api/appkit-ui/data/AreaChart.mdx @@ -55,11 +55,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -67,7 +67,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `orientation` | `"horizontal" \| "vertical"` | | `"vertical"` | Chart orientation | diff --git a/docs/docs/api/appkit-ui/data/BarChart.mdx b/docs/docs/api/appkit-ui/data/BarChart.mdx index e4d832bf1..c016e9add 100644 --- a/docs/docs/api/appkit-ui/data/BarChart.mdx +++ b/docs/docs/api/appkit-ui/data/BarChart.mdx @@ -52,11 +52,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -64,7 +64,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `orientation` | `"horizontal" \| "vertical"` | | `"vertical"` | Chart orientation | diff --git a/docs/docs/api/appkit-ui/data/DataTable.mdx b/docs/docs/api/appkit-ui/data/DataTable.mdx index e6bcf8c59..2f9c6cf98 100644 --- a/docs/docs/api/appkit-ui/data/DataTable.mdx +++ b/docs/docs/api/appkit-ui/data/DataTable.mdx @@ -38,6 +38,12 @@ Features: - Responsive design - Supports opinionated mode (auto columns) and full-control mode (`children(table)`) +In opinionated mode the columns are the keys of the first row that match `/^[a-zA-Z_][a-zA-Z0-9_]*$/` (other +keys are dropped), headed by the key in Title Case. Every cell whose value parses as a number, numeric strings +included, is right-aligned and formatted: a key containing `cost`, `price`, `spend`, `revenue` or `usd` shows as +USD, and any other value of 1000 or more is abbreviated (10021 shows as 10K). For ids, zip codes or years, render +a `Table` from `useAnalyticsQuery` rows instead. + **Source:** [`packages/appkit-ui/src/react/table/data-table.tsx`](https://github.com/databricks/appkit/blob/main/packages/appkit-ui/src/react/table/data-table.tsx) diff --git a/docs/docs/api/appkit-ui/data/DonutChart.mdx b/docs/docs/api/appkit-ui/data/DonutChart.mdx index e7416551e..42bed7fb6 100644 --- a/docs/docs/api/appkit-ui/data/DonutChart.mdx +++ b/docs/docs/api/appkit-ui/data/DonutChart.mdx @@ -49,11 +49,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -61,7 +61,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `innerRadius` | `number` | | `0` | Inner radius for donut charts (0-100%) | diff --git a/docs/docs/api/appkit-ui/data/HeatmapChart.mdx b/docs/docs/api/appkit-ui/data/HeatmapChart.mdx index e62e6e35c..48a959935 100644 --- a/docs/docs/api/appkit-ui/data/HeatmapChart.mdx +++ b/docs/docs/api/appkit-ui/data/HeatmapChart.mdx @@ -66,11 +66,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -78,7 +78,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `yAxisKey` | `string` | | - | Field key for the Y-axis categories. For heatmaps, data should have: xKey (column), yAxisKey (row), and yKey (value). | diff --git a/docs/docs/api/appkit-ui/data/LineChart.mdx b/docs/docs/api/appkit-ui/data/LineChart.mdx index 992acd3e1..eaa662d00 100644 --- a/docs/docs/api/appkit-ui/data/LineChart.mdx +++ b/docs/docs/api/appkit-ui/data/LineChart.mdx @@ -54,11 +54,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -66,7 +66,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `orientation` | `"horizontal" \| "vertical"` | | `"vertical"` | Chart orientation | diff --git a/docs/docs/api/appkit-ui/data/PieChart.mdx b/docs/docs/api/appkit-ui/data/PieChart.mdx index c5168fa07..60def78b4 100644 --- a/docs/docs/api/appkit-ui/data/PieChart.mdx +++ b/docs/docs/api/appkit-ui/data/PieChart.mdx @@ -49,11 +49,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -61,7 +61,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `innerRadius` | `number` | | `0` | Inner radius for donut charts (0-100%) | diff --git a/docs/docs/api/appkit-ui/data/RadarChart.mdx b/docs/docs/api/appkit-ui/data/RadarChart.mdx index 1da2ee306..9bb102b65 100644 --- a/docs/docs/api/appkit-ui/data/RadarChart.mdx +++ b/docs/docs/api/appkit-ui/data/RadarChart.mdx @@ -53,11 +53,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -65,7 +65,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `showArea` | `boolean` | | `true` | Show area fill | diff --git a/docs/docs/api/appkit-ui/data/ScatterChart.mdx b/docs/docs/api/appkit-ui/data/ScatterChart.mdx index 4803d6520..0e395190a 100644 --- a/docs/docs/api/appkit-ui/data/ScatterChart.mdx +++ b/docs/docs/api/appkit-ui/data/ScatterChart.mdx @@ -55,11 +55,11 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `parameters` | `Record` | | - | Query parameters passed to the analytics endpoint | | `format` | `"auto" \| "json_array" \| "arrow_stream" \| "json" \| "arrow"` | | `"auto"` | Data format to use - "json_array": Use JSON format (smaller payloads, simpler) - "arrow_stream": Use Arrow format (faster for large datasets) - "auto": Automatically select based on expected data size | | `transformer` | `((data: T) => T)` | | - | Transform raw data before rendering | -| `data` | `ChartDataInput` | | - | Arrow Table or JSON array | +| `data` | `ChartDataInput` | | - | Arrow Table or an array of row objects (interfaces and `as const` arrays too). | | `title` | `string` | | - | Chart title | | `showLegend` | `boolean` | | - | Show legend | | `colorPalette` | `"categorical" \| "sequential" \| "diverging"` | | - | Color palette to use. Auto-selected based on chart type if not specified. - "categorical": Distinct colors for different categories (bar, pie, line) - "sequential": Gradient for magnitude/intensity (heatmap) - "diverging": Two-tone for positive/negative values | -| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) | +| `colors` | `string[]` | | - | Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the sequential and diverging palettes), held to the same formats. | | `height` | `number` | | - | Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). | | `className` | `string` | | - | Additional CSS classes | | `xKey` | `string` | | - | X-axis field key. Auto-detected from schema if not provided. | @@ -67,7 +67,7 @@ Supports both query mode (queryKey + parameters) and data mode (static data). | `ariaLabel` | `string` | | - | Accessibility label for screen readers | | `testId` | `string` | | - | Test ID for automated testing | | `options` | `Record` | | - | Additional ECharts options to merge | -| `valueFormatter` | `ChartValueFormatter` | | - | Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | +| `valueFormatter` | `ChartValueFormatter` | | - | `(value: string \| number, field: string) => string`. Formats measure values in the chart's built-in value axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different format for each series. | | `onDataClick` | `((datum: ChartClickDatum) => void)` | | - | Pointer-only: charts render to <canvas>, so this does not fire for keyboard users. Provide a keyboard-accessible equivalent (e.g. a table row action) for the same action. | | `selected` | `string \| string[]` | | - | Controlled selection by category name. Matching data element(s) render at full prominence while the rest are dimmed. Drive it from your own state to reflect a cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis; other chart types ignore it. | | `symbolSize` | `number` | | `8` | Symbol size | diff --git a/docs/docs/plugins/analytics.md b/docs/docs/plugins/analytics.md index 61bbe1ba5..66e9dd350 100644 --- a/docs/docs/plugins/analytics.md +++ b/docs/docs/plugins/analytics.md @@ -286,7 +286,7 @@ Editing `definitions.json` is picked up on the next request — no server restar ### useAnalyticsQuery -React hook that subscribes to an analytics query over SSE and returns its latest result. +React hook that subscribes to an analytics query over SSE and returns its latest result. Wrap `parameters` in `useMemo` (see [Memoization](#memoization)): the query re-runs whenever the parameters object is a new reference. ```ts import { useAnalyticsQuery } from "@databricks/appkit-ui/react"; diff --git a/packages/appkit-ui/src/react/charts/types.ts b/packages/appkit-ui/src/react/charts/types.ts index c2e6ff3a1..f84fb1735 100644 --- a/packages/appkit-ui/src/react/charts/types.ts +++ b/packages/appkit-ui/src/react/charts/types.ts @@ -82,7 +82,12 @@ export interface ChartBaseProps { * - "diverging": Two-tone for positive/negative values */ colorPalette?: ChartColorPalette; - /** Custom colors for series (overrides colorPalette) */ + /** + * Custom colors for series (overrides colorPalette) as hex, `rgb()` or `hsl()` strings, since ECharts draws on a + * canvas and cannot resolve `var()` or parse `oklch()` (those draw gray); without it, series colors are the CSS + * variables `--chart-cat-1` to `--chart-cat-8` on `:root` (`--chart-seq-*` and `--chart-div-*` for the + * sequential and diverging palettes), held to the same formats. + */ colors?: string[]; /** Chart height in pixels. Defaults to filling its parent (see `chartSizeStyle`). */ height?: number; @@ -103,9 +108,9 @@ export interface ChartBaseProps { options?: Record; /** - * Formats measure values in the chart's built-in value axes, tooltips, and - * value labels. `field` is the corresponding `yKey`, so one formatter can - * select a different format for each series. + * `(value: string | number, field: string) => string`. Formats measure values in the chart's built-in value + * axes, tooltips, and value labels. `field` is the corresponding `yKey`, so one formatter can select a different + * format for each series. * * For charts with multiple series on one value axis, axis ticks use the * first `yKey`; each tooltip uses its own series field. @@ -193,7 +198,7 @@ export interface QueryProps extends ChartBaseProps { /** Props for direct data injection */ export interface DataProps extends ChartBaseProps { - /** Arrow Table or JSON array */ + /** Arrow Table or an array of row objects (interfaces and `as const` arrays too). */ data: ChartDataInput; // Discriminator: cannot use query props with direct data diff --git a/packages/appkit-ui/src/react/table/data-table.tsx b/packages/appkit-ui/src/react/table/data-table.tsx index c89efdc60..8a502abb6 100644 --- a/packages/appkit-ui/src/react/table/data-table.tsx +++ b/packages/appkit-ui/src/react/table/data-table.tsx @@ -40,6 +40,12 @@ import type { DataTableLabels, DataTableProps } from "./types"; * - Responsive design * - Supports opinionated mode (auto columns) and full-control mode (`children(table)`) * + * In opinionated mode the columns are the keys of the first row that match `/^[a-zA-Z_][a-zA-Z0-9_]*$/` (other + * keys are dropped), headed by the key in Title Case. Every cell whose value parses as a number, numeric strings + * included, is right-aligned and formatted: a key containing `cost`, `price`, `spend`, `revenue` or `usd` shows as + * USD, and any other value of 1000 or more is abbreviated (10021 shows as 10K). For ids, zip codes or years, render + * a `Table` from `useAnalyticsQuery` rows instead. + * * @param props - Props for the DataTable component * @param props.queryKey - The query key to fetch the data * @param props.parameters - The parameters to pass to the query. Required - use `{}` if none. diff --git a/packages/shared/src/cli/commands/docs.test.ts b/packages/shared/src/cli/commands/docs.test.ts new file mode 100644 index 000000000..3cbc71b48 --- /dev/null +++ b/packages/shared/src/cli/commands/docs.test.ts @@ -0,0 +1,140 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +import { afterAll, beforeAll, describe, expect, test } from "vitest"; + +import { apiIndex, lookupNames } from "./docs"; + +const anchor = (title: string) => + `[\u200b](#${title.toLowerCase()} "Direct link to ${title}")`; + +const chartPage = (name: string, ownProp: string) => + [ + `# ${name}`, + "", + `${name} component.`, + "", + `## Example${anchor("Example")}`, + "", + "```tsx", + `<${name} data={rows} />`, + "```", + "", + `## ${name}${anchor(name)}`, + "", + `### Props${anchor("Props")}`, + "", + "| Prop | Type | Required | Default | Description |", + "| ---- | ---- | -------- | ------- | ----------- |", + "| `height` | `number` | | `300` | Chart height in pixels. Applies to the canvas. |", + `| \`${ownProp}\` | \`string \\| string[]\` | | - | - |`, + ].join("\n"); + +const files: Record = { + "docs/api/appkit-ui/data/BarChart.md": chartPage("BarChart", "stacked"), + "docs/api/appkit-ui/data/LineChart.md": chartPage("LineChart", "smooth"), + "docs/api/appkit-ui/ui/Calendar.md": [ + "# Calendar", + "", + "Date picker component for selecting single dates or date ranges", + ].join("\n"), + "docs/api/appkit-ui/ui/Select.md": [ + "# Select", + "", + "Dropdown control", + "", + `## SelectItem${anchor("SelectItem")}`, + "", + "One option", + ].join("\n"), + "docs/api/appkit/Variable.sql.md": [ + "# Variable: sql", + "", + "```ts", + "const sql: { string: SQLStringMarker };", + "```", + "", + `## Type Declaration${anchor("Type Declaration")}`, + "", + "### string()", + "", + "```ts", + "string(value: string): SQLStringMarker;", + "```", + ].join("\n"), + "docs/plugins/analytics.md": [ + "# Analytics plugin", + "", + `### useAnalyticsQuery${anchor("useAnalyticsQuery")}`, + "", + "Subscribes to an analytics query.", + "", + "### Memoization", + ].join("\n"), +}; + +let root: string; + +beforeAll(() => { + root = fs.mkdtempSync(path.join(os.tmpdir(), "appkit-docs-")); + for (const [file, text] of Object.entries(files)) { + fs.mkdirSync(path.dirname(path.join(root, file)), { recursive: true }); + fs.writeFileSync(path.join(root, file), text); + } +}); + +afterAll(() => { + fs.rmSync(root, { recursive: true, force: true }); +}); + +describe("appkit docs NAME...", () => { + test("indexes component pages, their parts, reference pages and hooks", () => { + const names = [...apiIndex(root).keys()]; + expect(names).toEqual( + expect.arrayContaining([ + "BarChart", + "Select", + "SelectItem", + "sql", + "useAnalyticsQuery", + ]), + ); + expect(names).not.toContain("Props"); + expect(names).not.toContain("Memoization"); + }); + + test("prints one name in full, props one per line", () => { + const out = lookupNames(root, ["BarChart"]); + expect(out).toContain(""); + expect(out).toContain( + "- height?: number = 300 — Chart height in pixels. Applies to the canvas.", + ); + expect(out).toContain("- stacked?: string | string[]"); + expect(out).not.toContain("Direct link"); + }); + + test("prints several names without examples, and a shared prop once", () => { + const out = lookupNames(root, ["BarChart", "LineChart", "sql"]); + expect(out).not.toContain(""); + expect(out).toContain( + "- height?: number = 300 — Chart height in pixels.\n", + ); + expect(out).toContain("- height: as in BarChart"); + expect(out).toContain("- smooth?: string | string[]"); + expect(out).toContain("Members: string()"); + expect(out).not.toContain("string(value: string)"); + }); + + test("names what it cannot find, with similar names", () => { + expect(lookupNames(root, ["SelectOption"])).toContain( + "Not documented. Similar: SelectItem, Select", + ); + }); + + test("suggests a component whose description matches an unknown name", () => { + expect(lookupNames(root, ["DateRangePicker"])).toContain( + "Not documented. Similar: Calendar", + ); + }); +}); diff --git a/packages/shared/src/cli/commands/docs.ts b/packages/shared/src/cli/commands/docs.ts index fb7d477ed..2b724e3cb 100644 --- a/packages/shared/src/cli/commands/docs.ts +++ b/packages/shared/src/cli/commands/docs.ts @@ -98,14 +98,272 @@ function formatExpandedSection(section: Section): string { return `## ${section.name}${section.body}`; } -function runDocs(query: string | undefined, options: { full?: boolean }) { +interface ApiEntry { + file: string; + line: number; + level: number; +} + +/** Headings in component pages that name a page part, not an API. */ +const PAGE_PARTS = new Set(["Example", "Examples", "Props", "Usage", "Source"]); +/** Prose this long that another name already printed is left out of a multi-name lookup. */ +const LONG_PROSE = 100; +/** Sections a multi-name lookup leaves out: the signatures and props already say what they say. */ +const DETAIL_SECTIONS = /^(Example|Examples|Parameters|Returns|Usage|Source)\b/; + +/** The exported docs carry each heading's anchor link (`## Props[​](#props "Direct link to Props")`). */ +function cleanLine(line: string): string { + return line.replace(/\[\u200b\]\(#[^\s)]*(?: "[^"]*")?\)/g, "").trimEnd(); +} + +function readLines(file: string): string[] { + return fs.readFileSync(file, "utf-8").split("\n").map(cleanLine); +} + +function markdownFiles(dir: string): string[] { + if (!fs.existsSync(dir)) return []; + return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { + const file = path.join(dir, entry.name); + if (entry.isDirectory()) return markdownFiles(file); + return entry.name.endsWith(".md") ? [file] : []; + }); +} + +/** + * Every documented name: component pages and their parts (`docs/api/appkit-ui//.md`, `## SelectItem`), + * reference pages (`docs/api/appkit/..md`), and hooks documented in guides (`### useAnalyticsQuery`). + */ +export function apiIndex(packageRoot: string): Map { + const docsDir = path.join(packageRoot, "docs"); + const index = new Map(); + const add = (name: string, entry: ApiEntry) => { + if (!index.has(name)) index.set(name, entry); + }; + for (const file of markdownFiles(docsDir)) { + const rel = path.relative(docsDir, file).split(path.sep).join("/"); + const reference = rel.match(/^api\/appkit\/[A-Za-z]+\.(\w+)\.md$/); + if (reference) { + add(reference[1], { file, line: 0, level: 1 }); + continue; + } + const componentPage = rel.startsWith("api/appkit-ui/"); + readLines(file).forEach((line, i) => { + const heading = line.match(/^(#{1,4}) `?([A-Za-z]\w*)`?$/); + if (!heading || PAGE_PARTS.has(heading[2])) return; + if (componentPage || /^use[A-Z]/.test(heading[2])) { + add(heading[2], { file, line: i, level: heading[1].length }); + } + }); + } + return index; +} + +const unescapeCell = (cell: string) => + cell + .replace(/\\([\\`*_{}[\]()#+\-.!<>|])/g, "$1") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/{/g, "{") + .replace(/}/g, "}") + .replace(/`/g, ""); + +function tableCells(row: string): string[] { + return row + .replace(/^\|\s*|\s*\|$/g, "") + .split(/\s*(? + text.replace(/^(.+?\.)\s+[A-Z`(].*$/, "$1"); + +/** + * A doc section as an agent reads it: prose and signatures, one line per prop, no table chrome. A multi-name + * lookup (`details` off) also drops examples and prints a prop that an earlier name already showed only by name. + */ +function condense( + lines: string[], + details: boolean, + printed: Map, + owner: string, +): string { + const out: string[] = []; + const repeated = new Map(); + let inCode = false; + let skipLevel = 0; + let propsTable = false; + for (const [i, line] of lines.entries()) { + const heading = !inCode && line.match(/^(#+) (.*)$/); + if (heading) { + const level = heading[1].length; + if (skipLevel && level > skipLevel) continue; + skipLevel = + /^(Usage|Source)\b/.test(heading[2]) || + (!details && DETAIL_SECTIONS.test(heading[2])) + ? level + : 0; + if (!skipLevel && heading[2] !== "Props") out.push(line); + continue; + } + if (skipLevel) continue; + if (line.startsWith("```")) inCode = !inCode; + if (inCode || line.startsWith("```")) { + out.push(line); + continue; + } + if (/^