diff --git a/packages/components/package.json b/packages/components/package.json index 7a0105f3e6f..025abe76106 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -33,6 +33,7 @@ "prepublishOnly": "pnpm build && test -f 'dist/styles/@hashicorp/design-system-components.css' || (echo 'The pre-compiled CSS file was not found' && exit 1)" }, "dependencies": { + "@carbon/charts": "1.23.15", "@codemirror/commands": "^6.8.0", "@codemirror/lang-go": "^6.0.1", "@codemirror/lang-javascript": "^6.2.2", @@ -199,6 +200,12 @@ "./components/hds/button-set/index.js": "./dist/_app_/components/hds/button-set/index.js", "./components/hds/button/index.js": "./dist/_app_/components/hds/button/index.js", "./components/hds/card/container.js": "./dist/_app_/components/hds/card/container.js", + "./components/hds/charts/bar/index.js": "./dist/_app_/components/hds/charts/bar/index.js", + "./components/hds/charts/bar/options.js": "./dist/_app_/components/hds/charts/bar/options.js", + "./components/hds/charts/donut/index.js": "./dist/_app_/components/hds/charts/donut/index.js", + "./components/hds/charts/donut/options.js": "./dist/_app_/components/hds/charts/donut/options.js", + "./components/hds/charts/meter/index.js": "./dist/_app_/components/hds/charts/meter/index.js", + "./components/hds/charts/meter/options.js": "./dist/_app_/components/hds/charts/meter/options.js", "./components/hds/code-block/copy-button.js": "./dist/_app_/components/hds/code-block/copy-button.js", "./components/hds/code-block/description.js": "./dist/_app_/components/hds/code-block/description.js", "./components/hds/code-block/index.js": "./dist/_app_/components/hds/code-block/index.js", diff --git a/packages/components/src/components/hds/charts/bar/index.hbs b/packages/components/src/components/hds/charts/bar/index.hbs new file mode 100644 index 00000000000..5b6537ea286 --- /dev/null +++ b/packages/components/src/components/hds/charts/bar/index.hbs @@ -0,0 +1,6 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: MPL-2.0 +}} + +
\ No newline at end of file diff --git a/packages/components/src/components/hds/charts/bar/index.ts b/packages/components/src/components/hds/charts/bar/index.ts new file mode 100644 index 00000000000..f315b632ff2 --- /dev/null +++ b/packages/components/src/components/hds/charts/bar/index.ts @@ -0,0 +1,43 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +import { SimpleBarChart } from '@carbon/charts'; +import options from './options.js'; +import '@carbon/charts/styles.css'; + +export interface HdsChartsBarSignature { + Args: { + title?: string; + data: Array<{ group: string; date: string; value: number }>; + }; + Blocks: { + default: []; + }; + Element: HTMLDivElement; +} + +export default class HdsChartsBar extends Component { + chart: SimpleBarChart | null = null; + + @action + setupChart(element: HTMLDivElement): void { + const chartData = this.args.data; + + // Merge the dynamic options into the default options + const chartOptions = { + ...options, + title: this.args.title || options.title, + }; + + // Create the SimpleBarChart instance + this.chart = new SimpleBarChart(element, { + data: chartData, + options: chartOptions, + }); + } +} diff --git a/packages/components/src/components/hds/charts/bar/options.js b/packages/components/src/components/hds/charts/bar/options.js new file mode 100644 index 00000000000..5ad394ee481 --- /dev/null +++ b/packages/components/src/components/hds/charts/bar/options.js @@ -0,0 +1,26 @@ +import { ScaleTypes } from '@carbon/charts'; + +export default { + title: '', + toolbar: { + enabled: false, // hide toolbar + }, + axes: { + left: { + mapsTo: 'value', + }, + bottom: { + mapsTo: 'date', + scaleType: ScaleTypes.LABELS, + }, + }, + grid: { + x: { + numberOfTicks: 0, + }, + }, + height: '400px', + legend: { + enabled: false, // hide legend (for single color bar chart) + }, +}; diff --git a/packages/components/src/components/hds/charts/donut/index.hbs b/packages/components/src/components/hds/charts/donut/index.hbs new file mode 100644 index 00000000000..f3cb47e4e7d --- /dev/null +++ b/packages/components/src/components/hds/charts/donut/index.hbs @@ -0,0 +1,6 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: MPL-2.0 +}} + +
\ No newline at end of file diff --git a/packages/components/src/components/hds/charts/donut/index.ts b/packages/components/src/components/hds/charts/donut/index.ts new file mode 100644 index 00000000000..93c164a53df --- /dev/null +++ b/packages/components/src/components/hds/charts/donut/index.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +import { DonutChart } from '@carbon/charts'; +import options from './options.js'; +import '@carbon/charts/styles.css'; +export interface HdsChartsDonutSignature { + Args: { + title?: string; + data: Array<{ group: string; value: number }>; + colorMap?: { [key: string]: string }; // Optional custom colors for the chart segments/slices + }; + Blocks: { + default: []; + }; + Element: HTMLDivElement; +} + +export default class HdsChartsDonut extends Component { + chart: DonutChart | null = null; + + @action + setupChart(element: HTMLDivElement): void { + const chartData = this.args.data; + + // Merge the dynamic options into the default options + const chartOptions = { + ...options, + title: this.args.title || options.title, + color: { + scale: this.args.colorMap, + }, + }; + + // Create the DonutChart instance + this.chart = new DonutChart(element, { + data: chartData, + options: chartOptions, + }); + } +} diff --git a/packages/components/src/components/hds/charts/donut/options.js b/packages/components/src/components/hds/charts/donut/options.js new file mode 100644 index 00000000000..6d4e5e630a5 --- /dev/null +++ b/packages/components/src/components/hds/charts/donut/options.js @@ -0,0 +1,24 @@ +export default { + title: '', // Set title using @title on the component + resizable: true, + legend: { + // alignment: 'left', // = alignment w/i container, options: 'left', 'right', 'center' + position: 'left', // = position relative to chart, options: 'top', 'bottom', 'left', 'right' + truncation: { + type: 'none', + }, + }, + toolbar: { + enabled: false, // hide toolbar + }, + donut: { + alignment: 'center', // = alignment w/i container, options: 'center', 'left', 'right' + }, + pie: { + labels: { + enabled: true, + formatter: (data) => data.value, + }, + }, + height: '175px', +}; diff --git a/packages/components/src/components/hds/charts/meter/index.hbs b/packages/components/src/components/hds/charts/meter/index.hbs new file mode 100644 index 00000000000..44bcde1d8bb --- /dev/null +++ b/packages/components/src/components/hds/charts/meter/index.hbs @@ -0,0 +1,6 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: MPL-2.0 +}} + +
\ No newline at end of file diff --git a/packages/components/src/components/hds/charts/meter/index.ts b/packages/components/src/components/hds/charts/meter/index.ts new file mode 100644 index 00000000000..cfc0649daa7 --- /dev/null +++ b/packages/components/src/components/hds/charts/meter/index.ts @@ -0,0 +1,57 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +import { MeterChart } from '@carbon/charts'; +import options from './options.js'; +import '@carbon/charts/styles.css'; + +export interface HdsChartsMeterSignature { + Args: { + title?: string; + data: Array<{ group: string; value: number }>; + total?: number; // if not passed in it will be calculated from the data + }; + Blocks: { + default: []; + }; + Element: HTMLDivElement; +} + +export default class HdsChartsMeter extends Component { + chart: MeterChart | null = null; + + @action + setupChart(element: HTMLDivElement): void { + const chartData = this.args.data; + + // Dynamically calculate the total from the passed-in data + const chartTotal = chartData.reduce( + (sum, item): number => sum + item.value, + 0 + ); + + // Merge the dynamic options into the default options + const chartOptions = { + ...options, + title: this.args.title || options.title, + meter: { + ...options.meter, + proportional: { + ...options.meter.proportional, + total: this.args.total || chartTotal, + }, + }, + }; + + // Create the MeterChart instance + this.chart = new MeterChart(element, { + data: chartData, + options: chartOptions, + }); + } +} diff --git a/packages/components/src/components/hds/charts/meter/options.js b/packages/components/src/components/hds/charts/meter/options.js new file mode 100644 index 00000000000..80982860fe4 --- /dev/null +++ b/packages/components/src/components/hds/charts/meter/options.js @@ -0,0 +1,12 @@ +export default { + title: '', + height: '130px', + meter: { + proportional: { + unit: '', + }, + }, + toolbar: { + enabled: false, // hide toolbar + }, +}; diff --git a/packages/components/src/styles/@hashicorp/design-system-components.scss b/packages/components/src/styles/@hashicorp/design-system-components.scss index 00c6008b820..f488e056cde 100644 --- a/packages/components/src/styles/@hashicorp/design-system-components.scss +++ b/packages/components/src/styles/@hashicorp/design-system-components.scss @@ -26,6 +26,7 @@ @use "../components/button"; @use "../components/button-set"; @use "../components/card"; +@use "../components/charts"; @use "../components/code-block"; @use "../components/code-editor"; @use "../components/copy"; diff --git a/packages/components/src/styles/components/charts.scss b/packages/components/src/styles/components/charts.scss new file mode 100644 index 00000000000..5d1ac382934 --- /dev/null +++ b/packages/components/src/styles/components/charts.scss @@ -0,0 +1,33 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +// +// CHARTS +// + +// > DONUT + +.hds-charts-donut { + // outline: 1px dotted red; // for testing - see boundaries of chart container + + // increase stroke definition on slices (especially for resized/shrunken charts) + .slice { + stroke: #fff; + stroke-width: 1px; + } + + // The size of the title affects the rendered size of the donut chart + .title { + min-height: 1.3em; + } +} + +// > BAR + +.hds-charts-bar { + .graph-frame { + overflow: hidden; // cut off bottom line which overflows container + } +} diff --git a/packages/components/src/template-registry.ts b/packages/components/src/template-registry.ts index 66b79a5e3d1..87b75e8f818 100644 --- a/packages/components/src/template-registry.ts +++ b/packages/components/src/template-registry.ts @@ -22,22 +22,14 @@ import type HdsAdvancedTableExpandableTrGroupComponent from './components/hds/ad import type HdsAlertComponent from './components/hds/alert'; import type HdsAlertDescriptionComponent from './components/hds/alert/description'; import type HdsAlertTitleComponent from './components/hds/alert/title'; -import type HdsAppHeaderComponent from './components/hds/app-header'; -import type HdsAppHeaderHomeLinkComponent from './components/hds/app-header/home-link'; -import type HdsAppHeaderMenuButtonComponent from './components/hds/app-header/menu-button'; + import type HdsAppFooterComponent from './components/hds/app-footer'; import type HdsAppFooterCopyrightComponent from './components/hds/app-footer/copyright'; import type HdsAppFooterItemComponent from './components/hds/app-footer/item'; import type HdsAppFooterLegalLinksComponent from './components/hds/app-footer/legal-links'; import type HdsAppFooterLinkComponent from './components/hds/app-footer/link'; import type HdsAppFooterStatusLinkComponent from './components/hds/app-footer/status-link'; -import type HdsBadgeComponent from './components/hds/badge'; -import type HdsBadgeCountComponent from './components/hds/badge-count'; -import type HdsBreadcrumbComponent from './components/hds/breadcrumb/index.ts'; -import type HdsBreadcrumbItemComponent from './components/hds/breadcrumb/item'; -import type HdsBreadcrumbTruncationComponent from './components/hds/breadcrumb/truncation.ts'; -import type HdsButtonComponent from './components/hds/button'; -import type HdsButtonSetComponent from './components/hds/button-set'; + import type HdsAppFrameComponent from './components/hds/app-frame'; import type HdsAppFrameFooterComponent from './components/hds/app-frame/parts/footer'; import type HdsAppFrameHeaderComponent from './components/hds/app-frame/parts/header'; @@ -45,6 +37,10 @@ import type HdsAppFrameMainComponent from './components/hds/app-frame/parts/main import type HdsAppFrameModalsComponent from './components/hds/app-frame/parts/modals'; import type HdsAppFrameSidebarComponent from './components/hds/app-frame/parts/sidebar'; +import type HdsAppHeaderComponent from './components/hds/app-header'; +import type HdsAppHeaderHomeLinkComponent from './components/hds/app-header/home-link'; +import type HdsAppHeaderMenuButtonComponent from './components/hds/app-header/menu-button'; + import type HdsAppSideNavComponent from './components/hds/app-side-nav'; import type HdsAppSideNavToggleButtonComponent from './components/hds/app-side-nav/toggle-button'; import type HdsAppSideNavPortalComponent from './components/hds/app-side-nav/portal'; @@ -60,7 +56,20 @@ import type HdsApplicationStateBodyComponent from './components/hds/application- import type HdsApplicationStateFooterComponent from './components/hds/application-state/footer'; import type HdsApplicationStateHeaderComponent from './components/hds/application-state/header'; import type HdsApplicationStateMediaComponent from './components/hds/application-state/media'; + +import type HdsBadgeComponent from './components/hds/badge'; +import type HdsBadgeCountComponent from './components/hds/badge-count'; +import type HdsBreadcrumbComponent from './components/hds/breadcrumb/index.ts'; +import type HdsBreadcrumbItemComponent from './components/hds/breadcrumb/item'; +import type HdsBreadcrumbTruncationComponent from './components/hds/breadcrumb/truncation.ts'; +import type HdsButtonComponent from './components/hds/button'; +import type HdsButtonSetComponent from './components/hds/button-set'; import type HdsCardContainerComponent from './components/hds/card/container.ts'; + +import type HdsChartsDonut from './components/hds/charts/donut/index.ts'; +import type HdsChartsMeter from './components/hds/charts/meter/index.ts'; +import type HdsChartsBar from './components/hds/charts/bar/index.ts'; + import type HdsCodeEditorComponent from './components/hds/code-editor/index.ts'; import type HdsCodeEditorDescriptionComponent from './components/hds/code-editor/description.ts'; import type HdsCodeEditorGenericComponent from './components/hds/code-editor/generic.ts'; @@ -433,6 +442,11 @@ export default interface HdsComponentsRegistry { 'Hds::Card::Container': typeof HdsCardContainerComponent; 'hds/card/container': typeof HdsCardContainerComponent; + // Charts + 'Hds::Charts::Donut': typeof HdsChartsDonut; + 'Hds::Charts::Meter': typeof HdsChartsMeter; + 'Hds::Charts::Bar': typeof HdsChartsBar; + // Code Block 'Hds::CodeBlock': typeof HdsCodeBlockComponent; 'hds/code-block': typeof HdsCodeBlockComponent; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 141c7b2cafe..fb9f1a0862d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,9 @@ importers: packages/components: dependencies: + '@carbon/charts': + specifier: 1.23.15 + version: 1.23.15 '@codemirror/commands': specifier: ^6.8.0 version: 6.8.1 @@ -1877,6 +1880,15 @@ packages: '@bundled-es-modules/memfs@4.9.4': resolution: {integrity: sha512-1XyYPUaIHwEOdF19wYVLBtHJRr42Do+3ctht17cZOHwHf67vkmRNPlYDGY2kJps4RgE5+c7nEZmEzxxvb1NZWA==} + '@carbon/charts@1.23.15': + resolution: {integrity: sha512-Q9zdXzRkKL/PRRMSnc3rA9ypyH0UejFxmN2/fS1K4o5yZb9PQkxc7cWuglI9GwAUD/ml6/clcIuLmVKnB8BFcA==} + + '@carbon/colors@11.37.0': + resolution: {integrity: sha512-PXZkIJ9AulEkiIFlI8fjaksi7tWuoPUKfChc5op55j6jP1zXTEfrb449SCKXOJM912MzY5EkaRGgNN09f6rM2Q==} + + '@carbon/utils-position@1.3.0': + resolution: {integrity: sha512-bfar2dV+fQ15syIrH3n9ujY4PXd1Q+AF2VcTLJIC04IDe2f80zOnJlLNPc/RktHcWTZ7WSQm80cQo3abGcsfTA==} + '@changesets/apply-release-plan@7.0.12': resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==} @@ -2852,6 +2864,10 @@ packages: resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} engines: {node: '>=18.18'} + '@ibm/telemetry-js@1.9.1': + resolution: {integrity: sha512-qq8RPafUJHUQieXVCte1kbJEx6JctWzbA/YkXzopbfzIDRT2+hbR9QmgH+KH7bDDNRcDbdHWvHfwJKzThlMtPg==} + hasBin: true + '@inquirer/figures@1.0.9': resolution: {integrity: sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==} engines: {node: '>=18'} @@ -3543,6 +3559,99 @@ packages: '@types/cors@2.8.17': resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -3630,6 +3739,9 @@ packages: '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -3768,6 +3880,24 @@ packages: '@types/tinycolor2@1.4.6': resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} + '@types/topojson-client@3.1.5': + resolution: {integrity: sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw==} + + '@types/topojson-server@3.0.4': + resolution: {integrity: sha512-5+ieK8ePfP+K2VH6Vgs1VCt+fO1U8XZHj0UsF+NktaF0DavAo1q3IvCBXgokk/xmtvoPltSUs6vxuR/zMdOE1g==} + + '@types/topojson-simplify@3.0.3': + resolution: {integrity: sha512-sBO5UZ0O2dB0bNwo0vut2yLHhj3neUGi9uL7/ROdm8Gs6dtt4jcB9OGDKr+M2isZwQM2RuzVmifnMZpxj4IGNw==} + + '@types/topojson-specification@1.0.5': + resolution: {integrity: sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ==} + + '@types/topojson@3.2.6': + resolution: {integrity: sha512-ppfdlxjxofWJ66XdLgIlER/85RvpGyfOf8jrWf+3kVIjEatFxEZYD/Ea83jO672Xu1HRzd/ghwlbcZIUNHTskw==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -5690,6 +5820,151 @@ packages: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-cloud@1.2.7: + resolution: {integrity: sha512-8TrgcgwRIpoZYQp7s3fGB7tATWfhckRb8KcVd1bOgqkNdkJRDGWfdSf4HkHHzZxSczwQJdSxvfPudwir5IAJ3w==} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@1.0.6: + resolution: {integrity: sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + dag-map@2.0.2: resolution: {integrity: sha512-xnsprIzYuDeiyu5zSKwilV/ajRHxnoMlAhEREfyfTgTSViMVY2fGP1ZcHJbtwup26oCkofySU/m6oKJ3HrkW7w==} @@ -5720,6 +5995,9 @@ packages: dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + date-time@2.1.0: resolution: {integrity: sha512-/9+C44X7lot0IeiyfgJmETtRMhBidBYM2QFFIkGa0U1k+hSyY87Nw7PY3eDqpvCBm7I3WCSfPeZskW/YYq6m4g==} engines: {node: '>=4'} @@ -5842,6 +6120,9 @@ packages: resolution: {integrity: sha512-R6ep6JJ+eOBZsBr9esiNN1gxFbZE4Q2cULkUSFumGYecAiS6qodDvcPx/sFuWHMNul7DWmrtoEOpYSm7o6tbSA==} engines: {node: '>=18'} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -5962,6 +6243,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.2.6: + resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + domutils@1.7.0: resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} @@ -7646,6 +7930,9 @@ packages: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} + html-to-image@1.11.11: + resolution: {integrity: sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -7839,6 +8126,13 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + intl-messageformat@10.7.16: resolution: {integrity: sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==} @@ -10319,6 +10613,9 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup-plugin-copy-assets@2.0.3: resolution: {integrity: sha512-ETShhQGb9SoiwcNrvb3BhUNSGR89Jao0+XxxfzzLW1YsUzx8+rMO4z9oqWWmo6OHUmfNQRvqRj0cAyPkS9lN9w==} peerDependencies: @@ -10381,6 +10678,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + rxjs@6.6.7: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} engines: {npm: '>=2.0.0'} @@ -11215,6 +11515,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + topojson-client@3.1.0: + resolution: {integrity: sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==} + hasBin: true + tough-cookie@4.1.4: resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} @@ -13027,6 +13331,31 @@ snapshots: stream: 0.0.3 util: 0.12.5 + '@carbon/charts@1.23.15': + dependencies: + '@carbon/colors': 11.37.0 + '@carbon/utils-position': 1.3.0 + '@ibm/telemetry-js': 1.9.1 + '@types/d3': 7.4.3 + '@types/topojson': 3.2.6 + d3: 7.9.0 + d3-cloud: 1.2.7 + d3-sankey: 0.12.3 + date-fns: 4.1.0 + dompurify: 3.2.6 + html-to-image: 1.11.11 + lodash-es: 4.17.21 + topojson-client: 3.1.0 + tslib: 2.8.1 + + '@carbon/colors@11.37.0': + dependencies: + '@ibm/telemetry-js': 1.9.1 + + '@carbon/utils-position@1.3.0': + dependencies: + '@ibm/telemetry-js': 1.9.1 + '@changesets/apply-release-plan@7.0.12': dependencies: '@changesets/config': 3.1.1 @@ -14300,6 +14629,7 @@ snapshots: '@hashicorp/design-system-components@file:packages/components(5fea96526e38c31493053252567363c4)': dependencies: + '@carbon/charts': 1.23.15 '@codemirror/commands': 6.8.1 '@codemirror/lang-go': 6.0.1 '@codemirror/lang-javascript': 6.2.4 @@ -14358,6 +14688,7 @@ snapshots: '@hashicorp/design-system-components@file:packages/components(f62dfc5f715da30824529e0727e3c947)': dependencies: + '@carbon/charts': 1.23.15 '@codemirror/commands': 6.8.1 '@codemirror/lang-go': 6.0.1 '@codemirror/lang-javascript': 6.2.4 @@ -14441,6 +14772,8 @@ snapshots: '@humanwhocodes/retry@0.4.2': {} + '@ibm/telemetry-js@1.9.1': {} + '@inquirer/figures@1.0.9': {} '@isaacs/balanced-match@4.0.1': {} @@ -15330,6 +15663,123 @@ snapshots: dependencies: '@types/node': 24.1.0 + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.34 @@ -15465,6 +15915,8 @@ snapshots: dependencies: '@types/node': 24.1.0 + '@types/geojson@7946.0.16': {} + '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 @@ -15603,6 +16055,36 @@ snapshots: '@types/tinycolor2@1.4.6': {} + '@types/topojson-client@3.1.5': + dependencies: + '@types/geojson': 7946.0.16 + '@types/topojson-specification': 1.0.5 + + '@types/topojson-server@3.0.4': + dependencies: + '@types/geojson': 7946.0.16 + '@types/topojson-specification': 1.0.5 + + '@types/topojson-simplify@3.0.3': + dependencies: + '@types/geojson': 7946.0.16 + '@types/topojson-specification': 1.0.5 + + '@types/topojson-specification@1.0.5': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/topojson@3.2.6': + dependencies: + '@types/geojson': 7946.0.16 + '@types/topojson-client': 3.1.5 + '@types/topojson-server': 3.0.4 + '@types/topojson-simplify': 3.0.3 + '@types/topojson-specification': 1.0.5 + + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -18266,6 +18748,179 @@ snapshots: dependencies: array-find-index: 1.0.2 + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-cloud@1.2.7: + dependencies: + d3-dispatch: 1.0.6 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@1.0.6: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + dag-map@2.0.2: {} data-uri-to-buffer@6.0.2: {} @@ -18301,6 +18956,8 @@ snapshots: dataloader@1.4.0: {} + date-fns@4.1.0: {} + date-time@2.1.0: dependencies: time-zone: 1.0.0 @@ -18410,6 +19067,10 @@ snapshots: p-map: 7.0.3 slash: 5.1.0 + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + delayed-stream@1.0.0: {} delegate@3.2.0: {} @@ -18506,6 +19167,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.2.6: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@1.7.0: dependencies: dom-serializer: 0.2.2 @@ -21953,6 +22618,8 @@ snapshots: html-tags@3.3.1: {} + html-to-image@1.11.11: {} + html-void-elements@3.0.0: {} htmlparser2@3.10.1: @@ -22183,6 +22850,10 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + internmap@1.0.1: {} + + internmap@2.0.3: {} + intl-messageformat@10.7.16: dependencies: '@formatjs/ecma402-abstract': 2.3.4 @@ -25137,6 +25808,8 @@ snapshots: dependencies: glob: 7.2.3 + robust-predicates@3.0.2: {} + rollup-plugin-copy-assets@2.0.3(rollup@4.46.2): dependencies: fs-extra: 7.0.1 @@ -25224,6 +25897,8 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rw@1.3.3: {} + rxjs@6.6.7: dependencies: tslib: 1.14.1 @@ -26374,6 +27049,10 @@ snapshots: toidentifier@1.0.1: {} + topojson-client@3.1.0: + dependencies: + commander: 2.20.3 + tough-cookie@4.1.4: dependencies: psl: 1.15.0 diff --git a/showcase/app/router.ts b/showcase/app/router.ts index d6b68629d80..aa9b7b81a6a 100644 --- a/showcase/app/router.ts +++ b/showcase/app/router.ts @@ -11,31 +11,31 @@ export default class Router extends EmberRouter { rootURL = config.rootURL; } -Router.map(function () { - this.route('page-foundations', { path: 'foundations' }, function () { +Router.map(function (): void { + this.route('page-foundations', { path: 'foundations' }, function (): void { this.route('typography'); this.route('elevation'); this.route('focus-ring'); - this.route('breakpoints', function () { - this.route('frameless', function () { + this.route('breakpoints', function (): void { + this.route('frameless', function (): void { this.route('demo-viewport-breakpoints-visualization'); this.route('demo-viewport-breakpoints-visualization-with-ui-shell'); this.route('demo-viewport-breakpoints-page-padding'); }); }); }); - this.route('page-components', { path: 'components' }, function () { + this.route('page-components', { path: 'components' }, function (): void { this.route('accordion'); this.route('advanced-table'); this.route('alert'); this.route('app-footer'); - this.route('app-header', function () { - this.route('frameless', function () { + this.route('app-header', function (): void { + this.route('frameless', function (): void { this.route('demo-responsiveness'); }); }); - this.route('app-side-nav', function () { - this.route('frameless', function () { + this.route('app-side-nav', function (): void { + this.route('frameless', function (): void { this.route('demo-responsiveness'); }); }); @@ -46,6 +46,9 @@ Router.map(function () { this.route('button'); this.route('button-set'); this.route('card'); + + this.route('charts', function (): void {}); + this.route('code-block'); this.route('code-editor'); this.route('dropdown'); diff --git a/showcase/app/routes/page-components/charts/index.js b/showcase/app/routes/page-components/charts/index.js new file mode 100644 index 00000000000..33510fdef6d --- /dev/null +++ b/showcase/app/routes/page-components/charts/index.js @@ -0,0 +1,136 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import Route from '@ember/routing/route'; + +// Donut data + +const DONUT_SERVICE_HEALTH_DATA = [ + { group: 'Critical', value: 38 }, + { group: 'Warning', value: 34 }, + { group: 'Healthy', value: 18 }, +]; + +/* + Note: Currently, Donut chart does not natively support sub-groups or hierarchical (multi-level) data. + (Sometimes called a "Sunburst chart".) + + Cannot do: + { + group: 'Consul Dedicated', + value: [ + { group: "below v.1.4", value: 1 }, + { group: "above v1.14.0", value: 0 } + ] + }, +*/ +const DONUT_CLUSTERS_DATA = [ + { group: 'Self-managed', value: 2 }, + { + group: 'Consul Dedicated', + value: 1, + }, +]; + +// Meter data + +const METER_DATABASE_TRANSACTIONS_DATA = [ + { + group: 'Create', + value: 174, + }, + { + group: 'Update', + value: 4, + }, + { + group: 'Replace', + value: 13, + }, + { + group: 'Import', + value: 84, + }, + { + group: 'Delete', + value: 3, + }, +]; + +const METER_BILLABLE_RESOURCES_DATA = [ + { + group: 'Stack resources', + value: 1200, + }, + { + group: 'Workspace resources', + value: 24500, + }, +]; + +// Bar data + +const BAR_MANAGED_RESOURCES_DATA = [ + { + date: '2025-01', + value: 9000, + }, + { + date: '2025-02', + value: 12000, + }, + { + date: '2025-03', + value: 10000, + }, + { + date: '2025-04', + value: 13000, + }, + { + date: '2025-05', + value: 14000, + }, + { + date: '2025-06', + value: 15000, + }, + { + date: '2025-07', + value: 15000, + }, + { + date: '2025-08', + value: 18000, + }, + { + date: '2025-09', + value: 21000, + }, + { + date: '2025-10', + value: 22000, + }, + { + date: '2025-11', + value: 24000, + }, + { + date: '2025-12', + value: 27000, + }, +]; + +export default class PageComponentsChartsRoute extends Route { + async model() { + return { + DONUT_SERVICE_HEALTH_DATA, + DONUT_CLUSTERS_DATA, + METER_DATABASE_TRANSACTIONS_DATA, + METER_BILLABLE_RESOURCES_DATA, + BAR_MANAGED_RESOURCES_DATA, + }; + } +} diff --git a/showcase/app/templates/index.hbs b/showcase/app/templates/index.hbs index 763c9df7b74..f5990bf0579 100644 --- a/showcase/app/templates/index.hbs +++ b/showcase/app/templates/index.hbs @@ -37,6 +37,18 @@ + + Explorations + + Carbon Charts + +
    +
  1. + + Various chart components + +
  2. +
diff --git a/showcase/app/templates/page-components/charts/index.hbs b/showcase/app/templates/page-components/charts/index.hbs new file mode 100644 index 00000000000..ef9b3449b54 --- /dev/null +++ b/showcase/app/templates/page-components/charts/index.hbs @@ -0,0 +1,61 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: MPL-2.0 +}} + +{{page-title "Charts"}} + +Charts + +Carbon Charts Donut + +
+ + + Clusters + + + + + +
+ Services + From clusters above v1.14.0 +
+ 5 + +
+
+ + + Service Instances + + +
+ + Carbon Charts Meter + + + + + + + + + + + + Carbon Charts Bar + + + + +
\ No newline at end of file diff --git a/showcase/tests/acceptance/components/hds/charts/index.js b/showcase/tests/acceptance/components/hds/charts/index.js new file mode 100644 index 00000000000..ffdcfaac529 --- /dev/null +++ b/showcase/tests/acceptance/components/hds/charts/index.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { visit } from '@ember/test-helpers'; +import { setupApplicationTest } from 'showcase/tests/helpers'; +import { a11yAudit } from 'ember-a11y-testing/test-support'; + +module('Acceptance | components/charts', function (hooks) { + setupApplicationTest(hooks); + + test('Components/charts page passes automated a11y checks', async function (assert) { + await visit('/components/charts/donut'); + + await a11yAudit(); + + assert.ok(true, 'a11y automation audit passed'); + }); +}); diff --git a/showcase/tests/acceptance/percy-test.js b/showcase/tests/acceptance/percy-test.js index f446348071f..cf2bb238c5b 100644 --- a/showcase/tests/acceptance/percy-test.js +++ b/showcase/tests/acceptance/percy-test.js @@ -84,6 +84,9 @@ module('Acceptance | Percy test', function (hooks) { await visit('/components/card'); await percySnapshot('Card'); + await visit('/components/charts'); + await percySnapshot('Charts'); + await visit('/components/code-block'); await percySnapshot('CodeBlock'); diff --git a/showcase/tests/integration/components/hds/charts/bar/index-test.js b/showcase/tests/integration/components/hds/charts/bar/index-test.js new file mode 100644 index 00000000000..8dfd3ce9289 --- /dev/null +++ b/showcase/tests/integration/components/hds/charts/bar/index-test.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'showcase/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | hds/charts/bar/index', function (hooks) { + setupRenderingTest(hooks); + + test('it should render the component with a CSS class that matches the component name', async function (assert) { + this.data = [ + { date: '2025-01', value: 1000 }, + { date: '2025-02', value: 1500 }, + ]; + + await render( + hbs``, + ); + assert.dom('#test-charts-bar').hasClass('hds-charts-bar'); + }); +}); diff --git a/showcase/tests/integration/components/hds/charts/donut/index-test.js b/showcase/tests/integration/components/hds/charts/donut/index-test.js new file mode 100644 index 00000000000..5b6f50dc91a --- /dev/null +++ b/showcase/tests/integration/components/hds/charts/donut/index-test.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'showcase/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | hds/charts/donut/index', function (hooks) { + setupRenderingTest(hooks); + + test('it should render the component with a CSS class that matches the component name', async function (assert) { + this.data = [ + { group: 'group 1', value: 2 }, + { group: 'group 2', value: 4 }, + ]; + + await render( + hbs``, + ); + assert.dom('#test-charts-donut').hasClass('hds-charts-donut'); + }); +}); diff --git a/showcase/tests/integration/components/hds/charts/meter/index-test.js b/showcase/tests/integration/components/hds/charts/meter/index-test.js new file mode 100644 index 00000000000..91d6db1c070 --- /dev/null +++ b/showcase/tests/integration/components/hds/charts/meter/index-test.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'showcase/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | hds/charts/meter/index', function (hooks) { + setupRenderingTest(hooks); + + test('it should render the component with a CSS class that matches the component name', async function (assert) { + this.data = [ + { group: 'Test group 1', value: 30 }, + { group: 'Test group 2', value: 70 }, + ]; + + await render( + hbs``, + ); + assert.dom('#test-charts-meter').hasClass('hds-charts-meter'); + }); +});