@ds-mo/ui 2.11.2 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -13
- package/dist/.build-stamp +1 -1
- package/dist/components/ds-app-shell.js +1 -1
- package/dist/components/ds-banner.js +1 -1
- package/dist/components/ds-banner.js.map +1 -1
- package/dist/components/ds-bar-nav.js +1 -1
- package/dist/components/ds-bar-nav.js.map +1 -1
- package/dist/components/ds-button-filled.js +1 -1
- package/dist/components/{ds-accordion.d.ts → ds-button-unfilled.d.ts} +4 -4
- package/dist/components/ds-button-unfilled.js +2 -0
- package/dist/components/{ds-card-data-viz.d.ts → ds-card-data-viz-donut.d.ts} +4 -4
- package/dist/components/ds-card-data-viz-donut.js +2 -0
- package/dist/components/ds-card-data-viz-donut.js.map +1 -0
- package/dist/components/ds-card-setting.js +1 -1
- package/dist/components/ds-card-setting.js.map +1 -1
- package/dist/components/{ds-fade.d.ts → ds-card.d.ts} +4 -4
- package/dist/components/ds-card.js +2 -0
- package/dist/components/ds-card.js.map +1 -0
- package/dist/components/ds-chart-bar.js +1 -1
- package/dist/components/ds-chart-bar.js.map +1 -1
- package/dist/components/ds-chart-donut.js +1 -1
- package/dist/components/ds-chart-donut.js.map +1 -1
- package/dist/components/ds-chart-legend.js +1 -1
- package/dist/components/ds-chart-legend.js.map +1 -1
- package/dist/components/ds-chart-line.js +1 -1
- package/dist/components/ds-checkbox.js +1 -1
- package/dist/components/ds-checkbox.js.map +1 -1
- package/dist/components/ds-chip.js +1 -1
- package/dist/components/ds-chip.js.map +1 -1
- package/dist/components/ds-empty-state.js +1 -1
- package/dist/components/ds-empty-state.js.map +1 -1
- package/dist/components/ds-field.js +1 -1
- package/dist/components/ds-icon.js +1 -1
- package/dist/components/ds-input.js +1 -1
- package/dist/components/ds-input.js.map +1 -1
- package/dist/components/ds-loader.js +1 -1
- package/dist/components/ds-loader.js.map +1 -1
- package/dist/components/ds-menu.js +1 -1
- package/dist/components/ds-modal.js +1 -1
- package/dist/components/ds-pagination.js +1 -1
- package/dist/components/ds-pagination.js.map +1 -1
- package/dist/components/ds-panel-nav.js +1 -1
- package/dist/components/ds-panel-nav.js.map +1 -1
- package/dist/components/ds-panel-tools.js +1 -1
- package/dist/components/ds-panel-tools.js.map +1 -1
- package/dist/components/ds-radio-group.js +1 -1
- package/dist/components/ds-radio-group.js.map +1 -1
- package/dist/components/ds-select.js +1 -1
- package/dist/components/ds-select.js.map +1 -1
- package/dist/components/ds-shell-gradient-picker.js +1 -1
- package/dist/components/ds-shell-gradient-swatch.js +1 -1
- package/dist/components/ds-skeleton.js +1 -1
- package/dist/components/ds-skeleton.js.map +1 -1
- package/dist/components/ds-slider.js +1 -1
- package/dist/components/ds-slider.js.map +1 -1
- package/dist/components/ds-tab-group-nav.js +1 -1
- package/dist/components/ds-tab-group.js +1 -1
- package/dist/components/ds-tab-group.js.map +1 -1
- package/dist/components/ds-table.js +1 -1
- package/dist/components/ds-table.js.map +1 -1
- package/dist/components/ds-tag.js +1 -1
- package/dist/components/ds-tag.js.map +1 -1
- package/dist/components/ds-text.js +1 -1
- package/dist/components/ds-toggle.js +1 -1
- package/dist/components/ds-toggle.js.map +1 -1
- package/dist/components/ds-tooltip-data-viz.js +1 -1
- package/dist/components/ds-tooltip-data-viz.js.map +1 -1
- package/dist/components/ds-tooltip.js +1 -1
- package/dist/components/ds-tooltip.js.map +1 -1
- package/dist/components/p-1m8r0wFg.js +2 -0
- package/dist/components/p-1m8r0wFg.js.map +1 -0
- package/dist/components/p-3FLHei19.js +2 -0
- package/dist/components/p-3FLHei19.js.map +1 -0
- package/dist/components/p-B2_D4IDN.js +2 -0
- package/dist/components/p-B2_D4IDN.js.map +1 -0
- package/dist/components/p-B5NcWtpp.js +2 -0
- package/dist/components/p-B5NcWtpp.js.map +1 -0
- package/dist/components/{p-8Nt92j1-.js → p-B82KZX9D.js} +2 -2
- package/dist/components/p-BQq26pt9.js.map +1 -1
- package/dist/components/p-B_g8X0eh.js +2 -0
- package/dist/components/p-B_g8X0eh.js.map +1 -0
- package/dist/components/{p-DdFUTZ3y.js → p-Be3PHv34.js} +2 -2
- package/dist/components/p-CQmf2CeW.js +2 -0
- package/dist/components/p-CQmf2CeW.js.map +1 -0
- package/dist/components/{p-DOU4cbpc.js → p-CtwNUCnp.js} +2 -2
- package/dist/components/p-CuRjYmBk.js +2 -0
- package/dist/components/p-CuRjYmBk.js.map +1 -0
- package/dist/components/p-CwARVsZQ.js +2 -0
- package/dist/components/p-CwARVsZQ.js.map +1 -0
- package/dist/components/p-DohXlNCJ.js +2 -0
- package/dist/components/p-DohXlNCJ.js.map +1 -0
- package/dist/components/p-DuFm-ieS.js +2 -0
- package/dist/components/p-DuFm-ieS.js.map +1 -0
- package/dist/components/p-EK1hOP19.js.map +1 -1
- package/dist/lib/nav/index.js +3 -0
- package/dist/lib/nav/index.js.map +2 -2
- package/dist/lib/utils/control-width.d.ts +4 -0
- package/dist/lib/utils/index.d.ts +2 -0
- package/dist/lib/utils/index.js +20 -1
- package/dist/lib/utils/index.js.map +3 -3
- package/dist/lib/utils/token-defaults.d.ts +7 -0
- package/dist/types/components/ButtonFilled/ButtonFilled.d.ts +21 -3
- package/dist/types/components/ButtonFilled/index.d.ts +1 -1
- package/dist/types/components/ButtonUnfilled/ButtonUnfilled.d.ts +70 -0
- package/dist/types/components/ButtonUnfilled/index.d.ts +2 -0
- package/dist/types/components/Card/Card.d.ts +20 -0
- package/dist/types/components/Card/index.d.ts +2 -0
- package/dist/types/components/CardDataVizDonut/CardDataVizDonut.d.ts +26 -0
- package/dist/types/components/CardDataVizDonut/index.d.ts +2 -0
- package/dist/types/components/CardSetting/CardSetting.d.ts +7 -2
- package/dist/types/components/ChartDonut/ChartDonut.d.ts +31 -1
- package/dist/types/components/Checkbox/Checkbox.d.ts +1 -1
- package/dist/types/components/Chip/Chip.d.ts +18 -14
- package/dist/types/components/Chip/index.d.ts +1 -1
- package/dist/types/components/Input/Input.d.ts +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +1 -1
- package/dist/types/components/PanelNav/PanelNav.d.ts +2 -0
- package/dist/types/components/PanelTools/panel-tools-types.d.ts +1 -1
- package/dist/types/components/RadioGroup/RadioGroup.d.ts +2 -2
- package/dist/types/components/Select/Select.d.ts +34 -2
- package/dist/types/components/Select/index.d.ts +2 -0
- package/dist/types/components/ShellGradientSwatch/ShellGradientSwatch.d.ts +1 -1
- package/dist/types/components/Slider/Slider.d.ts +1 -1
- package/dist/types/components/TabGroup/TabGroup.d.ts +1 -1
- package/dist/types/components/TabGroup/tab-item-utils.d.ts +2 -1
- package/dist/types/components/TabGroupNav/TabGroupNav.d.ts +1 -1
- package/dist/types/components/Tag/Tag.d.ts +0 -2
- package/dist/types/components/Tag/index.d.ts +1 -1
- package/dist/types/components/Toggle/Toggle.d.ts +1 -1
- package/dist/types/components/Tooltip/Tooltip.d.ts +25 -6
- package/dist/types/components/TooltipDataViz/TooltipDataViz.d.ts +18 -0
- package/dist/types/components.d.ts +474 -576
- package/dist/types/utils/control-width.d.ts +5 -0
- package/dist/types/utils/index.d.ts +2 -0
- package/dist/types/utils/token-defaults.d.ts +7 -0
- package/package.json +7 -4
- package/src/angular/index.ts +3 -9
- package/src/angular/proxies.ts +62 -215
- package/src/react/components.ts +3 -9
- package/src/react/ds-button-unfilled.ts +33 -0
- package/src/react/ds-card-data-viz-donut.ts +27 -0
- package/src/react/{ds-fade.ts → ds-card.ts} +7 -7
- package/src/react/ds-chip.ts +2 -10
- package/src/wc/components/BarNav/BarNav.tsx +3 -2
- package/src/wc/components/BarNav/bar-nav-tabs-menu-utils.ts +1 -1
- package/src/wc/components/ButtonFilled/ButtonFilled.tsx +97 -11
- package/src/wc/components/ButtonFilled/index.ts +7 -1
- package/src/wc/components/ButtonUnfilled/ButtonUnfilled.tsx +230 -0
- package/src/wc/components/ButtonUnfilled/index.ts +7 -0
- package/src/wc/components/Card/Card.tsx +79 -0
- package/src/wc/components/Card/index.ts +1 -0
- package/src/wc/components/{CardDataViz/CardDataViz.tsx → CardDataVizDonut/CardDataVizDonut.tsx} +47 -41
- package/src/wc/components/CardDataVizDonut/index.ts +1 -0
- package/src/wc/components/CardSetting/CardSetting.tsx +21 -36
- package/src/wc/components/ChartDonut/ChartDonut.tsx +159 -11
- package/src/wc/components/ChartLegend/ChartLegend.tsx +3 -0
- package/src/wc/components/Checkbox/Checkbox.tsx +5 -5
- package/src/wc/components/Chip/Chip.tsx +50 -67
- package/src/wc/components/Chip/index.ts +1 -1
- package/src/wc/components/Input/Input.tsx +4 -4
- package/src/wc/components/Menu/Menu.tsx +7 -4
- package/src/wc/components/Pagination/Pagination.tsx +6 -6
- package/src/wc/components/PanelNav/PanelNav.tsx +77 -48
- package/src/wc/components/PanelTools/PanelTools.tsx +19 -16
- package/src/wc/components/PanelTools/panel-tools-types.ts +1 -1
- package/src/wc/components/PanelTools/panel-tools-utils.ts +1 -1
- package/src/wc/components/RadioGroup/RadioGroup.tsx +7 -7
- package/src/wc/components/Select/Select.tsx +145 -64
- package/src/wc/components/Select/index.ts +1 -0
- package/src/wc/components/ShellGradientSwatch/ShellGradientSwatch.tsx +4 -3
- package/src/wc/components/Slider/Slider.tsx +7 -3
- package/src/wc/components/TabGroup/TabGroup.tsx +13 -7
- package/src/wc/components/TabGroup/tab-item-utils.ts +2 -1
- package/src/wc/components/TabGroupNav/TabGroupNav.tsx +14 -13
- package/src/wc/components/Tag/Tag.tsx +25 -24
- package/src/wc/components/Tag/index.ts +1 -1
- package/src/wc/components/Toggle/Toggle.tsx +6 -6
- package/src/wc/components/Tooltip/Tooltip.tsx +166 -64
- package/src/wc/components/TooltipDataViz/TooltipDataViz.tsx +57 -2
- package/src/wc/components.d.ts +474 -579
- package/src/wc/utils/control-density.css +42 -0
- package/src/wc/utils/control-inactive.css +20 -0
- package/src/wc/utils/control-width.css +28 -0
- package/src/wc/utils/control-width.ts +10 -0
- package/src/wc/utils/index.ts +2 -0
- package/src/wc/utils/interaction-fill.css +162 -0
- package/src/wc/utils/scroll-edge-fade.css +5 -0
- package/src/wc/utils/token-defaults.ts +10 -0
- package/dist/components/ds-accordion.js +0 -2
- package/dist/components/ds-accordion.js.map +0 -1
- package/dist/components/ds-breadcrumb.d.ts +0 -11
- package/dist/components/ds-breadcrumb.js +0 -2
- package/dist/components/ds-breadcrumb.js.map +0 -1
- package/dist/components/ds-button-unfilled-icon.d.ts +0 -11
- package/dist/components/ds-button-unfilled-icon.js +0 -2
- package/dist/components/ds-card-data-viz.js +0 -2
- package/dist/components/ds-card-data-viz.js.map +0 -1
- package/dist/components/ds-fade.js +0 -2
- package/dist/components/ds-fade.js.map +0 -1
- package/dist/components/ds-header.d.ts +0 -11
- package/dist/components/ds-header.js +0 -2
- package/dist/components/ds-header.js.map +0 -1
- package/dist/components/ds-scrollbar.d.ts +0 -11
- package/dist/components/ds-scrollbar.js +0 -2
- package/dist/components/ds-scrollbar.js.map +0 -1
- package/dist/components/ds-surface.d.ts +0 -11
- package/dist/components/ds-surface.js +0 -2
- package/dist/components/ds-surface.js.map +0 -1
- package/dist/components/ds-toast-provider.d.ts +0 -11
- package/dist/components/ds-toast-provider.js +0 -2
- package/dist/components/ds-toast-provider.js.map +0 -1
- package/dist/components/p-BMQbEIrQ.js +0 -2
- package/dist/components/p-BMQbEIrQ.js.map +0 -1
- package/dist/components/p-BSFgy5r6.js +0 -2
- package/dist/components/p-BSFgy5r6.js.map +0 -1
- package/dist/components/p-CBUIn8dk.js +0 -2
- package/dist/components/p-CBUIn8dk.js.map +0 -1
- package/dist/components/p-ChVwCVHy.js +0 -2
- package/dist/components/p-ChVwCVHy.js.map +0 -1
- package/dist/components/p-CpNIQXz6.js +0 -2
- package/dist/components/p-CpNIQXz6.js.map +0 -1
- package/dist/components/p-CvgHQfvT.js +0 -2
- package/dist/components/p-CvgHQfvT.js.map +0 -1
- package/dist/components/p-bDf6yBQd.js +0 -2
- package/dist/components/p-bDf6yBQd.js.map +0 -1
- package/dist/types/components/Accordion/Accordion.d.ts +0 -28
- package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +0 -16
- package/dist/types/components/ButtonUnfilledIcon/ButtonUnfilledIcon.d.ts +0 -45
- package/dist/types/components/ButtonUnfilledIcon/index.d.ts +0 -2
- package/dist/types/components/CardDataViz/CardDataViz.d.ts +0 -22
- package/dist/types/components/CardDataViz/index.d.ts +0 -2
- package/dist/types/components/Fade/Fade.d.ts +0 -22
- package/dist/types/components/Fade/index.d.ts +0 -2
- package/dist/types/components/Header/Header.d.ts +0 -7
- package/dist/types/components/Scrollbar/Scrollbar.d.ts +0 -27
- package/dist/types/components/Surface/Surface.d.ts +0 -22
- package/dist/types/components/Toast/Toast.d.ts +0 -16
- package/dist/types/components/Toast/toast-service.d.ts +0 -24
- package/src/react/ds-accordion.ts +0 -27
- package/src/react/ds-breadcrumb.ts +0 -27
- package/src/react/ds-button-unfilled-icon.ts +0 -33
- package/src/react/ds-card-data-viz.ts +0 -26
- package/src/react/ds-header.ts +0 -26
- package/src/react/ds-scrollbar.ts +0 -26
- package/src/react/ds-surface.ts +0 -26
- package/src/react/ds-toast-provider.ts +0 -26
- package/src/wc/components/Accordion/Accordion.tsx +0 -144
- package/src/wc/components/Breadcrumb/Breadcrumb.tsx +0 -61
- package/src/wc/components/ButtonUnfilledIcon/ButtonUnfilledIcon.tsx +0 -129
- package/src/wc/components/ButtonUnfilledIcon/index.ts +0 -1
- package/src/wc/components/CardDataViz/index.ts +0 -1
- package/src/wc/components/Fade/Fade.tsx +0 -58
- package/src/wc/components/Fade/index.ts +0 -1
- package/src/wc/components/Header/Header.tsx +0 -33
- package/src/wc/components/Scrollbar/Scrollbar.tsx +0 -189
- package/src/wc/components/Surface/Surface.tsx +0 -81
- package/src/wc/components/Toast/Toast.tsx +0 -179
- package/src/wc/components/Toast/toast-service.ts +0 -67
- /package/dist/components/{ds-button-unfilled-icon.js.map → ds-button-unfilled.js.map} +0 -0
- /package/dist/components/{p-8Nt92j1-.js.map → p-B82KZX9D.js.map} +0 -0
- /package/dist/components/{p-DdFUTZ3y.js.map → p-Be3PHv34.js.map} +0 -0
- /package/dist/components/{p-DOU4cbpc.js.map → p-CtwNUCnp.js.map} +0 -0
package/src/wc/components/{CardDataViz/CardDataViz.tsx → CardDataVizDonut/CardDataVizDonut.tsx}
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Component, Element, State, h, Host, Prop } from '@stencil/core';
|
|
1
|
+
import { Component, Element, Event, EventEmitter, State, h, Host, Prop } from '@stencil/core';
|
|
2
|
+
import type { CardWidth } from '../Card/Card';
|
|
2
3
|
|
|
3
|
-
export type
|
|
4
|
+
export type CardDataVizDonutWidth = CardWidth;
|
|
4
5
|
|
|
5
6
|
/** Matches the `dsSliceHover`/`dsItemHover` detail shape emitted by `ds-chart-*` and `ds-chart-legend`. */
|
|
6
7
|
type HoveredDatum = { label: string } | null;
|
|
@@ -8,31 +9,26 @@ type HoveredDatum = { label: string } | null;
|
|
|
8
9
|
/** A slotted chart/legend that opts into hover sync by exposing an `activeLabel` prop. */
|
|
9
10
|
type SyncableSlot = HTMLElement & { activeLabel?: string | null };
|
|
10
11
|
|
|
11
|
-
const CARD_WIDTH_VARS: Record<CardDataVizWidth, string> = {
|
|
12
|
-
xs: 'var(--dimension-card-width-xs)',
|
|
13
|
-
sm: 'var(--dimension-card-width-sm)',
|
|
14
|
-
md: 'var(--dimension-card-width-md)',
|
|
15
|
-
lg: 'var(--dimension-card-width-lg)',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
12
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* once the data-viz card's real header actions (menu, caption, footer stat) are designed.
|
|
13
|
+
* Donut data-viz card — shared `ds-card` chrome with a fill chart region and
|
|
14
|
+
* content-sized legend. Hover sync between chart and legend stays here.
|
|
22
15
|
*/
|
|
23
16
|
@Component({
|
|
24
|
-
tag: 'ds-card-data-viz',
|
|
25
|
-
styleUrl: '
|
|
17
|
+
tag: 'ds-card-data-viz-donut',
|
|
18
|
+
styleUrl: 'CardDataVizDonut.css',
|
|
26
19
|
scoped: true,
|
|
27
20
|
})
|
|
28
|
-
export class
|
|
21
|
+
export class CardDataVizDonut {
|
|
29
22
|
@Element() el!: HTMLElement;
|
|
30
23
|
|
|
31
24
|
/** Widget heading shown in the card header. */
|
|
32
25
|
@Prop() heading!: string;
|
|
33
26
|
|
|
34
|
-
/** Card width token. */
|
|
35
|
-
@Prop() cardWidth:
|
|
27
|
+
/** Card width token — also sets matching min-height. */
|
|
28
|
+
@Prop() cardWidth: CardDataVizDonutWidth = 'md';
|
|
29
|
+
|
|
30
|
+
/** Emits when the header filter control is activated. */
|
|
31
|
+
@Event() dsFilterClick!: EventEmitter<void>;
|
|
36
32
|
|
|
37
33
|
// Scoped (light-DOM) components have no native slot projection to detect emptiness from CSS —
|
|
38
34
|
// check the actual children so an unused region (e.g. no legend) doesn't render a dangling
|
|
@@ -41,13 +37,16 @@ export class CardDataViz {
|
|
|
41
37
|
@State() private hasLegendSlot = false;
|
|
42
38
|
|
|
43
39
|
componentWillRender() {
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
// Not `:scope >` — Stencil's scoped slot polyfill relocates slotted children into
|
|
41
|
+
// region wrappers (and here into nested `ds-card`), so they may not stay direct
|
|
42
|
+
// host children across renders.
|
|
43
|
+
this.hasChartSlot = !!this.el.querySelector('[slot="chart"]');
|
|
44
|
+
this.hasLegendSlot = !!this.el.querySelector('[slot="legend"]');
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
componentDidLoad() {
|
|
49
48
|
// Sync the chart's and legend's `activeLabel` from each other's hover events, so any
|
|
50
|
-
// ds-chart
|
|
49
|
+
// ds-chart-donut + ds-chart-legend pair cross-highlights without every consumer having to
|
|
51
50
|
// wire it up by hand. Delegated on the host (rather than bound to the specific slotted
|
|
52
51
|
// elements) since Stencil events bubble and the slot content can be swapped at runtime.
|
|
53
52
|
this.el.addEventListener('dsSliceHover', this.handleChartHover);
|
|
@@ -61,8 +60,8 @@ export class CardDataViz {
|
|
|
61
60
|
|
|
62
61
|
private handleChartHover = (e: Event) => {
|
|
63
62
|
// Not `:scope >` — Stencil's slot polyfill for scoped (non-shadow) components relocates
|
|
64
|
-
// slotted children into an inner
|
|
65
|
-
//
|
|
63
|
+
// slotted children into an inner region wrapper on render, so they're no longer direct
|
|
64
|
+
// children of the host by the time this fires.
|
|
66
65
|
const legend = this.el.querySelector('[slot="legend"]') as SyncableSlot | null;
|
|
67
66
|
if (!legend || !('activeLabel' in legend)) return;
|
|
68
67
|
legend.activeLabel = (e as CustomEvent<HoveredDatum>).detail?.label ?? null;
|
|
@@ -74,28 +73,35 @@ export class CardDataViz {
|
|
|
74
73
|
chart.activeLabel = (e as CustomEvent<HoveredDatum>).detail?.label ?? null;
|
|
75
74
|
};
|
|
76
75
|
|
|
76
|
+
private handleFilterClick = () => {
|
|
77
|
+
this.dsFilterClick.emit();
|
|
78
|
+
};
|
|
79
|
+
|
|
77
80
|
render() {
|
|
78
81
|
return (
|
|
79
|
-
<Host class="card-data-viz"
|
|
80
|
-
<
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
<Host class="card-data-viz-donut">
|
|
83
|
+
<ds-card heading={this.heading} cardWidth={this.cardWidth}>
|
|
84
|
+
<ds-button-unfilled
|
|
85
|
+
slot="actions"
|
|
86
|
+
variant="icon"
|
|
87
|
+
type="button"
|
|
88
|
+
icon="Filters"
|
|
89
|
+
aria-label="Filter"
|
|
90
|
+
onDsClick={this.handleFilterClick}
|
|
91
|
+
/>
|
|
92
|
+
<div class="card-data-viz-donut__layout">
|
|
93
|
+
{this.hasChartSlot && (
|
|
94
|
+
<div class="card-data-viz-donut__chart-region">
|
|
95
|
+
<slot name="chart" />
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
{this.hasLegendSlot && (
|
|
99
|
+
<div class="card-data-viz-donut__legend-region">
|
|
100
|
+
<slot name="legend" />
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
85
103
|
</div>
|
|
86
|
-
</
|
|
87
|
-
<div class="card-data-viz__body">
|
|
88
|
-
{this.hasChartSlot && (
|
|
89
|
-
<div class="card-data-viz__chart-region">
|
|
90
|
-
<slot name="chart" />
|
|
91
|
-
</div>
|
|
92
|
-
)}
|
|
93
|
-
{this.hasLegendSlot && (
|
|
94
|
-
<div class="card-data-viz__legend-region">
|
|
95
|
-
<slot name="legend" />
|
|
96
|
-
</div>
|
|
97
|
-
)}
|
|
98
|
-
</div>
|
|
104
|
+
</ds-card>
|
|
99
105
|
</Host>
|
|
100
106
|
);
|
|
101
107
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { CardDataVizDonutWidth } from './CardDataVizDonut';
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core';
|
|
2
|
+
import type { CardWidth } from '../Card/Card';
|
|
2
3
|
|
|
3
|
-
export type CardSettingWidth =
|
|
4
|
-
|
|
5
|
-
const CARD_WIDTH_VARS: Record<CardSettingWidth, string> = {
|
|
6
|
-
xs: 'var(--dimension-card-width-xs)',
|
|
7
|
-
sm: 'var(--dimension-card-width-sm)',
|
|
8
|
-
md: 'var(--dimension-card-width-md)',
|
|
9
|
-
lg: 'var(--dimension-card-width-lg)',
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const FAINT_BRAND_TITLE_COLOR = 'var(--color-foreground-faint-brand)';
|
|
4
|
+
export type CardSettingWidth = CardWidth;
|
|
13
5
|
|
|
14
6
|
@Component({
|
|
15
7
|
tag: 'ds-card-setting',
|
|
@@ -20,7 +12,11 @@ export class CardSetting {
|
|
|
20
12
|
/** Section heading shown in the card header. */
|
|
21
13
|
@Prop() heading!: string;
|
|
22
14
|
|
|
23
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Card width token (`sm` / `md` / `lg`). Also sets host `min-height` to the
|
|
17
|
+
* matching `--dimension-card-height-*` so the body fills available space
|
|
18
|
+
* even when the slot is empty.
|
|
19
|
+
*/
|
|
24
20
|
@Prop() cardWidth: CardSettingWidth = 'md';
|
|
25
21
|
|
|
26
22
|
/** Controlled edit state — parent owns single-edit orchestration. */
|
|
@@ -41,42 +37,33 @@ export class CardSetting {
|
|
|
41
37
|
const editing = this.editing;
|
|
42
38
|
|
|
43
39
|
return (
|
|
44
|
-
<Host
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
>
|
|
51
|
-
<header class="card-setting__header">
|
|
52
|
-
<div class="card-setting__title-wrap">
|
|
53
|
-
<ds-text
|
|
54
|
-
class="card-setting__title"
|
|
55
|
-
variant="text-title-small"
|
|
56
|
-
color={editing ? FAINT_BRAND_TITLE_COLOR : 'primary'}
|
|
57
|
-
as="h2"
|
|
58
|
-
>
|
|
59
|
-
{this.heading}
|
|
60
|
-
</ds-text>
|
|
61
|
-
</div>
|
|
40
|
+
<Host class="card-setting">
|
|
41
|
+
<ds-card
|
|
42
|
+
heading={this.heading}
|
|
43
|
+
cardWidth={this.cardWidth}
|
|
44
|
+
appearance={editing ? 'editing' : 'default'}
|
|
45
|
+
>
|
|
62
46
|
{!editing ? (
|
|
63
|
-
<ds-button-unfilled
|
|
47
|
+
<ds-button-unfilled
|
|
48
|
+
slot="actions"
|
|
49
|
+
variant="icon"
|
|
64
50
|
type="button"
|
|
65
51
|
icon="Pencil"
|
|
66
52
|
aria-label="Edit"
|
|
67
53
|
onDsClick={this.enterEdit}
|
|
68
54
|
/>
|
|
69
55
|
) : (
|
|
70
|
-
<div class="card-setting__actions">
|
|
71
|
-
<ds-button-unfilled
|
|
56
|
+
<div slot="actions" class="card-setting__actions">
|
|
57
|
+
<ds-button-unfilled
|
|
58
|
+
variant="icon"
|
|
72
59
|
type="button"
|
|
73
60
|
icon="Cross"
|
|
74
61
|
backgroundContrast="bold"
|
|
75
|
-
has-border
|
|
76
62
|
aria-label="Cancel"
|
|
77
63
|
onDsClick={this.exitEdit}
|
|
78
64
|
/>
|
|
79
65
|
<ds-button-filled
|
|
66
|
+
variant="icon"
|
|
80
67
|
type="button"
|
|
81
68
|
icon="Check"
|
|
82
69
|
intent="brand"
|
|
@@ -86,10 +73,8 @@ export class CardSetting {
|
|
|
86
73
|
/>
|
|
87
74
|
</div>
|
|
88
75
|
)}
|
|
89
|
-
</header>
|
|
90
|
-
<div class="card-setting__body">
|
|
91
76
|
<slot />
|
|
92
|
-
</
|
|
77
|
+
</ds-card>
|
|
93
78
|
</Host>
|
|
94
79
|
);
|
|
95
80
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component, Prop, State, Event, EventEmitter, h, Host } from '@stencil/core';
|
|
1
|
+
import { Component, Prop, State, Event, EventEmitter, Element, Watch, h, Host } from '@stencil/core';
|
|
2
2
|
import { arc, pie } from 'd3-shape';
|
|
3
3
|
import { categoryColor } from '../../utils/chart-colors';
|
|
4
4
|
import { formatCompactNumber, resolveCssLengthPx, truncateSvgTextToWidth, TOKEN_DEFAULTS } from '../../utils';
|
|
@@ -9,6 +9,14 @@ const DIMMED_OPACITY = 0.25;
|
|
|
9
9
|
const CENTER_GAP_PX = 0;
|
|
10
10
|
/** Fraction of the inner-circle diameter center text is allowed to use before truncating. */
|
|
11
11
|
const CENTER_TEXT_SAFE_WIDTH_RATIO = 0.82;
|
|
12
|
+
/** Fallback when filling before the first ResizeObserver measurement (matches fill min). */
|
|
13
|
+
const FILL_FALLBACK_PX = 128;
|
|
14
|
+
|
|
15
|
+
type DonutTooltipState = {
|
|
16
|
+
datum: ChartDatum;
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
};
|
|
12
20
|
|
|
13
21
|
@Component({
|
|
14
22
|
tag: 'ds-chart-donut',
|
|
@@ -16,9 +24,17 @@ const CENTER_TEXT_SAFE_WIDTH_RATIO = 0.82;
|
|
|
16
24
|
scoped: true,
|
|
17
25
|
})
|
|
18
26
|
export class ChartDonut {
|
|
27
|
+
@Element() el!: HTMLElement;
|
|
28
|
+
|
|
19
29
|
/** Slices to render. Set as a JS property (not an HTML attribute). */
|
|
20
30
|
@Prop() data: ChartDatum[] = [];
|
|
21
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Explicit diameter in px. When unset, the donut sizes to its container
|
|
33
|
+
* (ResizeObserver) clamped between `--dimension-size-base * 16` (128px) and
|
|
34
|
+
* `* 24` (192px), and stays centered in the leftover space. Prefer unset
|
|
35
|
+
* inside card layouts.
|
|
36
|
+
*/
|
|
37
|
+
@Prop() size: number | undefined;
|
|
22
38
|
/** Ring thickness — number (px) or TokoMo length. Defaults to `--dimension-size-200` (16px). */
|
|
23
39
|
@Prop() thickness: number | string = TOKEN_DEFAULTS.size200;
|
|
24
40
|
/** Corner radius on each slice — number (px) or TokoMo length. Defaults to `--dimension-radius-025` (2px). */
|
|
@@ -33,27 +49,133 @@ export class ChartDonut {
|
|
|
33
49
|
* Externally controlled highlight, matched by `label` — e.g. drive this from a sibling
|
|
34
50
|
* `ds-chart-legend`'s `dsItemHover` event to keep chart and legend hover in sync.
|
|
35
51
|
* Falls back to this component's own pointer/focus hover when unset.
|
|
52
|
+
* External sync dims slices only — the data-viz tooltip is reserved for this
|
|
53
|
+
* component's own pointer/keyboard interaction.
|
|
36
54
|
*/
|
|
37
55
|
@Prop() activeLabel: string | null = null;
|
|
38
56
|
|
|
39
57
|
@State() private hoveredLabel: string | null = null;
|
|
58
|
+
/** Own-hover tooltip (cursor-following). Cleared on leave; not driven by `activeLabel`. */
|
|
59
|
+
@State() private tooltip: DonutTooltipState | null = null;
|
|
40
60
|
/** Center text, truncated with an ellipsis if it doesn't fit inside the inner circle. */
|
|
41
61
|
@State() private displayedValueText: string = '';
|
|
42
62
|
@State() private displayedCaptionText: string = '';
|
|
63
|
+
/** Measured fill diameter when `size` is unset. */
|
|
64
|
+
@State() private measuredSize: number = FILL_FALLBACK_PX;
|
|
43
65
|
|
|
44
66
|
/** Fires with the hovered/focused slice's datum, or `null` on leave/blur. */
|
|
45
67
|
@Event() dsSliceHover!: EventEmitter<ChartDatum | null>;
|
|
46
68
|
|
|
47
69
|
private valueTextEl?: SVGTextElement;
|
|
48
70
|
private captionTextEl?: SVGTextElement;
|
|
71
|
+
private wrapperEl?: HTMLDivElement;
|
|
72
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
73
|
+
|
|
74
|
+
private get isFillMode(): boolean {
|
|
75
|
+
return this.size == null || !Number.isFinite(this.size) || this.size <= 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private get fillMinPx(): number {
|
|
79
|
+
return resolveCssLengthPx(TOKEN_DEFAULTS.donutFillMin, FILL_FALLBACK_PX);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private get fillMaxPx(): number {
|
|
83
|
+
return resolveCssLengthPx(TOKEN_DEFAULTS.donutFillMax, 192);
|
|
84
|
+
}
|
|
49
85
|
|
|
50
|
-
|
|
86
|
+
/** Clamp available square side into the fill min/max band. */
|
|
87
|
+
private clampFillSize(availablePx: number): number {
|
|
88
|
+
const minPx = this.fillMinPx;
|
|
89
|
+
const maxPx = this.fillMaxPx;
|
|
90
|
+
if (!(availablePx > 0)) return minPx;
|
|
91
|
+
return Math.round(Math.min(maxPx, Math.max(minPx, availablePx)));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private get resolvedSize(): number {
|
|
95
|
+
if (!this.isFillMode) return this.size as number;
|
|
96
|
+
return this.clampFillSize(this.measuredSize);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
componentDidLoad() {
|
|
100
|
+
this.syncResizeObserver();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@Watch('size')
|
|
104
|
+
onSizePropChange() {
|
|
105
|
+
this.syncResizeObserver();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
disconnectedCallback() {
|
|
109
|
+
this.teardownResizeObserver();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private syncResizeObserver() {
|
|
113
|
+
this.teardownResizeObserver();
|
|
114
|
+
if (!this.isFillMode) return;
|
|
115
|
+
// Observe the host (which fills its parent), not the wrapper — the wrapper
|
|
116
|
+
// only wraps the SVG and would collapse to the clamped size, locking fill at min.
|
|
117
|
+
const target = this.el;
|
|
118
|
+
if (!target || typeof ResizeObserver === 'undefined') return;
|
|
119
|
+
|
|
120
|
+
this.resizeObserver = new ResizeObserver(entries => {
|
|
121
|
+
const entry = entries[0];
|
|
122
|
+
if (!entry) return;
|
|
123
|
+
this.applyAvailableSize(entry.contentRect.width, entry.contentRect.height);
|
|
124
|
+
});
|
|
125
|
+
this.resizeObserver.observe(target);
|
|
126
|
+
this.measureHost();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private measureHost() {
|
|
130
|
+
const rect = this.el.getBoundingClientRect();
|
|
131
|
+
this.applyAvailableSize(rect.width, rect.height);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private applyAvailableSize(width: number, height: number) {
|
|
135
|
+
const available = Math.floor(Math.min(width, height));
|
|
136
|
+
if (available > 0 && available !== this.measuredSize) {
|
|
137
|
+
this.measuredSize = available;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private teardownResizeObserver() {
|
|
142
|
+
this.resizeObserver?.disconnect();
|
|
143
|
+
this.resizeObserver = null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private handleHover(datum: ChartDatum | null, event?: MouseEvent) {
|
|
51
147
|
this.hoveredLabel = datum?.label ?? null;
|
|
52
148
|
this.dsSliceHover.emit(datum);
|
|
149
|
+
if (!datum) {
|
|
150
|
+
this.tooltip = null;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.updateTooltip(datum, event);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private handleSliceMove(datum: ChartDatum, event: MouseEvent) {
|
|
157
|
+
if (this.hoveredLabel !== datum.label) return;
|
|
158
|
+
this.updateTooltip(datum, event);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private updateTooltip(datum: ChartDatum, event?: MouseEvent) {
|
|
162
|
+
const wrapper = this.wrapperEl;
|
|
163
|
+
if (!wrapper) return;
|
|
164
|
+
const size = this.resolvedSize;
|
|
165
|
+
const rect = wrapper.getBoundingClientRect();
|
|
166
|
+
const x = event ? event.clientX - rect.left : size / 2;
|
|
167
|
+
const y = event ? event.clientY - rect.top : size / 2;
|
|
168
|
+
this.tooltip = { datum, x, y };
|
|
53
169
|
}
|
|
54
170
|
|
|
55
171
|
componentDidRender() {
|
|
56
|
-
|
|
172
|
+
// Re-bind after HMR when DidLoad's observer was dropped.
|
|
173
|
+
if (this.isFillMode && !this.resizeObserver) {
|
|
174
|
+
this.syncResizeObserver();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const size = this.resolvedSize;
|
|
178
|
+
const radius = size / 2;
|
|
57
179
|
const thicknessPx = resolveCssLengthPx(this.thickness, TOKEN_DEFAULTS.size200);
|
|
58
180
|
const innerRadius = radius - thicknessPx;
|
|
59
181
|
const maxWidth = innerRadius * 2 * CENTER_TEXT_SAFE_WIDTH_RATIO;
|
|
@@ -75,7 +197,8 @@ export class ChartDonut {
|
|
|
75
197
|
}
|
|
76
198
|
|
|
77
199
|
render() {
|
|
78
|
-
const
|
|
200
|
+
const size = this.resolvedSize;
|
|
201
|
+
const radius = size / 2;
|
|
79
202
|
const thicknessPx = resolveCssLengthPx(this.thickness, TOKEN_DEFAULTS.size200);
|
|
80
203
|
const cornerRadiusPx = resolveCssLengthPx(this.cornerRadius, TOKEN_DEFAULTS.radius025);
|
|
81
204
|
const innerRadius = radius - thicknessPx;
|
|
@@ -115,15 +238,30 @@ export class ChartDonut {
|
|
|
115
238
|
// Show the full text before the post-render truncation pass has measured it (avoids a blank first paint).
|
|
116
239
|
const fullValueText = this.centerValue ?? formatCompactNumber(total);
|
|
117
240
|
const fullCaptionText = this.centerCaption ?? '';
|
|
241
|
+
const tip = this.tooltip;
|
|
242
|
+
const fill = this.isFillMode;
|
|
118
243
|
|
|
119
244
|
return (
|
|
120
|
-
<Host
|
|
121
|
-
|
|
245
|
+
<Host
|
|
246
|
+
class={{
|
|
247
|
+
'chart-donut': true,
|
|
248
|
+
'chart-donut--fill': fill,
|
|
249
|
+
'chart-donut--fixed': !fill,
|
|
250
|
+
}}
|
|
251
|
+
style={!fill ? { width: `${size}px`, height: `${size}px` } : undefined}
|
|
252
|
+
>
|
|
253
|
+
<div
|
|
254
|
+
class="chart-donut__wrapper"
|
|
255
|
+
style={!fill ? { width: `${size}px`, height: `${size}px` } : undefined}
|
|
256
|
+
ref={el => {
|
|
257
|
+
this.wrapperEl = (el as HTMLDivElement) ?? undefined;
|
|
258
|
+
}}
|
|
259
|
+
>
|
|
122
260
|
<svg
|
|
123
261
|
class="chart-donut__svg"
|
|
124
|
-
viewBox={`0 0 ${
|
|
125
|
-
width={
|
|
126
|
-
height={
|
|
262
|
+
viewBox={`0 0 ${size} ${size}`}
|
|
263
|
+
width={size}
|
|
264
|
+
height={size}
|
|
127
265
|
>
|
|
128
266
|
<g transform={`translate(${radius}, ${radius})`}>
|
|
129
267
|
{isEmpty ? (
|
|
@@ -141,7 +279,8 @@ export class ChartDonut {
|
|
|
141
279
|
tabindex={0}
|
|
142
280
|
role="img"
|
|
143
281
|
aria-label={`${datum.label}: ${datum.value}`}
|
|
144
|
-
onMouseEnter={() => this.handleHover(datum)}
|
|
282
|
+
onMouseEnter={(e: MouseEvent) => this.handleHover(datum, e)}
|
|
283
|
+
onMouseMove={(e: MouseEvent) => this.handleSliceMove(datum, e)}
|
|
145
284
|
onMouseLeave={() => this.handleHover(null)}
|
|
146
285
|
onFocus={() => this.handleHover(datum)}
|
|
147
286
|
onBlur={() => this.handleHover(null)}
|
|
@@ -177,6 +316,15 @@ export class ChartDonut {
|
|
|
177
316
|
</text>
|
|
178
317
|
)}
|
|
179
318
|
</svg>
|
|
319
|
+
{tip && (
|
|
320
|
+
<ds-tooltip-data-viz
|
|
321
|
+
key={tip.datum.label}
|
|
322
|
+
label={tip.datum.label}
|
|
323
|
+
value={formatCompactNumber(tip.datum.value)}
|
|
324
|
+
x={tip.x}
|
|
325
|
+
y={tip.y}
|
|
326
|
+
/>
|
|
327
|
+
)}
|
|
180
328
|
</div>
|
|
181
329
|
</Host>
|
|
182
330
|
);
|
|
@@ -73,6 +73,9 @@ export class ChartLegend {
|
|
|
73
73
|
class={{
|
|
74
74
|
'chart-legend__item': true,
|
|
75
75
|
'chart-legend__item--interactive': !!item.href,
|
|
76
|
+
'ds-control--md': true,
|
|
77
|
+
'ds-interaction-fill': true,
|
|
78
|
+
'ds-focus-ring-inset': !!item.href,
|
|
76
79
|
}}
|
|
77
80
|
style={{ opacity: isDimmed ? String(DIMMED_OPACITY) : '1' }}
|
|
78
81
|
href={item.href}
|
|
@@ -13,12 +13,12 @@ export class Checkbox {
|
|
|
13
13
|
@Prop() label!: string;
|
|
14
14
|
@Prop({ mutable: true }) checked: boolean = false;
|
|
15
15
|
@Prop() indeterminate: boolean = false;
|
|
16
|
-
@Prop()
|
|
16
|
+
@Prop() isInactive: boolean = false;
|
|
17
17
|
|
|
18
18
|
@Event() dsChange!: EventEmitter<boolean>;
|
|
19
19
|
|
|
20
20
|
private handleActivate = () => {
|
|
21
|
-
if (this.
|
|
21
|
+
if (this.isInactive) return;
|
|
22
22
|
this.checked = !this.checked;
|
|
23
23
|
this.dsChange.emit(this.checked);
|
|
24
24
|
};
|
|
@@ -37,10 +37,10 @@ export class Checkbox {
|
|
|
37
37
|
<Host
|
|
38
38
|
role="checkbox"
|
|
39
39
|
aria-checked={this.indeterminate ? 'mixed' : String(this.checked)}
|
|
40
|
-
aria-disabled={this.
|
|
40
|
+
aria-disabled={this.isInactive || undefined}
|
|
41
41
|
aria-labelledby={this.labelId}
|
|
42
|
-
tabIndex={this.
|
|
43
|
-
class={{ checkbox: true, inactive: this.
|
|
42
|
+
tabIndex={this.isInactive ? -1 : 0}
|
|
43
|
+
class={{ checkbox: true, 'ds-control-inactive': this.isInactive }}
|
|
44
44
|
onClick={this.handleActivate}
|
|
45
45
|
onKeyDown={this.handleKeyDown}
|
|
46
46
|
>
|