@galaxy-io/dls 1.2.7 → 1.3.1
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/README.md +2 -0
- package/dist/avatar/Avatar.d.ts +2 -1
- package/dist/avatar/Avatar.js +103 -14
- package/dist/buttons/Button.d.ts +6 -1
- package/dist/buttons/Button.js +8 -4
- package/dist/charts/BarChart.d.ts +30 -20
- package/dist/charts/BarChart.js +183 -253
- package/dist/charts/ChartAxis.d.ts +47 -22
- package/dist/charts/ChartAxis.js +81 -60
- package/dist/charts/ChartCategoryTargets.d.ts +27 -0
- package/dist/charts/ChartCategoryTargets.js +75 -0
- package/dist/charts/ChartEmptyState.d.ts +17 -0
- package/dist/charts/ChartEmptyState.js +29 -0
- package/dist/charts/ChartFrame.d.ts +110 -0
- package/dist/charts/ChartFrame.js +143 -0
- package/dist/charts/ChartLegend.d.ts +27 -4
- package/dist/charts/ChartLegend.js +46 -23
- package/dist/charts/ChartPrimitives.d.ts +230 -0
- package/dist/charts/ChartPrimitives.js +305 -0
- package/dist/charts/ChartTooltip.d.ts +25 -4
- package/dist/charts/ChartTooltip.js +55 -49
- package/dist/charts/LineChart.d.ts +42 -20
- package/dist/charts/LineChart.js +175 -241
- package/dist/charts/PieChart.d.ts +48 -32
- package/dist/charts/PieChart.js +180 -170
- package/dist/charts/barChartGeometry.d.ts +120 -0
- package/dist/charts/barChartGeometry.js +210 -0
- package/dist/charts/barChartLegend.d.ts +25 -0
- package/dist/charts/barChartLegend.js +23 -0
- package/dist/charts/chartFormat.d.ts +27 -0
- package/dist/charts/chartFormat.js +71 -0
- package/dist/charts/chartScales.d.ts +120 -0
- package/dist/charts/chartScales.js +165 -0
- package/dist/charts/chartTheme.d.ts +18 -0
- package/dist/charts/chartTheme.js +26 -0
- package/dist/charts/constants.d.ts +241 -18
- package/dist/charts/constants.js +261 -32
- package/dist/charts/lineChartGeometry.d.ts +92 -0
- package/dist/charts/lineChartGeometry.js +134 -0
- package/dist/charts/pieChartGeometry.d.ts +60 -0
- package/dist/charts/pieChartGeometry.js +79 -0
- package/dist/charts/types.d.ts +428 -54
- package/dist/charts/types.js +155 -0
- package/dist/charts/useCartesianChartLayout.d.ts +70 -0
- package/dist/charts/useCartesianChartLayout.js +56 -0
- package/dist/charts/useChartDimensions.d.ts +47 -0
- package/dist/charts/useChartDimensions.js +63 -0
- package/dist/charts/useChartFormatters.d.ts +19 -0
- package/dist/charts/useChartFormatters.js +20 -0
- package/dist/charts/useChartInteraction.d.ts +76 -0
- package/dist/charts/useChartInteraction.js +126 -0
- package/dist/charts/useChartTooltipPosition.d.ts +53 -0
- package/dist/charts/useChartTooltipPosition.js +39 -0
- package/dist/charts/useSeriesColorResolver.d.ts +37 -0
- package/dist/charts/useSeriesColorResolver.js +27 -0
- package/dist/hooks/useElementClientSize.d.ts +20 -0
- package/dist/hooks/useElementClientSize.js +43 -0
- package/dist/inputs/CheckboxInput.d.ts +7 -2
- package/dist/inputs/CheckboxInput.js +30 -14
- package/dist/inputs/Input.d.ts +1 -1
- package/dist/inputs/Input.js +6 -2
- package/dist/inputs/MultiSelectInput.js +1 -1
- package/dist/inputs/RadioInput.js +7 -2
- package/dist/styles.css +69 -74
- package/dist/table/InfiniteSpreadsheet.d.ts +6 -0
- package/dist/table/InfiniteSpreadsheet.js +235 -0
- package/dist/table/InfiniteTable.d.ts +7 -88
- package/dist/table/InfiniteTable.js +366 -577
- package/dist/{spreadsheet → table}/SpreadsheetCell.d.ts +6 -4
- package/dist/table/SpreadsheetCell.js +71 -0
- package/dist/{spreadsheet → table}/SpreadsheetCellEditor.js +27 -21
- package/dist/table/SpreadsheetHeaderCell.d.ts +23 -0
- package/dist/table/SpreadsheetHeaderCell.js +91 -0
- package/dist/table/SpreadsheetMenuItem.d.ts +14 -0
- package/dist/table/SpreadsheetMenuItem.js +33 -0
- package/dist/table/SpreadsheetPrimitives.d.ts +172 -0
- package/dist/table/SpreadsheetPrimitives.js +105 -0
- package/dist/table/SpreadsheetRow.d.ts +33 -0
- package/dist/table/SpreadsheetRow.js +73 -0
- package/dist/{spreadsheet → table}/SpreadsheetRowActionCell.d.ts +5 -7
- package/dist/table/SpreadsheetRowActionCell.js +51 -0
- package/dist/table/TableExpandCell.d.ts +11 -0
- package/dist/table/TableExpandCell.js +24 -0
- package/dist/table/TableExpandedRow.d.ts +16 -0
- package/dist/table/TableExpandedRow.js +77 -0
- package/dist/table/TableHeaderCellContent.d.ts +30 -0
- package/dist/table/TableHeaderCellContent.js +48 -0
- package/dist/table/TablePrimitives.d.ts +307 -0
- package/dist/table/TablePrimitives.js +298 -0
- package/dist/table/TableSelectCell.d.ts +18 -0
- package/dist/table/TableSelectCell.js +26 -0
- package/dist/table/TableStatusRow.d.ts +18 -0
- package/dist/table/TableStatusRow.js +50 -0
- package/dist/table/VirtualizedInfiniteTable.d.ts +11 -27
- package/dist/table/VirtualizedInfiniteTable.js +182 -317
- package/dist/table/types.d.ts +249 -0
- package/dist/table/types.js +51 -0
- package/dist/table/useInfiniteScrollSentinel.d.ts +24 -0
- package/dist/table/useInfiniteScrollSentinel.js +53 -0
- package/dist/{spreadsheet/hooks → table}/useSpreadsheetEditing.d.ts +1 -1
- package/dist/{spreadsheet/hooks → table}/useSpreadsheetEditing.js +1 -1
- package/dist/table/useTableColumnLayout.d.ts +28 -0
- package/dist/table/useTableColumnLayout.js +63 -0
- package/dist/table/useTableColumnResize.d.ts +38 -0
- package/dist/table/useTableColumnResize.js +155 -0
- package/dist/table/useTableKeyboardNavigation.d.ts +25 -0
- package/dist/table/useTableKeyboardNavigation.js +83 -0
- package/dist/table/useTableRowExpansion.d.ts +24 -0
- package/dist/table/useTableRowExpansion.js +62 -0
- package/dist/table/useTableRowSelection.d.ts +27 -0
- package/dist/table/useTableRowSelection.js +94 -0
- package/dist/table/utils.d.ts +50 -0
- package/dist/table/utils.js +78 -0
- package/dist/text/MarkdownText.js +45 -27
- package/dist/theme/variants/dark.js +1 -1
- package/dist/widget/Widget.d.ts +2 -0
- package/dist/widget/Widget.js +14 -7
- package/package.json +1 -5
- package/dist/assets/components/enrichment/PerplexityIcon.d.ts +0 -3
- package/dist/assets/components/enrichment/PerplexityIcon.js +0 -35
- package/dist/assets/components/enrichment/TavilyIcon.d.ts +0 -3
- package/dist/assets/components/enrichment/TavilyIcon.js +0 -15
- package/dist/assets/components/onboarding/TenantSetupDark.d.ts +0 -3
- package/dist/assets/components/onboarding/TenantSetupDark.js +0 -498
- package/dist/assets/components/onboarding/TenantSetupLight.d.ts +0 -3
- package/dist/assets/components/onboarding/TenantSetupLight.js +0 -482
- package/dist/assets/components/onboarding/UserSetupDark.d.ts +0 -3
- package/dist/assets/components/onboarding/UserSetupDark.js +0 -1086
- package/dist/assets/components/onboarding/UserSetupLight.d.ts +0 -3
- package/dist/assets/components/onboarding/UserSetupLight.js +0 -1024
- package/dist/assets/components/onboarding/WorkspaceSetupBuildDark.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupBuildDark.js +0 -466
- package/dist/assets/components/onboarding/WorkspaceSetupBuildLight.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupBuildLight.js +0 -460
- package/dist/assets/components/onboarding/WorkspaceSetupConnectDark.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupConnectDark.js +0 -336
- package/dist/assets/components/onboarding/WorkspaceSetupConnectLight.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupConnectLight.js +0 -336
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateDark.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateDark.js +0 -153
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateLight.d.ts +0 -3
- package/dist/assets/components/onboarding/WorkspaceSetupIntegrateLight.js +0 -153
- package/dist/assets/components/projects/MappingMethodAutoIntrospectDark.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodAutoIntrospectDark.js +0 -117
- package/dist/assets/components/projects/MappingMethodAutoIntrospectLight.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodAutoIntrospectLight.js +0 -117
- package/dist/assets/components/projects/MappingMethodBlankDark.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankDark.js +0 -150
- package/dist/assets/components/projects/MappingMethodBlankDarkHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankDarkHovered.js +0 -150
- package/dist/assets/components/projects/MappingMethodBlankLight.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankLight.js +0 -150
- package/dist/assets/components/projects/MappingMethodBlankLightHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodBlankLightHovered.js +0 -150
- package/dist/assets/components/projects/MappingMethodJsonDark.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonDark.js +0 -90
- package/dist/assets/components/projects/MappingMethodJsonDarkHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonDarkHovered.js +0 -90
- package/dist/assets/components/projects/MappingMethodJsonLight.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonLight.js +0 -90
- package/dist/assets/components/projects/MappingMethodJsonLightHovered.d.ts +0 -3
- package/dist/assets/components/projects/MappingMethodJsonLightHovered.js +0 -90
- package/dist/assets/components/projects/ProjectsEmptyStateDark.d.ts +0 -3
- package/dist/assets/components/projects/ProjectsEmptyStateDark.js +0 -454
- package/dist/assets/components/projects/ProjectsEmptyStateLight.d.ts +0 -3
- package/dist/assets/components/projects/ProjectsEmptyStateLight.js +0 -456
- package/dist/assets/components/root/CreateProjectActionCardDark.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardDark.js +0 -1796
- package/dist/assets/components/root/CreateProjectActionCardDarkHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardDarkHovered.js +0 -1796
- package/dist/assets/components/root/CreateProjectActionCardLight.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardLight.js +0 -1786
- package/dist/assets/components/root/CreateProjectActionCardLightHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateProjectActionCardLightHovered.js +0 -1786
- package/dist/assets/components/root/CreateSourceActionCardDark.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardDark.js +0 -879
- package/dist/assets/components/root/CreateSourceActionCardDarkHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardDarkHovered.js +0 -879
- package/dist/assets/components/root/CreateSourceActionCardLight.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardLight.js +0 -889
- package/dist/assets/components/root/CreateSourceActionCardLightHovered.d.ts +0 -3
- package/dist/assets/components/root/CreateSourceActionCardLightHovered.js +0 -889
- package/dist/assets/components/sources/AttioIcon.d.ts +0 -3
- package/dist/assets/components/sources/AttioIcon.js +0 -11
- package/dist/assets/components/sources/BigquerySourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/BigquerySourceIcon.js +0 -39
- package/dist/assets/components/sources/BrowserbaseSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/BrowserbaseSourceIcon.js +0 -35
- package/dist/assets/components/sources/ClickhouseLogoSourceIconDark.d.ts +0 -3
- package/dist/assets/components/sources/ClickhouseLogoSourceIconDark.js +0 -13
- package/dist/assets/components/sources/ClickhouseLogoSourceIconLight.d.ts +0 -3
- package/dist/assets/components/sources/ClickhouseLogoSourceIconLight.js +0 -13
- package/dist/assets/components/sources/ConfluenceSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/ConfluenceSourceIcon.js +0 -30
- package/dist/assets/components/sources/GithubSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/GithubSourceIcon.js +0 -27
- package/dist/assets/components/sources/GoogleDriveIcon.d.ts +0 -3
- package/dist/assets/components/sources/GoogleDriveIcon.js +0 -45
- package/dist/assets/components/sources/HubspotSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/HubspotSourceIcon.js +0 -14
- package/dist/assets/components/sources/JiraSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/JiraSourceIcon.js +0 -54
- package/dist/assets/components/sources/LinearSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/LinearSourceIcon.js +0 -14
- package/dist/assets/components/sources/MysqlLogoSourceIconDark.d.ts +0 -3
- package/dist/assets/components/sources/MysqlLogoSourceIconDark.js +0 -17
- package/dist/assets/components/sources/NetsuiteSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/NetsuiteSourceIcon.js +0 -32
- package/dist/assets/components/sources/NotionIcon.d.ts +0 -3
- package/dist/assets/components/sources/NotionIcon.js +0 -20
- package/dist/assets/components/sources/PostgresqlIcon.d.ts +0 -3
- package/dist/assets/components/sources/PostgresqlIcon.js +0 -61
- package/dist/assets/components/sources/S3Icon.d.ts +0 -3
- package/dist/assets/components/sources/S3Icon.js +0 -76
- package/dist/assets/components/sources/SalesforceSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/SalesforceSourceIcon.js +0 -23
- package/dist/assets/components/sources/SlackIcon.d.ts +0 -3
- package/dist/assets/components/sources/SlackIcon.js +0 -32
- package/dist/assets/components/sources/SnowflakeLogoSourceIconDark.d.ts +0 -3
- package/dist/assets/components/sources/SnowflakeLogoSourceIconDark.js +0 -14
- package/dist/assets/components/sources/SnowflakeLogoSourceIconLight.d.ts +0 -3
- package/dist/assets/components/sources/SnowflakeLogoSourceIconLight.js +0 -14
- package/dist/assets/components/sources/WikipediaSourceIcon.d.ts +0 -3
- package/dist/assets/components/sources/WikipediaSourceIcon.js +0 -1490
- package/dist/avatar/AvatarEmpty.d.ts +0 -7
- package/dist/avatar/AvatarEmpty.js +0 -99
- package/dist/avatar/types.d.ts +0 -5
- package/dist/avatar/types.js +0 -9
- package/dist/charts/utils.d.ts +0 -29
- package/dist/charts/utils.js +0 -62
- package/dist/icons/BackIcon.d.ts +0 -3
- package/dist/icons/BackIcon.js +0 -13
- package/dist/icons/CloseIcon.d.ts +0 -3
- package/dist/icons/CloseIcon.js +0 -13
- package/dist/icons/CreateIcon.d.ts +0 -3
- package/dist/icons/CreateIcon.js +0 -13
- package/dist/icons/ForwardIcon.d.ts +0 -3
- package/dist/icons/ForwardIcon.js +0 -13
- package/dist/icons/HelpIcon.d.ts +0 -3
- package/dist/icons/HelpIcon.js +0 -14
- package/dist/icons/ProjectsIcon.d.ts +0 -3
- package/dist/icons/ProjectsIcon.js +0 -12
- package/dist/icons/SearchIcon.d.ts +0 -3
- package/dist/icons/SearchIcon.js +0 -12
- package/dist/icons/SourcesIcon.d.ts +0 -3
- package/dist/icons/SourcesIcon.js +0 -12
- package/dist/icons/TextIcon.d.ts +0 -4
- package/dist/icons/TextIcon.js +0 -22
- package/dist/icons/WebScrapeIcon.d.ts +0 -4
- package/dist/icons/WebScrapeIcon.js +0 -22
- package/dist/icons/WebhookIcon.d.ts +0 -4
- package/dist/icons/WebhookIcon.js +0 -22
- package/dist/icons/sources/AttioLogomark.d.ts +0 -4
- package/dist/icons/sources/AttioLogomark.js +0 -8
- package/dist/icons/sources/BrowserbaseLogomark.d.ts +0 -4
- package/dist/icons/sources/BrowserbaseLogomark.js +0 -8
- package/dist/icons/sources/ClickhouseLogomark.d.ts +0 -4
- package/dist/icons/sources/ClickhouseLogomark.js +0 -16
- package/dist/icons/sources/ConfluenceLogomark.d.ts +0 -4
- package/dist/icons/sources/ConfluenceLogomark.js +0 -8
- package/dist/icons/sources/GithubLogomark.d.ts +0 -4
- package/dist/icons/sources/GithubLogomark.js +0 -8
- package/dist/icons/sources/GoogleBigqueryLogomark.d.ts +0 -4
- package/dist/icons/sources/GoogleBigqueryLogomark.js +0 -8
- package/dist/icons/sources/GoogleDriveLogomark.d.ts +0 -4
- package/dist/icons/sources/GoogleDriveLogomark.js +0 -8
- package/dist/icons/sources/HubspotLogomark.d.ts +0 -4
- package/dist/icons/sources/HubspotLogomark.js +0 -8
- package/dist/icons/sources/JiraLogomark.d.ts +0 -4
- package/dist/icons/sources/JiraLogomark.js +0 -8
- package/dist/icons/sources/LinearLogomark.d.ts +0 -4
- package/dist/icons/sources/LinearLogomark.js +0 -8
- package/dist/icons/sources/MySQLLogomark.d.ts +0 -4
- package/dist/icons/sources/MySQLLogomark.js +0 -8
- package/dist/icons/sources/NetsuiteLogomark.d.ts +0 -4
- package/dist/icons/sources/NetsuiteLogomark.js +0 -8
- package/dist/icons/sources/NotionLogomark.d.ts +0 -4
- package/dist/icons/sources/NotionLogomark.js +0 -8
- package/dist/icons/sources/PostgresLogomark.d.ts +0 -4
- package/dist/icons/sources/PostgresLogomark.js +0 -8
- package/dist/icons/sources/S3Logomark.d.ts +0 -4
- package/dist/icons/sources/S3Logomark.js +0 -8
- package/dist/icons/sources/SalesforceLogomark.d.ts +0 -4
- package/dist/icons/sources/SalesforceLogomark.js +0 -8
- package/dist/icons/sources/SlackLogoIconmark.d.ts +0 -4
- package/dist/icons/sources/SlackLogoIconmark.js +0 -8
- package/dist/icons/sources/SnowflakeLogomark.d.ts +0 -4
- package/dist/icons/sources/SnowflakeLogomark.js +0 -16
- package/dist/icons/sources/WikipediaLogomark.d.ts +0 -4
- package/dist/icons/sources/WikipediaLogomark.js +0 -8
- package/dist/spreadsheet/InfiniteSpreadsheet.d.ts +0 -3
- package/dist/spreadsheet/InfiniteSpreadsheet.js +0 -265
- package/dist/spreadsheet/SpreadsheetAddColumnButton.d.ts +0 -6
- package/dist/spreadsheet/SpreadsheetAddColumnButton.js +0 -32
- package/dist/spreadsheet/SpreadsheetCell.js +0 -115
- package/dist/spreadsheet/SpreadsheetHeaderCell.d.ts +0 -18
- package/dist/spreadsheet/SpreadsheetHeaderCell.js +0 -141
- package/dist/spreadsheet/SpreadsheetRow.d.ts +0 -21
- package/dist/spreadsheet/SpreadsheetRow.js +0 -68
- package/dist/spreadsheet/SpreadsheetRowActionCell.js +0 -78
- package/dist/spreadsheet/hooks/useColumnResize.d.ts +0 -6
- package/dist/spreadsheet/hooks/useColumnResize.js +0 -46
- package/dist/spreadsheet/types.d.ts +0 -92
- package/dist/spreadsheet/types.js +0 -21
- /package/dist/{spreadsheet → table}/SpreadsheetCellEditor.d.ts +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ChartLabelFormatter, ChartMargin, ChartValueDomain, ChartValueFormatter, ChartValueUnit } from "./types";
|
|
2
|
+
import type { ChartDimensions } from "./useChartDimensions";
|
|
3
|
+
/**
|
|
4
|
+
* Everything a cartesian chart resolves *before* it can be measured.
|
|
5
|
+
*
|
|
6
|
+
* There is a hard ordering inside bar and line alike:
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* domain → ticks → left margin → dimensions → plot size → geometry
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The gutter has to fit the tick labels, the ticks come from the domain, and
|
|
13
|
+
* the domain comes from the data — none of which needs the plot. Everything
|
|
14
|
+
* after `geometry` does need it, which is why this hook stops there rather than
|
|
15
|
+
* trying to own the whole chart: the geometry builders are generic over the
|
|
16
|
+
* chart's own key types, and threading those through here would buy nothing.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately **not generic**. `getBarValueDomain` and `getLineValueDomain`
|
|
19
|
+
* have already erased the key types by the time they return an extent, so
|
|
20
|
+
* nothing in this phase needs them.
|
|
21
|
+
*/
|
|
22
|
+
interface UseCartesianChartLayoutOptions {
|
|
23
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
24
|
+
/**
|
|
25
|
+
* The data's own extent, before any override or nicing.
|
|
26
|
+
*
|
|
27
|
+
* Free to be a fresh array each render — the memo below keys on the two
|
|
28
|
+
* numbers, not the array's identity.
|
|
29
|
+
*/
|
|
30
|
+
rawDomain: [number, number];
|
|
31
|
+
valueDomain?: Partial<ChartValueDomain>;
|
|
32
|
+
width?: number;
|
|
33
|
+
height?: number;
|
|
34
|
+
fillWidth?: boolean;
|
|
35
|
+
fillHeight?: boolean;
|
|
36
|
+
aspectRatio?: number;
|
|
37
|
+
margin?: Partial<ChartMargin>;
|
|
38
|
+
valueUnit?: ChartValueUnit;
|
|
39
|
+
valueFormatter?: ChartValueFormatter;
|
|
40
|
+
labelFormatter?: ChartLabelFormatter;
|
|
41
|
+
/**
|
|
42
|
+
* Rewrites the resolved value formatter for the axis alone.
|
|
43
|
+
*
|
|
44
|
+
* Takes the resolved formatter rather than replacing it, because the only
|
|
45
|
+
* caller — a percent-normalized bar chart — falls back to it whenever the
|
|
46
|
+
* consumer asked for something specific. Applies to the tick labels *and* the
|
|
47
|
+
* gutter estimate, which is the point: sizing the gutter with a different
|
|
48
|
+
* formatter than the one that renders into it is how a gutter ends up too
|
|
49
|
+
* narrow for its own labels.
|
|
50
|
+
*
|
|
51
|
+
* Must be stable; memoize it at the call site.
|
|
52
|
+
*/
|
|
53
|
+
deriveAxisFormatter?: (formatValue: ChartValueFormatter) => ChartValueFormatter;
|
|
54
|
+
valueAxisTitle?: string;
|
|
55
|
+
categoryAxisTitle?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface CartesianChartLayout {
|
|
58
|
+
dimensions: ChartDimensions;
|
|
59
|
+
/** Override applied, zero included, degenerate widened, `nice()` applied. */
|
|
60
|
+
domain: [number, number];
|
|
61
|
+
valueTicks: number[];
|
|
62
|
+
/** Tooltip rows and value labels. */
|
|
63
|
+
formatValue: ChartValueFormatter;
|
|
64
|
+
/** Category names — the axis and the tooltip heading. */
|
|
65
|
+
formatLabel: ChartLabelFormatter;
|
|
66
|
+
/** Axis ticks. Identical to `formatValue` unless `deriveAxisFormatter` said otherwise. */
|
|
67
|
+
formatAxisValue: ChartValueFormatter;
|
|
68
|
+
}
|
|
69
|
+
export declare function useCartesianChartLayout({ containerRef, rawDomain, valueDomain, width, height, fillWidth, fillHeight, aspectRatio, margin, valueUnit, valueFormatter, labelFormatter, deriveAxisFormatter, valueAxisTitle, categoryAxisTitle, }: UseCartesianChartLayoutOptions): CartesianChartLayout;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { addAxisTitleSpace, estimateValueAxisMargin, getValueTicks, resolveValueDomain } from "./chartScales.js";
|
|
2
|
+
import { useChartFormatters } from "./useChartFormatters.js";
|
|
3
|
+
import { useChartDimensions } from "./useChartDimensions.js";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
|
+
//#region src/charts/useCartesianChartLayout.ts
|
|
6
|
+
function useCartesianChartLayout({ containerRef, rawDomain, valueDomain, width, height, fillWidth, fillHeight, aspectRatio, margin, valueUnit, valueFormatter, labelFormatter, deriveAxisFormatter, valueAxisTitle, categoryAxisTitle }) {
|
|
7
|
+
const { formatValue, formatLabel } = useChartFormatters({
|
|
8
|
+
valueFormatter,
|
|
9
|
+
valueUnit,
|
|
10
|
+
labelFormatter
|
|
11
|
+
});
|
|
12
|
+
const formatAxisValue = useMemo(() => deriveAxisFormatter?.(formatValue) ?? formatValue, [deriveAxisFormatter, formatValue]);
|
|
13
|
+
const [rawMin, rawMax] = rawDomain;
|
|
14
|
+
const domain = useMemo(() => resolveValueDomain([rawMin, rawMax], valueDomain), [
|
|
15
|
+
rawMin,
|
|
16
|
+
rawMax,
|
|
17
|
+
valueDomain
|
|
18
|
+
]);
|
|
19
|
+
const valueTicks = useMemo(() => getValueTicks(domain, valueDomain), [domain, valueDomain]);
|
|
20
|
+
const dimensions = useChartDimensions({
|
|
21
|
+
containerRef,
|
|
22
|
+
width,
|
|
23
|
+
height,
|
|
24
|
+
fillWidth,
|
|
25
|
+
fillHeight,
|
|
26
|
+
aspectRatio,
|
|
27
|
+
margin: addAxisTitleSpace(useMemo(() => ({
|
|
28
|
+
...margin,
|
|
29
|
+
left: margin?.left ?? estimateValueAxisMargin(valueTicks, formatAxisValue)
|
|
30
|
+
}), [
|
|
31
|
+
margin,
|
|
32
|
+
valueTicks,
|
|
33
|
+
formatAxisValue
|
|
34
|
+
]), {
|
|
35
|
+
hasValueTitle: Boolean(valueAxisTitle),
|
|
36
|
+
hasCategoryTitle: Boolean(categoryAxisTitle)
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
return useMemo(() => ({
|
|
40
|
+
dimensions,
|
|
41
|
+
domain,
|
|
42
|
+
valueTicks,
|
|
43
|
+
formatValue,
|
|
44
|
+
formatLabel,
|
|
45
|
+
formatAxisValue
|
|
46
|
+
}), [
|
|
47
|
+
dimensions,
|
|
48
|
+
domain,
|
|
49
|
+
valueTicks,
|
|
50
|
+
formatValue,
|
|
51
|
+
formatLabel,
|
|
52
|
+
formatAxisValue
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { useCartesianChartLayout };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ChartMargin } from "./types";
|
|
2
|
+
interface UseChartDimensionsOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The element to measure.
|
|
5
|
+
*
|
|
6
|
+
* Owned by the caller rather than returned from here: a hook that hands back
|
|
7
|
+
* a ref inside its result object reads as a ref access during render, both to
|
|
8
|
+
* the `react-hooks/refs` lint rule and to anyone reviewing the call site.
|
|
9
|
+
*/
|
|
10
|
+
containerRef: React.RefObject<HTMLElement | null>;
|
|
11
|
+
width?: number;
|
|
12
|
+
height?: number;
|
|
13
|
+
fillWidth?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Take the height from the measured box rather than a prop.
|
|
16
|
+
*
|
|
17
|
+
* Requires an ancestor with a definite height — see {@link ChartSize}. The
|
|
18
|
+
* measured element is the *plot box*, not the chart root, so the legend is
|
|
19
|
+
* already excluded by flexbox and nothing here has to subtract it.
|
|
20
|
+
*/
|
|
21
|
+
fillHeight?: boolean;
|
|
22
|
+
aspectRatio?: number;
|
|
23
|
+
margin?: Partial<ChartMargin>;
|
|
24
|
+
/**
|
|
25
|
+
* Fallback for whichever fields `margin` leaves out.
|
|
26
|
+
*
|
|
27
|
+
* Radial charts pass their own, since the cartesian default reserves gutters
|
|
28
|
+
* for axes they do not draw. Merged per field, so a caller's partial margin
|
|
29
|
+
* lands on top of *this* rather than reverting the chart to the cartesian
|
|
30
|
+
* defaults.
|
|
31
|
+
*/
|
|
32
|
+
defaultMargin?: ChartMargin;
|
|
33
|
+
}
|
|
34
|
+
export interface ChartDimensions {
|
|
35
|
+
width: number;
|
|
36
|
+
height: number;
|
|
37
|
+
plotWidth: number;
|
|
38
|
+
plotHeight: number;
|
|
39
|
+
margin: ChartMargin;
|
|
40
|
+
/** False until the box has usable dimensions; guard mark rendering on it. */
|
|
41
|
+
isMeasured: boolean;
|
|
42
|
+
/** Handed to the plot box so it reserves space before measurement lands. */
|
|
43
|
+
reservedHeight?: number;
|
|
44
|
+
reservedAspectRatio?: number;
|
|
45
|
+
}
|
|
46
|
+
export declare function useChartDimensions({ containerRef, width, height, fillWidth, fillHeight, aspectRatio, margin: marginOverride, defaultMargin, }: UseChartDimensionsOptions): ChartDimensions;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useElementClientSize } from "../hooks/useElementClientSize.js";
|
|
2
|
+
import { DEFAULT_CHART_MARGIN } from "./constants.js";
|
|
3
|
+
import { getPlotDimensions, resolveMargin } from "./chartScales.js";
|
|
4
|
+
import { useEffect, useMemo } from "react";
|
|
5
|
+
//#region src/charts/useChartDimensions.ts
|
|
6
|
+
function useChartDimensions({ containerRef, width, height, fillWidth = false, fillHeight = false, aspectRatio, margin: marginOverride, defaultMargin }) {
|
|
7
|
+
const { width: measuredWidth, height: measuredHeight } = useElementClientSize(containerRef);
|
|
8
|
+
const resolvedWidth = fillWidth ? measuredWidth ?? 0 : width ?? 0;
|
|
9
|
+
const resolvedHeight = fillHeight ? measuredHeight ?? 0 : aspectRatio ? resolvedWidth / aspectRatio : height ?? 0;
|
|
10
|
+
const { top: marginTop, right: marginRight, bottom: marginBottom, left: marginLeft } = marginOverride ?? {};
|
|
11
|
+
const { top: defaultTop, right: defaultRight, bottom: defaultBottom, left: defaultLeft } = defaultMargin ?? DEFAULT_CHART_MARGIN;
|
|
12
|
+
const margin = useMemo(() => resolveMargin({
|
|
13
|
+
top: marginTop,
|
|
14
|
+
right: marginRight,
|
|
15
|
+
bottom: marginBottom,
|
|
16
|
+
left: marginLeft
|
|
17
|
+
}, {
|
|
18
|
+
top: defaultTop,
|
|
19
|
+
right: defaultRight,
|
|
20
|
+
bottom: defaultBottom,
|
|
21
|
+
left: defaultLeft
|
|
22
|
+
}), [
|
|
23
|
+
marginTop,
|
|
24
|
+
marginRight,
|
|
25
|
+
marginBottom,
|
|
26
|
+
marginLeft,
|
|
27
|
+
defaultTop,
|
|
28
|
+
defaultRight,
|
|
29
|
+
defaultBottom,
|
|
30
|
+
defaultLeft
|
|
31
|
+
]);
|
|
32
|
+
const { plotWidth, plotHeight } = useMemo(() => getPlotDimensions(resolvedWidth, resolvedHeight, margin), [
|
|
33
|
+
resolvedWidth,
|
|
34
|
+
resolvedHeight,
|
|
35
|
+
margin
|
|
36
|
+
]);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
|
|
39
|
+
if (!fillHeight || measuredHeight === void 0 || measuredHeight > 0) return;
|
|
40
|
+
console.warn("[@galaxy-io/dls] A chart with `fillHeight` measured 0px tall and will not render. `fillHeight` takes its height from the container, so an ancestor needs a definite height — an explicit height, a flex or grid track, or absolute positioning. Use `height` or `aspectRatio` instead if the container is sized by its content.");
|
|
41
|
+
}, [fillHeight, measuredHeight]);
|
|
42
|
+
return useMemo(() => ({
|
|
43
|
+
width: resolvedWidth,
|
|
44
|
+
height: resolvedHeight,
|
|
45
|
+
plotWidth,
|
|
46
|
+
plotHeight,
|
|
47
|
+
margin,
|
|
48
|
+
isMeasured: resolvedWidth > 0 && resolvedHeight > 0,
|
|
49
|
+
reservedHeight: fillHeight || aspectRatio ? void 0 : height,
|
|
50
|
+
reservedAspectRatio: fillHeight ? void 0 : aspectRatio
|
|
51
|
+
}), [
|
|
52
|
+
resolvedWidth,
|
|
53
|
+
resolvedHeight,
|
|
54
|
+
plotWidth,
|
|
55
|
+
plotHeight,
|
|
56
|
+
margin,
|
|
57
|
+
aspectRatio,
|
|
58
|
+
height,
|
|
59
|
+
fillHeight
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { useChartDimensions };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ChartLabelFormatter, ChartValueFormatter, ChartValueUnit } from "./types";
|
|
2
|
+
interface UseChartFormattersOptions {
|
|
3
|
+
valueFormatter?: ChartValueFormatter;
|
|
4
|
+
valueUnit?: ChartValueUnit;
|
|
5
|
+
labelFormatter?: ChartLabelFormatter;
|
|
6
|
+
}
|
|
7
|
+
export interface ChartFormatters {
|
|
8
|
+
formatValue: ChartValueFormatter;
|
|
9
|
+
formatLabel: ChartLabelFormatter;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolves the value and label formatters once per chart.
|
|
13
|
+
*
|
|
14
|
+
* Doing this centrally is what keeps axis ticks, value labels and tooltip rows
|
|
15
|
+
* from drifting apart — the recurring failure when each call site formats for
|
|
16
|
+
* itself.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useChartFormatters({ valueFormatter, valueUnit, labelFormatter, }: UseChartFormattersOptions): ChartFormatters;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { resolveLabelFormatter, resolveValueFormatter } from "./chartFormat.js";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
//#region src/charts/useChartFormatters.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the value and label formatters once per chart.
|
|
6
|
+
*
|
|
7
|
+
* Doing this centrally is what keeps axis ticks, value labels and tooltip rows
|
|
8
|
+
* from drifting apart — the recurring failure when each call site formats for
|
|
9
|
+
* itself.
|
|
10
|
+
*/
|
|
11
|
+
function useChartFormatters({ valueFormatter, valueUnit, labelFormatter }) {
|
|
12
|
+
const formatValue = useMemo(() => resolveValueFormatter(valueFormatter, valueUnit), [valueFormatter, valueUnit]);
|
|
13
|
+
const formatLabel = useMemo(() => resolveLabelFormatter(labelFormatter), [labelFormatter]);
|
|
14
|
+
return useMemo(() => ({
|
|
15
|
+
formatValue,
|
|
16
|
+
formatLabel
|
|
17
|
+
}), [formatValue, formatLabel]);
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { useChartFormatters };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ChartMarkState } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Hover and pin interaction shared by every chart.
|
|
4
|
+
*
|
|
5
|
+
* Two independent axes:
|
|
6
|
+
*
|
|
7
|
+
* - **Category** — a numeric index along the plot. Hovering previews, clicking
|
|
8
|
+
* pins so the tooltip survives the pointer leaving.
|
|
9
|
+
* - **Series** — a legend key. Hovering isolates that series, clicking pins the
|
|
10
|
+
* isolation.
|
|
11
|
+
*
|
|
12
|
+
* Both live here rather than one of them in the charts, so there is a single
|
|
13
|
+
* `isEngaged` boolean. That matters more than it looks: `ChartPlotGroup` uses it
|
|
14
|
+
* to cancel the mark restore delay, and a second hover source that didn't feed
|
|
15
|
+
* it would sit through that delay before muting anything and feel broken.
|
|
16
|
+
*
|
|
17
|
+
* Escape or a click on the plot background clears both pins.
|
|
18
|
+
*/
|
|
19
|
+
interface UseChartInteractionOptions {
|
|
20
|
+
/** Number of hoverable categories. A shrinking count clears stale indices. */
|
|
21
|
+
categoryCount: number;
|
|
22
|
+
/** Legend keys currently rendered. A key that disappears clears a stale pin. */
|
|
23
|
+
seriesKeys?: string[];
|
|
24
|
+
/** Suppress all interaction — used while loading and when the tooltip is off. */
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Render every mark muted, whatever the two axes say.
|
|
28
|
+
*
|
|
29
|
+
* Distinct from {@link disabled}, which suppresses *input*. Loading suppresses
|
|
30
|
+
* *emphasis*: there is nothing yet worth drawing attention to. Folded in here
|
|
31
|
+
* rather than left to each mark, because the alternative is the same
|
|
32
|
+
* `isLoading ? MUTED : getMarkState(…)` ternary hand-copied at every mark —
|
|
33
|
+
* which is exactly how one of them came to be missing it.
|
|
34
|
+
*/
|
|
35
|
+
isLoading?: boolean;
|
|
36
|
+
/** Notified when the pinned category changes. */
|
|
37
|
+
onPinnedChange?: (index: number | null) => void;
|
|
38
|
+
}
|
|
39
|
+
interface MarkStateArgs {
|
|
40
|
+
/** Omit for marks that belong to no particular category, such as a line. */
|
|
41
|
+
categoryIndex?: number;
|
|
42
|
+
/** Omit for marks that belong to no particular series. */
|
|
43
|
+
seriesKey?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ChartInteraction {
|
|
46
|
+
pinnedIndex: number | null;
|
|
47
|
+
/** Pinned wins over hovered — this is what the tooltip follows. */
|
|
48
|
+
activeIndex: number | null;
|
|
49
|
+
hoveredSeriesKey: string | null;
|
|
50
|
+
pinnedSeriesKey: string | null;
|
|
51
|
+
/** True while *either* axis is engaged; cancels the mark restore delay. */
|
|
52
|
+
isEngaged: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Emphasis for one mark, composed from both axes.
|
|
55
|
+
*
|
|
56
|
+
* The grammar is inherited from the reference and is the opposite of the
|
|
57
|
+
* obvious one: engaging something does not brighten it, it softens everything
|
|
58
|
+
* else. With something pinned, the unrelated marks recede further still, so
|
|
59
|
+
* the pinned mark and the one under the pointer stay legible against them.
|
|
60
|
+
*
|
|
61
|
+
* A mark has to survive *both* filters to stay active — the two axes
|
|
62
|
+
* intersect rather than override, so pinning a series and then hovering a
|
|
63
|
+
* category leaves only their overlap lit.
|
|
64
|
+
*/
|
|
65
|
+
getMarkState: (args: MarkStateArgs) => ChartMarkState;
|
|
66
|
+
onCategoryEnter: (categoryIndex: number) => void;
|
|
67
|
+
onCategoryLeave: () => void;
|
|
68
|
+
onCategoryClick: (categoryIndex: number) => void;
|
|
69
|
+
onSeriesEnter: (seriesKey: string) => void;
|
|
70
|
+
onSeriesLeave: () => void;
|
|
71
|
+
onSeriesClick: (seriesKey: string) => void;
|
|
72
|
+
/** Attach to the plot backdrop; clears both pins. */
|
|
73
|
+
onBackdropClick: () => void;
|
|
74
|
+
}
|
|
75
|
+
export declare function useChartInteraction({ categoryCount, seriesKeys, disabled, isLoading, onPinnedChange, }: UseChartInteractionOptions): ChartInteraction;
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ChartMarkState } from "./types.js";
|
|
2
|
+
import { match } from "ts-pattern";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
//#region src/charts/useChartInteraction.ts
|
|
5
|
+
/** How far back a state sits, so two axes can be compared and the worse taken. */
|
|
6
|
+
function severity(state) {
|
|
7
|
+
return match(state).with(ChartMarkState.ACTIVE, () => 0).with(ChartMarkState.MUTED, () => 1).with(ChartMarkState.FADED, () => 2).exhaustive();
|
|
8
|
+
}
|
|
9
|
+
function useChartInteraction({ categoryCount, seriesKeys, disabled = false, isLoading = false, onPinnedChange }) {
|
|
10
|
+
const [hoveredIndex, setHoveredIndex] = useState(null);
|
|
11
|
+
const [pinnedIndex, setPinnedIndex] = useState(null);
|
|
12
|
+
const [hoveredSeriesKey, setHoveredSeriesKey] = useState(null);
|
|
13
|
+
const [pinnedSeriesKey, setPinnedSeriesKey] = useState(null);
|
|
14
|
+
const onPinnedChangeRef = useRef(onPinnedChange);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
onPinnedChangeRef.current = onPinnedChange;
|
|
17
|
+
});
|
|
18
|
+
const safeHovered = hoveredIndex !== null && hoveredIndex < categoryCount ? hoveredIndex : null;
|
|
19
|
+
const safePinned = pinnedIndex !== null && pinnedIndex < categoryCount ? pinnedIndex : null;
|
|
20
|
+
const isKnownSeries = (key) => key !== null && (seriesKeys === void 0 || seriesKeys.includes(key));
|
|
21
|
+
const safeHoveredSeries = isKnownSeries(hoveredSeriesKey) ? hoveredSeriesKey : null;
|
|
22
|
+
const safePinnedSeries = isKnownSeries(pinnedSeriesKey) ? pinnedSeriesKey : null;
|
|
23
|
+
const clearPins = useCallback(() => {
|
|
24
|
+
setPinnedIndex(null);
|
|
25
|
+
setPinnedSeriesKey(null);
|
|
26
|
+
onPinnedChangeRef.current?.(null);
|
|
27
|
+
}, []);
|
|
28
|
+
const hasPin = safePinned !== null || safePinnedSeries !== null;
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (disabled || !hasPin) return;
|
|
31
|
+
const onKeyDown = (event) => {
|
|
32
|
+
if (event.key === "Escape") clearPins();
|
|
33
|
+
};
|
|
34
|
+
window.addEventListener("keydown", onKeyDown);
|
|
35
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
36
|
+
}, [
|
|
37
|
+
disabled,
|
|
38
|
+
hasPin,
|
|
39
|
+
clearPins
|
|
40
|
+
]);
|
|
41
|
+
const onCategoryEnter = useCallback((categoryIndex) => {
|
|
42
|
+
if (disabled) return;
|
|
43
|
+
setHoveredIndex(categoryIndex);
|
|
44
|
+
}, [disabled]);
|
|
45
|
+
const onCategoryLeave = useCallback(() => {
|
|
46
|
+
if (disabled) return;
|
|
47
|
+
setHoveredIndex(null);
|
|
48
|
+
}, [disabled]);
|
|
49
|
+
const onCategoryClick = useCallback((categoryIndex) => {
|
|
50
|
+
if (disabled) return;
|
|
51
|
+
const next = pinnedIndex === categoryIndex ? null : categoryIndex;
|
|
52
|
+
setPinnedIndex(next);
|
|
53
|
+
onPinnedChangeRef.current?.(next);
|
|
54
|
+
}, [disabled, pinnedIndex]);
|
|
55
|
+
const onSeriesEnter = useCallback((seriesKey) => {
|
|
56
|
+
setHoveredSeriesKey(seriesKey);
|
|
57
|
+
}, []);
|
|
58
|
+
const onSeriesLeave = useCallback(() => {
|
|
59
|
+
setHoveredSeriesKey(null);
|
|
60
|
+
}, []);
|
|
61
|
+
const onSeriesClick = useCallback((seriesKey) => {
|
|
62
|
+
const next = pinnedSeriesKey === seriesKey ? null : seriesKey;
|
|
63
|
+
setPinnedSeriesKey(next);
|
|
64
|
+
if (next === null) setHoveredSeriesKey(null);
|
|
65
|
+
}, [pinnedSeriesKey]);
|
|
66
|
+
const getMarkState = useCallback(({ categoryIndex, seriesKey }) => {
|
|
67
|
+
if (isLoading) return ChartMarkState.MUTED;
|
|
68
|
+
const categoryState = (() => {
|
|
69
|
+
if (categoryIndex === void 0) return ChartMarkState.ACTIVE;
|
|
70
|
+
if (safePinned !== null) {
|
|
71
|
+
if (categoryIndex === safePinned) return ChartMarkState.ACTIVE;
|
|
72
|
+
if (categoryIndex === safeHovered) return ChartMarkState.MUTED;
|
|
73
|
+
return ChartMarkState.FADED;
|
|
74
|
+
}
|
|
75
|
+
if (safeHovered !== null) return categoryIndex === safeHovered ? ChartMarkState.ACTIVE : ChartMarkState.MUTED;
|
|
76
|
+
return ChartMarkState.ACTIVE;
|
|
77
|
+
})();
|
|
78
|
+
const seriesState = (() => {
|
|
79
|
+
if (seriesKey === void 0) return ChartMarkState.ACTIVE;
|
|
80
|
+
if (safePinnedSeries !== null) {
|
|
81
|
+
if (seriesKey === safePinnedSeries) return ChartMarkState.ACTIVE;
|
|
82
|
+
if (seriesKey === safeHoveredSeries) return ChartMarkState.MUTED;
|
|
83
|
+
return ChartMarkState.FADED;
|
|
84
|
+
}
|
|
85
|
+
if (safeHoveredSeries !== null) return seriesKey === safeHoveredSeries ? ChartMarkState.ACTIVE : ChartMarkState.MUTED;
|
|
86
|
+
return ChartMarkState.ACTIVE;
|
|
87
|
+
})();
|
|
88
|
+
return severity(categoryState) >= severity(seriesState) ? categoryState : seriesState;
|
|
89
|
+
}, [
|
|
90
|
+
isLoading,
|
|
91
|
+
safePinned,
|
|
92
|
+
safeHovered,
|
|
93
|
+
safePinnedSeries,
|
|
94
|
+
safeHoveredSeries
|
|
95
|
+
]);
|
|
96
|
+
return useMemo(() => ({
|
|
97
|
+
pinnedIndex: safePinned,
|
|
98
|
+
activeIndex: safePinned ?? safeHovered,
|
|
99
|
+
hoveredSeriesKey: safeHoveredSeries,
|
|
100
|
+
pinnedSeriesKey: safePinnedSeries,
|
|
101
|
+
isEngaged: safePinned !== null || safeHovered !== null || safePinnedSeries !== null || safeHoveredSeries !== null,
|
|
102
|
+
getMarkState,
|
|
103
|
+
onCategoryEnter,
|
|
104
|
+
onCategoryLeave,
|
|
105
|
+
onCategoryClick,
|
|
106
|
+
onSeriesEnter,
|
|
107
|
+
onSeriesLeave,
|
|
108
|
+
onSeriesClick,
|
|
109
|
+
onBackdropClick: clearPins
|
|
110
|
+
}), [
|
|
111
|
+
safeHovered,
|
|
112
|
+
safePinned,
|
|
113
|
+
safeHoveredSeries,
|
|
114
|
+
safePinnedSeries,
|
|
115
|
+
getMarkState,
|
|
116
|
+
onCategoryEnter,
|
|
117
|
+
onCategoryLeave,
|
|
118
|
+
onCategoryClick,
|
|
119
|
+
onSeriesEnter,
|
|
120
|
+
onSeriesLeave,
|
|
121
|
+
onSeriesClick,
|
|
122
|
+
clearPins
|
|
123
|
+
]);
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { useChartInteraction };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tooltip placement with edge collision handling.
|
|
3
|
+
*
|
|
4
|
+
* Computed in JS rather than CSS because clamping needs a percentage of the
|
|
5
|
+
* tooltip's own size measured against a percentage of the container's, and
|
|
6
|
+
* `min()`/`max()` cannot resolve two different percentage bases in one
|
|
7
|
+
* expression. Any CSS-only attempt works until the first long label.
|
|
8
|
+
*/
|
|
9
|
+
interface UseChartTooltipPositionOptions {
|
|
10
|
+
/** Anchor in container coordinates. */
|
|
11
|
+
anchorX: number;
|
|
12
|
+
anchorY: number;
|
|
13
|
+
/** The box to stay inside. */
|
|
14
|
+
containerWidth: number;
|
|
15
|
+
containerHeight: number;
|
|
16
|
+
/** Half-width of the anchored category, so the tooltip can sit beside it. */
|
|
17
|
+
anchorHalfWidth?: number;
|
|
18
|
+
/**
|
|
19
|
+
* An x coordinate to move away from, instead of flipping on the container's
|
|
20
|
+
* midline.
|
|
21
|
+
*
|
|
22
|
+
* Radial charts need this. Their anchor already sits on the arc's outer edge,
|
|
23
|
+
* so "which half of the container am I in" points the tooltip back over the
|
|
24
|
+
* middle of the chart — across the very slices it describes, and across any
|
|
25
|
+
* donut-hole content. Passing the centre pushes it outward instead.
|
|
26
|
+
*/
|
|
27
|
+
placeAwayFromX?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Where the tooltip sits vertically relative to its anchor.
|
|
30
|
+
*
|
|
31
|
+
* `ABOVE` suits an anchor that marks the top of something (a bar, the highest
|
|
32
|
+
* point in a column). `CENTERED` suits an anchor that marks a position rather
|
|
33
|
+
* than a top, such as a point on an arc.
|
|
34
|
+
*/
|
|
35
|
+
verticalAlign?: ChartTooltipVerticalAlign;
|
|
36
|
+
}
|
|
37
|
+
export declare enum ChartTooltipVerticalAlign {
|
|
38
|
+
ABOVE = "ABOVE",
|
|
39
|
+
CENTERED = "CENTERED"
|
|
40
|
+
}
|
|
41
|
+
export interface ChartTooltipPosition {
|
|
42
|
+
/** Attach to the tooltip element so it can be measured. */
|
|
43
|
+
tooltipRef: React.RefObject<HTMLDivElement>;
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
/**
|
|
47
|
+
* False for the first frame after the content changes, while the measured
|
|
48
|
+
* size is still stale. Gating visibility on it hides the reflow.
|
|
49
|
+
*/
|
|
50
|
+
isMeasured: boolean;
|
|
51
|
+
}
|
|
52
|
+
export declare function useChartTooltipPosition({ anchorX, anchorY, containerWidth, containerHeight, anchorHalfWidth, placeAwayFromX, verticalAlign, }: UseChartTooltipPositionOptions): ChartTooltipPosition;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useElementClientSize } from "../hooks/useElementClientSize.js";
|
|
2
|
+
import "./constants.js";
|
|
3
|
+
import { clamp } from "./chartScales.js";
|
|
4
|
+
import { useMemo, useRef } from "react";
|
|
5
|
+
//#region src/charts/useChartTooltipPosition.ts
|
|
6
|
+
var ChartTooltipVerticalAlign = /* @__PURE__ */ function(ChartTooltipVerticalAlign) {
|
|
7
|
+
ChartTooltipVerticalAlign["ABOVE"] = "ABOVE";
|
|
8
|
+
ChartTooltipVerticalAlign["CENTERED"] = "CENTERED";
|
|
9
|
+
return ChartTooltipVerticalAlign;
|
|
10
|
+
}({});
|
|
11
|
+
function useChartTooltipPosition({ anchorX, anchorY, containerWidth, containerHeight, anchorHalfWidth = 0, placeAwayFromX, verticalAlign = "ABOVE" }) {
|
|
12
|
+
const tooltipRef = useRef(null);
|
|
13
|
+
const { width: tooltipWidth, height: tooltipHeight } = useElementClientSize(tooltipRef);
|
|
14
|
+
return useMemo(() => {
|
|
15
|
+
const isMeasured = tooltipWidth !== void 0 && tooltipHeight !== void 0;
|
|
16
|
+
const w = tooltipWidth ?? 0;
|
|
17
|
+
const h = tooltipHeight ?? 0;
|
|
18
|
+
const rawX = (placeAwayFromX !== void 0 ? anchorX < placeAwayFromX : anchorX > containerWidth / 2) ? anchorX - anchorHalfWidth - 10 - w : anchorX + anchorHalfWidth + 10;
|
|
19
|
+
const rawY = verticalAlign === "CENTERED" ? anchorY - h / 2 : Math.min(anchorY, containerHeight / 2);
|
|
20
|
+
return {
|
|
21
|
+
tooltipRef,
|
|
22
|
+
x: clamp(rawX, 0, Math.max(0, containerWidth - w)),
|
|
23
|
+
y: clamp(rawY, 0, Math.max(0, containerHeight - h)),
|
|
24
|
+
isMeasured
|
|
25
|
+
};
|
|
26
|
+
}, [
|
|
27
|
+
anchorX,
|
|
28
|
+
anchorY,
|
|
29
|
+
containerWidth,
|
|
30
|
+
containerHeight,
|
|
31
|
+
anchorHalfWidth,
|
|
32
|
+
placeAwayFromX,
|
|
33
|
+
verticalAlign,
|
|
34
|
+
tooltipWidth,
|
|
35
|
+
tooltipHeight
|
|
36
|
+
]);
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { ChartTooltipVerticalAlign, useChartTooltipPosition };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ChartPalette, ChartSeriesStyles } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Palette assignment for a chart's series, shared by all three charts.
|
|
4
|
+
*
|
|
5
|
+
* Every chart resolved colour the same way — look the key up in the `series`
|
|
6
|
+
* record, take its slot, fall back to the palette — but each spelled it
|
|
7
|
+
* differently and each rebuilt the key list itself. Doing it once here is what
|
|
8
|
+
* makes "adding a series never recolours the existing ones" a property of the
|
|
9
|
+
* design rather than of three separate call sites remembering to use
|
|
10
|
+
* `indexOf` instead of the loop counter.
|
|
11
|
+
*/
|
|
12
|
+
export interface SeriesColorResolver<TKey extends string> {
|
|
13
|
+
/**
|
|
14
|
+
* Series keys in `series` record order.
|
|
15
|
+
*
|
|
16
|
+
* Insertion order is what makes a key's palette slot stable regardless of
|
|
17
|
+
* which data happens to contain it, so this is never sorted.
|
|
18
|
+
*/
|
|
19
|
+
keys: TKey[];
|
|
20
|
+
/** Colour for a series. The record's own `color` wins over the slot. */
|
|
21
|
+
resolve: (key: TKey, explicit?: ChartPalette) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Colour by palette position, for marks that are not series.
|
|
24
|
+
*
|
|
25
|
+
* A stacked bar's segments are a second dimension with no record of their
|
|
26
|
+
* own, so they take the ramp by position rather than by key.
|
|
27
|
+
*/
|
|
28
|
+
resolveByIndex: (index: number, explicit?: ChartPalette) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Neutral, for a mark that names no series at all.
|
|
31
|
+
*
|
|
32
|
+
* The pie's folded bucket is not one of the slices, so borrowing a hue would
|
|
33
|
+
* imply it is.
|
|
34
|
+
*/
|
|
35
|
+
neutral: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function useSeriesColorResolver<TKey extends string>(series: ChartSeriesStyles<TKey>): SeriesColorResolver<TKey>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useGalaxyTheme } from "../theme/GalaxyTheme.js";
|
|
2
|
+
import { resolveChartPaletteColor, resolveSeriesColor } from "./chartTheme.js";
|
|
3
|
+
import { useCallback, useMemo } from "react";
|
|
4
|
+
//#region src/charts/useSeriesColorResolver.ts
|
|
5
|
+
function useSeriesColorResolver(series) {
|
|
6
|
+
const { theme } = useGalaxyTheme();
|
|
7
|
+
const keys = useMemo(() => Object.keys(series), [series]);
|
|
8
|
+
const resolveByIndex = useCallback((index, explicit) => explicit ? resolveChartPaletteColor(theme, explicit) : resolveSeriesColor(theme, index), [theme]);
|
|
9
|
+
const resolve = useCallback((key, explicit) => resolveSeriesColor(theme, keys.indexOf(key), explicit ?? series[key]?.color), [
|
|
10
|
+
theme,
|
|
11
|
+
keys,
|
|
12
|
+
series
|
|
13
|
+
]);
|
|
14
|
+
return useMemo(() => ({
|
|
15
|
+
keys,
|
|
16
|
+
resolve,
|
|
17
|
+
resolveByIndex,
|
|
18
|
+
neutral: theme.color.text.tertiary
|
|
19
|
+
}), [
|
|
20
|
+
keys,
|
|
21
|
+
resolve,
|
|
22
|
+
resolveByIndex,
|
|
23
|
+
theme
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { useSeriesColorResolver };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface ElementClientSize {
|
|
2
|
+
width: number | undefined;
|
|
3
|
+
height: number | undefined;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Hook that tracks an element's *client* size — the padding box, excluding
|
|
7
|
+
* scrollbars and borders.
|
|
8
|
+
*
|
|
9
|
+
* Use this instead of {@link useElementWidth} when the measurement drives
|
|
10
|
+
* something that must line up with the scrollport (a sticky overlay, a
|
|
11
|
+
* viewport-width panel). `useElementWidth` measures the border box via
|
|
12
|
+
* `getBoundingClientRect`, which includes the scrollbar gutter and would make
|
|
13
|
+
* such an element overhang.
|
|
14
|
+
*
|
|
15
|
+
* @param ref - A ref to the element to measure
|
|
16
|
+
* @returns The current client width/height in pixels, or undefined before the
|
|
17
|
+
* first measurement
|
|
18
|
+
*/
|
|
19
|
+
export declare const useElementClientSize: (ref: React.RefObject<HTMLElement | null>) => ElementClientSize;
|
|
20
|
+
export {};
|