@juspay/svelte-ui-components 2.75.0 → 2.76.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/dist/BarChart/BarChart.svelte +163 -48
- package/dist/BarChart/properties.d.ts +41 -0
- package/dist/DeltaIndicator/DeltaIndicator.svelte +87 -0
- package/dist/DeltaIndicator/DeltaIndicator.svelte.d.ts +4 -0
- package/dist/DeltaIndicator/properties.d.ts +26 -0
- package/dist/DeltaIndicator/properties.js +1 -0
- package/dist/DualAxisBarChart/DualAxisBarChart.svelte +521 -0
- package/dist/DualAxisBarChart/DualAxisBarChart.svelte.d.ts +4 -0
- package/dist/DualAxisBarChart/properties.d.ts +108 -0
- package/dist/DualAxisBarChart/properties.js +1 -0
- package/dist/FunnelChart/FunnelChart.svelte +335 -0
- package/dist/FunnelChart/FunnelChart.svelte.d.ts +4 -0
- package/dist/FunnelChart/properties.d.ts +69 -0
- package/dist/FunnelChart/properties.js +1 -0
- package/dist/LineChart/LineChart.svelte +190 -42
- package/dist/LineChart/properties.d.ts +69 -0
- package/dist/PieChart/PieChart.svelte +52 -20
- package/dist/PieChart/properties.d.ts +26 -0
- package/dist/SankeyChart/SankeyChart.svelte +15 -5
- package/dist/SankeyChart/properties.d.ts +19 -0
- package/dist/_chart/geometry.d.ts +1 -1
- package/dist/_chart/geometry.js +5 -4
- package/dist/_chart/highlight.d.ts +15 -0
- package/dist/_chart/highlight.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +3 -0
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
2
3
|
import type {
|
|
3
4
|
BarChartProperties,
|
|
4
5
|
BarChartRenderContext,
|
|
@@ -6,6 +7,7 @@
|
|
|
6
7
|
BarFillGradient,
|
|
7
8
|
BarFillPattern
|
|
8
9
|
} from './properties';
|
|
10
|
+
import type { ChartHighlightAPI } from '../_chart/highlight';
|
|
9
11
|
import ChartContainer from '../_chart/ChartContainer.svelte';
|
|
10
12
|
import Axis from '../_chart/Axis.svelte';
|
|
11
13
|
import ChartTooltip from '../_chart/ChartTooltip.svelte';
|
|
@@ -62,6 +64,12 @@
|
|
|
62
64
|
tooltipSnippet,
|
|
63
65
|
empty,
|
|
64
66
|
renderOverlay,
|
|
67
|
+
onChartReady,
|
|
68
|
+
highlightedIndex = null,
|
|
69
|
+
normaliseToFirstPoint = false,
|
|
70
|
+
topN,
|
|
71
|
+
overflowLabel = 'Other',
|
|
72
|
+
hideBarGraphics = false,
|
|
65
73
|
onbarclick,
|
|
66
74
|
onbarhover,
|
|
67
75
|
testId,
|
|
@@ -76,6 +84,24 @@
|
|
|
76
84
|
let hovered = $state<{ si: number; pi: number } | null>(null);
|
|
77
85
|
let mouseX = $state(0);
|
|
78
86
|
let mouseY = $state(0);
|
|
87
|
+
/** Internal tracking for the imperative highlight API (onChartReady). */
|
|
88
|
+
let apiHighlightedIndex = $state<number | null>(null);
|
|
89
|
+
|
|
90
|
+
// ── onMount: emit ChartHighlightAPI via onChartReady ──────────
|
|
91
|
+
|
|
92
|
+
onMount(() => {
|
|
93
|
+
if (typeof onChartReady !== 'function') {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const api: ChartHighlightAPI = {
|
|
97
|
+
highlight: (index) => {
|
|
98
|
+
apiHighlightedIndex = index;
|
|
99
|
+
},
|
|
100
|
+
getCategories: () => labels,
|
|
101
|
+
type: 'bar-chart'
|
|
102
|
+
};
|
|
103
|
+
onChartReady(api);
|
|
104
|
+
});
|
|
79
105
|
|
|
80
106
|
// ── Layout ─────────────────────────────────────────────────────
|
|
81
107
|
|
|
@@ -84,13 +110,91 @@
|
|
|
84
110
|
let dims = $derived(computeChartDimensions(chartWidth, chartHeight));
|
|
85
111
|
|
|
86
112
|
let isMulti = $derived(Array.isArray(series) && series.length > 0);
|
|
87
|
-
|
|
113
|
+
|
|
114
|
+
// ── Raw resolved series (before transformations) ──────────────
|
|
115
|
+
|
|
116
|
+
let rawSeries = $derived(isMulti ? series! : [{ name: '', data: data ?? [] }]);
|
|
117
|
+
|
|
118
|
+
// ── normaliseToFirstPoint transformation ──────────────────────
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* When normaliseToFirstPoint is true, each value is expressed as a
|
|
122
|
+
* percentage of the series' first data point's value (baseline = 100).
|
|
123
|
+
* Series whose first point is zero are left unchanged to avoid division
|
|
124
|
+
* by zero.
|
|
125
|
+
*/
|
|
126
|
+
let normalisedSeries = $derived.by(() => {
|
|
127
|
+
if (!normaliseToFirstPoint) {
|
|
128
|
+
return rawSeries;
|
|
129
|
+
}
|
|
130
|
+
return rawSeries.map((s) => {
|
|
131
|
+
const baseline = s.data[0]?.value ?? 0;
|
|
132
|
+
if (baseline === 0) {
|
|
133
|
+
return s;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
...s,
|
|
137
|
+
data: s.data.map((d) => ({
|
|
138
|
+
...d,
|
|
139
|
+
value: (d.value / baseline) * 100
|
|
140
|
+
}))
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// ── topN transformation ────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Clips to the top N bars (by first-series value, descending) and aggregates
|
|
149
|
+
* the rest into a single overflow bar. Operates on each series in parallel so
|
|
150
|
+
* the same category ordering is preserved across series.
|
|
151
|
+
* Only applies in non-multi or single-series mode (groupMode-agnostic:
|
|
152
|
+
* works by reordering labels, not by touching multi-series stacking).
|
|
153
|
+
*/
|
|
154
|
+
let resolvedSeries = $derived.by(() => {
|
|
155
|
+
if (topN == null || normalisedSeries.length === 0) {
|
|
156
|
+
return normalisedSeries;
|
|
157
|
+
}
|
|
158
|
+
const firstSeriesData = normalisedSeries[0]?.data ?? [];
|
|
159
|
+
if (firstSeriesData.length <= topN) {
|
|
160
|
+
return normalisedSeries;
|
|
161
|
+
}
|
|
162
|
+
// Sort indices by first-series value descending
|
|
163
|
+
const sortedIndices = firstSeriesData
|
|
164
|
+
.map((d, i) => ({ value: d.value, i }))
|
|
165
|
+
.sort((a, b) => b.value - a.value)
|
|
166
|
+
.map((item) => item.i);
|
|
167
|
+
|
|
168
|
+
const topIndices = new Set(sortedIndices.slice(0, topN));
|
|
169
|
+
|
|
170
|
+
return normalisedSeries.map((s) => {
|
|
171
|
+
const topData = s.data.filter((_, idx) => topIndices.has(idx));
|
|
172
|
+
const overflowValue = s.data
|
|
173
|
+
.filter((_, idx) => !topIndices.has(idx))
|
|
174
|
+
.reduce((sum, d) => sum + d.value, 0);
|
|
175
|
+
return {
|
|
176
|
+
...s,
|
|
177
|
+
data: [...topData, { label: overflowLabel, value: overflowValue }]
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
});
|
|
88
181
|
|
|
89
182
|
let labels = $derived.by(() => {
|
|
90
183
|
const first = resolvedSeries[0]?.data ?? [];
|
|
91
184
|
return first.map((d) => d.label);
|
|
92
185
|
});
|
|
93
186
|
|
|
187
|
+
// ── Effective highlighted index: merge declarative + imperative ─
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The declarative `highlightedIndex` prop takes precedence when explicitly
|
|
191
|
+
* set (non-null). The imperative API writes to `apiHighlightedIndex`.
|
|
192
|
+
* When both are null the chart renders normally (no dimming).
|
|
193
|
+
*/
|
|
194
|
+
let effectiveHighlightedIndex = $derived(
|
|
195
|
+
highlightedIndex != null ? highlightedIndex : apiHighlightedIndex
|
|
196
|
+
);
|
|
197
|
+
|
|
94
198
|
let isNormalized = $derived(stackNormalize && isMulti && groupMode === 'stacked');
|
|
95
199
|
|
|
96
200
|
/** When stackNormalize is active and no custom valueFormat is supplied, append % so the
|
|
@@ -606,53 +710,61 @@
|
|
|
606
710
|
</g>
|
|
607
711
|
{/if}
|
|
608
712
|
|
|
609
|
-
{#
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
713
|
+
{#if !hideBarGraphics}
|
|
714
|
+
{#each bars as bar, i (i)}
|
|
715
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
716
|
+
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
717
|
+
{#if isStackedMode && barRadius > 0}
|
|
718
|
+
<path
|
|
719
|
+
class="bar"
|
|
720
|
+
class:hovered={hovered?.si === bar.si && hovered?.pi === bar.pi}
|
|
721
|
+
class:highlighted={effectiveHighlightedIndex !== null &&
|
|
722
|
+
effectiveHighlightedIndex === bar.pi}
|
|
723
|
+
class:dimmed={(hovered !== null &&
|
|
724
|
+
(hovered.si !== bar.si || hovered.pi !== bar.pi)) ||
|
|
725
|
+
(effectiveHighlightedIndex !== null && effectiveHighlightedIndex !== bar.pi)}
|
|
726
|
+
d={stackedBarPath(bar)}
|
|
727
|
+
fill={barFillAttr(bar)}
|
|
728
|
+
aria-label="{bar.dataPoint.label}: {getDisplayValue(bar)}"
|
|
729
|
+
onmouseenter={(e) => handleEnter(e, bar)}
|
|
730
|
+
onmousemove={trackMouse}
|
|
731
|
+
onmouseleave={handleLeave}
|
|
732
|
+
onclick={() => handleClick(bar)}
|
|
733
|
+
/>
|
|
734
|
+
{:else}
|
|
735
|
+
<rect
|
|
736
|
+
class="bar"
|
|
737
|
+
class:hovered={hovered?.si === bar.si && hovered?.pi === bar.pi}
|
|
738
|
+
class:highlighted={effectiveHighlightedIndex !== null &&
|
|
739
|
+
effectiveHighlightedIndex === bar.pi}
|
|
740
|
+
class:dimmed={(hovered !== null &&
|
|
741
|
+
(hovered.si !== bar.si || hovered.pi !== bar.pi)) ||
|
|
742
|
+
(effectiveHighlightedIndex !== null && effectiveHighlightedIndex !== bar.pi)}
|
|
743
|
+
x={bar.x}
|
|
744
|
+
y={bar.y}
|
|
745
|
+
width={bar.width}
|
|
746
|
+
height={bar.height}
|
|
747
|
+
rx={barRadius}
|
|
748
|
+
ry={barRadius}
|
|
749
|
+
fill={barFillAttr(bar)}
|
|
750
|
+
aria-label="{bar.dataPoint.label}: {getDisplayValue(bar)}"
|
|
751
|
+
onmouseenter={(e) => handleEnter(e, bar)}
|
|
752
|
+
onmousemove={trackMouse}
|
|
753
|
+
onmouseleave={handleLeave}
|
|
754
|
+
onclick={() => handleClick(bar)}
|
|
755
|
+
/>
|
|
756
|
+
{/if}
|
|
757
|
+
{#if showValues && !isStackedMode}
|
|
758
|
+
<text
|
|
759
|
+
class="bar-value"
|
|
760
|
+
x={isVertical ? bar.x + bar.width / 2 : bar.x + bar.width + 4}
|
|
761
|
+
y={isVertical ? bar.y - 4 : bar.y + bar.height / 2}
|
|
762
|
+
text-anchor={isVertical ? 'middle' : 'start'}
|
|
763
|
+
dominant-baseline={isVertical ? 'auto' : 'middle'}>{getDisplayValue(bar)}</text
|
|
764
|
+
>
|
|
765
|
+
{/if}
|
|
766
|
+
{/each}
|
|
767
|
+
{/if}
|
|
656
768
|
|
|
657
769
|
<!-- A1-4: renderOverlay escape hatch — rendered after all bars -->
|
|
658
770
|
{#if typeof renderOverlay === 'function'}
|
|
@@ -691,6 +803,9 @@
|
|
|
691
803
|
.bar.hovered {
|
|
692
804
|
opacity: var(--barchart-bar-hover-opacity, 1);
|
|
693
805
|
}
|
|
806
|
+
.bar.highlighted {
|
|
807
|
+
opacity: var(--barchart-bar-highlighted-opacity, 1);
|
|
808
|
+
}
|
|
694
809
|
.bar.dimmed {
|
|
695
810
|
opacity: var(--barchart-bar-dimmed-opacity, 0.3);
|
|
696
811
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ChartHighlightAPI } from '../_chart/highlight';
|
|
2
3
|
export type BarFillPattern = {
|
|
3
4
|
pattern: {
|
|
4
5
|
/** SVG pattern element type: 'lines' | 'dots' | 'crosshatch' */
|
|
@@ -112,6 +113,46 @@ export type OptionalBarChartProperties = {
|
|
|
112
113
|
* live in SVG coordinate space.
|
|
113
114
|
*/
|
|
114
115
|
renderOverlay?: Snippet<[BarChartRenderContext]>;
|
|
116
|
+
/**
|
|
117
|
+
* Called once on mount with an imperative `ChartHighlightAPI` handle.
|
|
118
|
+
* Use `api.highlight(index)` to emphasise a specific bar (by its zero-based
|
|
119
|
+
* position within the category axis) and dim all others. Pass `null` to clear.
|
|
120
|
+
* The `type` field on the handle is always `'bar-chart'`.
|
|
121
|
+
*/
|
|
122
|
+
onChartReady?: (api: ChartHighlightAPI) => void;
|
|
123
|
+
/**
|
|
124
|
+
* Declarative complement to `onChartReady`. When set to a non-null number the
|
|
125
|
+
* bar at that zero-based category index is highlighted (full opacity) and the
|
|
126
|
+
* remaining bars are dimmed. Set to `null` or omit to show all bars normally.
|
|
127
|
+
*/
|
|
128
|
+
highlightedIndex?: number | null;
|
|
129
|
+
/**
|
|
130
|
+
* When `true`, each series' values are expressed as a percentage of that
|
|
131
|
+
* series' own first data point. A value equal to the baseline renders as 100,
|
|
132
|
+
* a value twice the baseline as 200, and so on. Useful for comparing relative
|
|
133
|
+
* growth across series that start at very different absolute levels.
|
|
134
|
+
* Has no effect on series that have no data or whose first point is zero.
|
|
135
|
+
*/
|
|
136
|
+
normaliseToFirstPoint?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* When set, only the top `topN` bars (by descending value) are shown
|
|
139
|
+
* individually. The remaining bars are aggregated into a single bar whose
|
|
140
|
+
* value is the sum of all omitted bars and whose label is `overflowLabel`
|
|
141
|
+
* (default `"Other"`). Has no effect when the data has `topN` or fewer bars.
|
|
142
|
+
* In multi-series mode the ranking is based on the first series.
|
|
143
|
+
*/
|
|
144
|
+
topN?: number;
|
|
145
|
+
/**
|
|
146
|
+
* Label for the aggregated overflow bar produced by `topN`. Defaults to
|
|
147
|
+
* `"Other"`. Has no effect when `topN` is not set.
|
|
148
|
+
*/
|
|
149
|
+
overflowLabel?: string;
|
|
150
|
+
/**
|
|
151
|
+
* When `true`, bar rectangles are not rendered. Only the axis labels, gridlines,
|
|
152
|
+
* and legend remain visible. Useful for building legend-only or label-only
|
|
153
|
+
* thumbnails alongside a full chart.
|
|
154
|
+
*/
|
|
155
|
+
hideBarGraphics?: boolean;
|
|
115
156
|
testId?: string;
|
|
116
157
|
classes?: string;
|
|
117
158
|
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DeltaIndicatorProperties, DeltaDirection } from './properties';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
value,
|
|
6
|
+
format,
|
|
7
|
+
invertColors = false,
|
|
8
|
+
hideArrow = false,
|
|
9
|
+
neutralThreshold = 0,
|
|
10
|
+
testId,
|
|
11
|
+
classes
|
|
12
|
+
}: DeltaIndicatorProperties = $props();
|
|
13
|
+
|
|
14
|
+
const defaultFormat = (input: number): string => `${Math.round(Math.abs(input))}%`;
|
|
15
|
+
|
|
16
|
+
// A negative threshold would invert the neutral band and misclassify direction, so
|
|
17
|
+
// clamp it to a non-negative value before the comparison math.
|
|
18
|
+
const safeNeutralThreshold = $derived(Math.max(0, neutralThreshold));
|
|
19
|
+
|
|
20
|
+
let direction = $derived<DeltaDirection>(
|
|
21
|
+
value > safeNeutralThreshold ? 'up' : value < -safeNeutralThreshold ? 'down' : 'neutral'
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Tone drives the color. 'up' reads as positive by default; invertColors flips
|
|
25
|
+
// the positive/negative tone for lower-is-better metrics. Neutral is always muted.
|
|
26
|
+
let tone = $derived(
|
|
27
|
+
direction === 'neutral'
|
|
28
|
+
? 'neutral'
|
|
29
|
+
: (direction === 'up') !== invertColors
|
|
30
|
+
? 'positive'
|
|
31
|
+
: 'negative'
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
let text = $derived((format ?? defaultFormat)(value));
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<span
|
|
38
|
+
class="delta-indicator delta-{tone} {classes ?? ''}"
|
|
39
|
+
data-pw={typeof testId === 'string' ? testId : null}
|
|
40
|
+
>
|
|
41
|
+
{#if !hideArrow && direction !== 'neutral'}
|
|
42
|
+
<span class="delta-indicator-arrow delta-arrow-{direction}" aria-hidden="true">
|
|
43
|
+
<svg viewBox="0 0 10 10"><path d="M5 1 L9 8 L1 8 Z" /></svg>
|
|
44
|
+
</span>
|
|
45
|
+
{/if}
|
|
46
|
+
<span class="delta-indicator-text">{text}</span>
|
|
47
|
+
</span>
|
|
48
|
+
|
|
49
|
+
<style>
|
|
50
|
+
.delta-indicator {
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
gap: var(--delta-indicator-gap, 2px);
|
|
54
|
+
font-size: var(--delta-indicator-font-size, 13px);
|
|
55
|
+
font-weight: var(--delta-indicator-font-weight, 600);
|
|
56
|
+
line-height: 1;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.delta-positive {
|
|
60
|
+
color: var(--delta-indicator-positive-color, #1a9d6f);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.delta-negative {
|
|
64
|
+
color: var(--delta-indicator-negative-color, #e5484d);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.delta-neutral {
|
|
68
|
+
color: var(--delta-indicator-neutral-color, #8a8a8a);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.delta-indicator-arrow {
|
|
72
|
+
display: inline-flex;
|
|
73
|
+
width: var(--delta-indicator-arrow-size, 9px);
|
|
74
|
+
height: var(--delta-indicator-arrow-size, 9px);
|
|
75
|
+
flex-shrink: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.delta-indicator-arrow svg {
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 100%;
|
|
81
|
+
fill: currentColor;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.delta-arrow-down {
|
|
85
|
+
transform: rotate(180deg);
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type DeltaIndicatorProperties = MandatoryDeltaIndicatorProperties & OptionalDeltaIndicatorProperties;
|
|
2
|
+
export type DeltaDirection = 'up' | 'down' | 'neutral';
|
|
3
|
+
export type MandatoryDeltaIndicatorProperties = {
|
|
4
|
+
/** The change amount; its sign selects the up / down / neutral direction. */
|
|
5
|
+
value: number;
|
|
6
|
+
};
|
|
7
|
+
export type OptionalDeltaIndicatorProperties = {
|
|
8
|
+
/**
|
|
9
|
+
* Formats the displayed text from the raw value. Default renders the rounded
|
|
10
|
+
* absolute value followed by a percent sign (e.g. `12%`).
|
|
11
|
+
*/
|
|
12
|
+
format?: (value: number) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Swap the up/down colors for lower-is-better metrics (e.g. bounce rate, RTO),
|
|
15
|
+
* where a decrease is "good" (positive tone) and an increase is "bad".
|
|
16
|
+
*/
|
|
17
|
+
invertColors?: boolean;
|
|
18
|
+
/** Hide the directional arrow, showing only the formatted text. */
|
|
19
|
+
hideArrow?: boolean;
|
|
20
|
+
/** Absolute values at or below this are treated as `neutral` (default 0). */
|
|
21
|
+
neutralThreshold?: number;
|
|
22
|
+
/** Test selector applied as the `data-pw` attribute. */
|
|
23
|
+
testId?: string;
|
|
24
|
+
/** Additional CSS classes for theming. */
|
|
25
|
+
classes?: string;
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|