@scalewing/react 1.38.0 → 1.39.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +53 -1
  3. package/dist/chart-axis.d.ts +61 -0
  4. package/dist/chart-axis.js +83 -0
  5. package/dist/chart-dates.d.ts +6 -0
  6. package/dist/chart-dates.js +15 -0
  7. package/dist/chart-metrics.d.ts +40 -0
  8. package/dist/chart-metrics.js +48 -0
  9. package/dist/chart-scale.d.ts +48 -0
  10. package/dist/chart-scale.js +116 -0
  11. package/dist/chart-table-rows.d.ts +8 -0
  12. package/dist/chart-table-rows.js +1 -0
  13. package/dist/column-chart-bars.d.ts +38 -0
  14. package/dist/column-chart-bars.js +82 -0
  15. package/dist/column-chart-callouts.d.ts +48 -0
  16. package/dist/column-chart-callouts.js +54 -0
  17. package/dist/column-chart-input.d.ts +40 -0
  18. package/dist/column-chart-input.js +60 -0
  19. package/dist/column-chart-layout.d.ts +63 -0
  20. package/dist/column-chart-layout.js +97 -0
  21. package/dist/components/BarChart.d.ts +1 -1
  22. package/dist/components/BarChart.js +1 -1
  23. package/dist/components/ChartLegend.d.ts +38 -0
  24. package/dist/components/ChartLegend.js +32 -0
  25. package/dist/components/ColumnChart.d.ts +72 -0
  26. package/dist/components/ColumnChart.js +71 -0
  27. package/dist/components/DataBar.d.ts +6 -6
  28. package/dist/components/LineChart.d.ts +83 -0
  29. package/dist/components/LineChart.js +77 -0
  30. package/dist/components/chart/ChartTable.d.ts +16 -0
  31. package/dist/components/chart/ChartTable.js +12 -0
  32. package/dist/components/chart/ChartValueAxis.d.ts +14 -0
  33. package/dist/components/chart/ChartValueAxis.js +11 -0
  34. package/dist/components/chart/use-chart-width.d.ts +8 -0
  35. package/dist/components/chart/use-chart-width.js +34 -0
  36. package/dist/components/column-chart/ChartCalloutList.d.ts +16 -0
  37. package/dist/components/column-chart/ChartCalloutList.js +13 -0
  38. package/dist/components/column-chart/ColumnChartDrawing.d.ts +17 -0
  39. package/dist/components/column-chart/ColumnChartDrawing.js +18 -0
  40. package/dist/components/line-chart/LineChartDrawing.d.ts +17 -0
  41. package/dist/components/line-chart/LineChartDrawing.js +16 -0
  42. package/dist/css/chart-marks.d.ts +10 -0
  43. package/dist/css/chart-marks.js +15 -0
  44. package/dist/css/chart-tones.d.ts +68 -0
  45. package/dist/css/chart-tones.js +130 -0
  46. package/dist/css/{css-chart.d.ts → css-bar-chart.d.ts} +2 -2
  47. package/dist/css/{css-chart.js → css-bar-chart.js} +2 -2
  48. package/dist/css/css-chart-legend.d.ts +5 -0
  49. package/dist/css/css-chart-legend.js +102 -0
  50. package/dist/css/css-chart-plot.d.ts +2 -0
  51. package/dist/css/css-chart-plot.js +170 -0
  52. package/dist/css/css-components.js +14 -2
  53. package/dist/css/css-data-bar.d.ts +4 -9
  54. package/dist/css/css-data-bar.js +15 -31
  55. package/dist/css/css-line-chart.d.ts +2 -0
  56. package/dist/css/css-line-chart.js +31 -0
  57. package/dist/css/stylesheet.js +10 -2
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.js +3 -0
  60. package/dist/is-one-of.d.ts +5 -0
  61. package/dist/is-one-of.js +7 -0
  62. package/dist/line-chart-input.d.ts +39 -0
  63. package/dist/line-chart-input.js +70 -0
  64. package/dist/line-chart-layout.d.ts +68 -0
  65. package/dist/line-chart-layout.js +99 -0
  66. package/dist/line-chart-markers.d.ts +29 -0
  67. package/dist/line-chart-markers.js +57 -0
  68. package/dist/line-chart-path.d.ts +18 -0
  69. package/dist/line-chart-path.js +33 -0
  70. package/dist/line-chart-points.d.ts +6 -0
  71. package/dist/line-chart-points.js +8 -0
  72. package/dist/line-chart-table.d.ts +15 -0
  73. package/dist/line-chart-table.js +29 -0
  74. package/dist/styles.css +219 -0
  75. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ import { categoricalColorKeys, categoricalHues, } from '@scalewing/tokens';
2
+ import { isOneOf } from '../is-one-of.js';
3
+ /** A source as its custom property. */
4
+ function sourceProperty(source) {
5
+ return 'semantic' in source
6
+ ? `var(--sw-color-${source.semantic})`
7
+ : `var(--sw-categorical-${source.categorical})`;
8
+ }
9
+ /**
10
+ * The statement tones a range bar's fill takes (see DataBar). `danger` is
11
+ * for a shortage, never for cash leaving: an outflow is `muted`.
12
+ */
13
+ export const statementFillTones = [
14
+ 'neutral',
15
+ 'success',
16
+ 'muted',
17
+ 'strong',
18
+ 'accent',
19
+ 'danger',
20
+ ];
21
+ /**
22
+ * Every fill tone: the categorical colours (a chart's series), then the
23
+ * statement tones a range bar adds. `neutral` is in both and is one grey.
24
+ */
25
+ export const chartFillTones = [
26
+ ...categoricalColorKeys,
27
+ ...statementFillTones.filter((tone) => tone !== 'neutral'),
28
+ ];
29
+ /** The tones a line, a marker or the boxed period is drawn in. */
30
+ export const chartStrokeTones = [
31
+ 'accent',
32
+ 'success',
33
+ 'warning',
34
+ 'danger',
35
+ 'neutral',
36
+ ];
37
+ export const chartTones = [
38
+ ...new Set([...chartFillTones, ...chartStrokeTones]),
39
+ ];
40
+ /**
41
+ * How much of a categorical colour a column's fill mixes into the surface:
42
+ * a lighter fill, so a line drawn over the columns stands apart, that
43
+ * keeps 1.5:1 on the surface in every palette and scheme.
44
+ */
45
+ export const categoricalFillShare = 0.72;
46
+ /**
47
+ * How much of the danger colour its fill mixes into the surface (a
48
+ * shortage's range bar, never cash leaving): a light red, at 1.5:1 or more
49
+ * on the surface in every palette and scheme, as every other fill.
50
+ */
51
+ export const dangerFillShare = 0.4;
52
+ /** Each fill tone's colour, mixed into the surface. */
53
+ export const chartFillMixes = {
54
+ ...Object.fromEntries(categoricalHues.map((hue) => [
55
+ hue,
56
+ { categorical: hue, share: categoricalFillShare, into: 'surface' },
57
+ ])),
58
+ neutral: { semantic: 'muted', share: 0.65, into: 'surface' },
59
+ success: { semantic: 'success', share: 0.55, into: 'surface' },
60
+ muted: { semantic: 'muted', share: 0.35, into: 'surface' },
61
+ strong: { semantic: 'text', share: 0.85, into: 'surface' },
62
+ accent: { semantic: 'accent', share: 1, into: 'surface' },
63
+ danger: { semantic: 'danger', share: dangerFillShare, into: 'surface' },
64
+ };
65
+ /** Each stroke tone's colour: a semantic colour, or muted for neutral. */
66
+ export const chartStrokeColors = {
67
+ accent: { semantic: 'accent' },
68
+ success: { semantic: 'success' },
69
+ warning: { semantic: 'warning' },
70
+ danger: { semantic: 'danger' },
71
+ neutral: { semantic: 'muted' },
72
+ };
73
+ /**
74
+ * How much of a line's stroke the area under it takes, over transparency:
75
+ * a quiet tint behind the line, decorative (the line carries the values).
76
+ */
77
+ export const chartAreaShare = 0.12;
78
+ /** How much of a hue's colour its words keep, moved toward the text colour. */
79
+ export const categoricalInkShare = 0.3;
80
+ /** How much of a semantic colour its words keep, moved toward the text colour. */
81
+ export const semanticInkShare = 0.5;
82
+ /** The tones whose words are drawn beside a mark: a series' and a stroke's. */
83
+ export const chartInkTones = [...categoricalHues, ...chartStrokeTones];
84
+ /** The words beside a mark: its tone moved toward the text colour. */
85
+ export const chartInkMixes = {
86
+ ...Object.fromEntries(categoricalHues.map((hue) => [
87
+ hue,
88
+ { categorical: hue, share: categoricalInkShare, into: 'text' },
89
+ ])),
90
+ accent: { semantic: 'accent', share: semanticInkShare, into: 'text' },
91
+ success: { semantic: 'success', share: semanticInkShare, into: 'text' },
92
+ warning: { semantic: 'warning', share: semanticInkShare, into: 'text' },
93
+ danger: { semantic: 'danger', share: semanticInkShare, into: 'text' },
94
+ neutral: { semantic: 'muted', share: 1, into: 'text' },
95
+ };
96
+ /** A mix as CSS: the colour alone when unmixed. */
97
+ export function chartColorMix(mix) {
98
+ const color = sourceProperty(mix);
99
+ if (mix.share === 1)
100
+ return color;
101
+ return `color-mix(in srgb, ${color} ${Math.round(mix.share * 100)}%, var(--sw-color-${mix.into}))`;
102
+ }
103
+ /** A fill tone's colour. */
104
+ export function chartFill(tone) {
105
+ return chartColorMix(chartFillMixes[tone]);
106
+ }
107
+ /*
108
+ * A tone class hands its roles to the marks inside it as custom
109
+ * properties, `--sw-chart-fill`, `--sw-chart-stroke` and `--sw-chart-ink`,
110
+ * so a legend swatch, a column, a line and a label each read the role it
111
+ * draws. A tone sets only the roles it has.
112
+ */
113
+ function toneDeclarations(tone) {
114
+ const declarations = [];
115
+ if (isOneOf(chartFillTones, tone))
116
+ declarations.push(`--sw-chart-fill: ${chartFill(tone)};`);
117
+ if (isOneOf(chartStrokeTones, tone))
118
+ declarations.push(`--sw-chart-stroke: ${sourceProperty(chartStrokeColors[tone])};`);
119
+ if (isOneOf(chartInkTones, tone))
120
+ declarations.push(`--sw-chart-ink: ${chartColorMix(chartInkMixes[tone])};`);
121
+ return declarations.join(' ');
122
+ }
123
+ export function cssChartToneClasses() {
124
+ return chartTones
125
+ .map((tone) => `.sw-chart-tone-${tone} { ${toneDeclarations(tone)} }`)
126
+ .join('\n');
127
+ }
128
+ export function chartToneClassCatalog() {
129
+ return chartTones.map((tone) => `sw-chart-tone-${tone}`);
130
+ }
@@ -5,5 +5,5 @@
5
5
  */
6
6
  export declare const barChartTones: readonly ["accent", "success", "warning", "danger"];
7
7
  export type BarChartTone = (typeof barChartTones)[number];
8
- export declare function cssChartClasses(): string;
9
- export declare function chartClassCatalog(): string[];
8
+ export declare function cssBarChartClasses(): string;
9
+ export declare function barChartClassCatalog(): string[];
@@ -66,7 +66,7 @@ function divergingRules() {
66
66
  .sw-bar-chart-diverging .sw-bar-chart-track::before { background: CanvasText; }
67
67
  }`;
68
68
  }
69
- export function cssChartClasses() {
69
+ export function cssBarChartClasses() {
70
70
  return `.sw-bar-chart {
71
71
  display: grid;
72
72
  gap: var(--sw-space-2);
@@ -155,7 +155,7 @@ ${divergingRules()}
155
155
  .sw-bar-chart-fill { background: CanvasText; }
156
156
  }`;
157
157
  }
158
- export function chartClassCatalog() {
158
+ export function barChartClassCatalog() {
159
159
  return [
160
160
  'sw-bar-chart',
161
161
  'sw-bar-chart-plot',
@@ -0,0 +1,5 @@
1
+ /** The marks a legend item can show: what its words name in the chart. */
2
+ export declare const chartLegendSwatches: readonly ["bar", "line", "marker", "box"];
3
+ export type ChartLegendSwatch = (typeof chartLegendSwatches)[number];
4
+ export declare function cssChartLegendClasses(): string;
5
+ export declare function chartLegendClassCatalog(): string[];
@@ -0,0 +1,102 @@
1
+ import { typographyVariants } from '@scalewing/tokens';
2
+ import { chartHairline, chartLineWidth } from './chart-marks.js';
3
+ const caption = typographyVariants.caption;
4
+ /** The marks a legend item can show: what its words name in the chart. */
5
+ export const chartLegendSwatches = ['bar', 'line', 'marker', 'box'];
6
+ /*
7
+ * Each swatch reads its colour from the item's tone class
8
+ * (`sw-chart-tone-<tone>`, `chart-tones.ts`): a bar is the tone's fill, a
9
+ * square a spacing step 3 wide; a line is its stroke, a spacing step 4
10
+ * long at the charts' line width; a marker is a downward triangle in the
11
+ * stroke, the shape a chart's marker takes; a box is the dashed outline of
12
+ * the boxed current period. Forced colours draw every swatch in the system
13
+ * text colour, as they draw the marks.
14
+ */
15
+ function swatchRules() {
16
+ return `.sw-chart-legend-bar {
17
+ background: var(--sw-chart-fill);
18
+ border-radius: calc(var(--sw-radius-sm) / 4);
19
+ height: var(--sw-space-3);
20
+ width: var(--sw-space-3);
21
+ }
22
+
23
+ .sw-chart-legend-line {
24
+ background: var(--sw-chart-stroke);
25
+ border-radius: var(--sw-radius-pill);
26
+ height: ${chartLineWidth}px;
27
+ width: var(--sw-space-4);
28
+ }
29
+
30
+ .sw-chart-legend-marker {
31
+ background: var(--sw-chart-stroke);
32
+ clip-path: polygon(0 0, 100% 0, 50% 100%);
33
+ height: var(--sw-space-3);
34
+ width: var(--sw-space-3);
35
+ }
36
+
37
+ .sw-chart-legend-box {
38
+ border: ${chartHairline}px dashed var(--sw-chart-stroke);
39
+ border-radius: calc(var(--sw-radius-sm) / 2);
40
+ box-sizing: border-box;
41
+ height: var(--sw-space-3);
42
+ width: var(--sw-space-4);
43
+ }
44
+
45
+ @media (forced-colors: active) {
46
+ .sw-chart-legend-bar,
47
+ .sw-chart-legend-line,
48
+ .sw-chart-legend-marker { background: CanvasText; }
49
+ .sw-chart-legend-box { border-color: CanvasText; }
50
+ }`;
51
+ }
52
+ /*
53
+ * A legend is a list of its items in a wrapping row, in the caption type:
54
+ * each item its swatch, then its words. The words wrap within the item
55
+ * rather than push the row past its container, and the swatch stays
56
+ * centred on their first line.
57
+ */
58
+ export function cssChartLegendClasses() {
59
+ return `.sw-chart-legend {
60
+ color: var(--sw-color-text);
61
+ column-gap: var(--sw-space-5);
62
+ display: flex;
63
+ flex-wrap: wrap;
64
+ font-family: var(--sw-font-sans);
65
+ font-size: ${caption.fontSize}px;
66
+ font-weight: ${caption.fontWeight};
67
+ letter-spacing: ${caption.letterSpacing}px;
68
+ line-height: ${caption.lineHeight}px;
69
+ list-style: none;
70
+ margin: 0;
71
+ padding: 0;
72
+ row-gap: var(--sw-space-2);
73
+ }
74
+
75
+ .sw-chart-legend-item {
76
+ align-items: flex-start;
77
+ display: inline-flex;
78
+ gap: var(--sw-space-2);
79
+ min-width: 0;
80
+ }
81
+
82
+ .sw-chart-legend-swatch {
83
+ display: block;
84
+ flex: none;
85
+ /* Centred on the first line of the words, however many lines they wrap to. */
86
+ margin-block-start: calc((${caption.lineHeight}px - var(--sw-space-3)) / 2);
87
+ }
88
+
89
+ .sw-chart-legend-line {
90
+ margin-block-start: calc((${caption.lineHeight}px - ${chartLineWidth}px) / 2);
91
+ }
92
+
93
+ ${swatchRules()}`;
94
+ }
95
+ export function chartLegendClassCatalog() {
96
+ return [
97
+ 'sw-chart-legend',
98
+ 'sw-chart-legend-item',
99
+ 'sw-chart-legend-swatch',
100
+ ...chartLegendSwatches.map((swatch) => `sw-chart-legend-${swatch}`),
101
+ ];
102
+ }
@@ -0,0 +1,2 @@
1
+ export declare function cssChartPlotClasses(): string;
2
+ export declare function chartPlotClassCatalog(): string[];
@@ -0,0 +1,170 @@
1
+ import { typographyVariants } from '@scalewing/tokens';
2
+ import { chartBoxDash, chartHairline, chartLeaderDash, chartLineWidth, } from './chart-marks.js';
3
+ const caption = typographyVariants.caption;
4
+ /*
5
+ * The parts every plotted chart (ColumnChart, LineChart) draws in its SVG:
6
+ * the words in the caption type, the grid and zero lines, the boxed
7
+ * period, a line and its last value, and the callouts with their leaders.
8
+ * Every colour is a theme colour or a tone's role (`chart-tones.ts`), read
9
+ * from the tone class on the mark or its group; words with no tone are
10
+ * the text colour.
11
+ */
12
+ function plotRules() {
13
+ return `.sw-chart {
14
+ display: grid;
15
+ gap: var(--sw-space-2);
16
+ min-width: 0;
17
+ }
18
+
19
+ .sw-chart-svg {
20
+ display: block;
21
+ font-family: var(--sw-font-sans);
22
+ font-size: ${caption.fontSize}px;
23
+ height: auto;
24
+ letter-spacing: ${caption.letterSpacing}px;
25
+ max-width: 100%;
26
+ overflow: visible;
27
+ width: 100%;
28
+ }
29
+
30
+ .sw-chart-tick,
31
+ .sw-chart-category {
32
+ fill: var(--sw-color-muted);
33
+ font-variant-numeric: tabular-nums;
34
+ }
35
+
36
+ .sw-chart-tick-line { fill: var(--sw-chart-ink); }
37
+
38
+ .sw-chart-grid {
39
+ stroke: var(--sw-color-border);
40
+ stroke-width: ${chartHairline};
41
+ }
42
+
43
+ .sw-chart-zero {
44
+ stroke: var(--sw-color-muted);
45
+ stroke-width: ${chartHairline};
46
+ }
47
+
48
+ .sw-chart-highlight {
49
+ fill: none;
50
+ stroke: var(--sw-chart-stroke);
51
+ stroke-dasharray: ${chartBoxDash};
52
+ stroke-width: ${chartHairline};
53
+ }
54
+
55
+ .sw-chart-line {
56
+ fill: none;
57
+ stroke: var(--sw-chart-stroke);
58
+ stroke-linecap: round;
59
+ stroke-linejoin: round;
60
+ stroke-width: ${chartLineWidth};
61
+ }
62
+
63
+ .sw-chart-dot { fill: var(--sw-chart-stroke); }
64
+
65
+ .sw-chart-end-label {
66
+ fill: var(--sw-chart-ink);
67
+ font-variant-numeric: tabular-nums;
68
+ font-weight: 600;
69
+ }
70
+
71
+ .sw-chart-leader {
72
+ stroke: var(--sw-chart-ink, var(--sw-color-text));
73
+ stroke-dasharray: ${chartLeaderDash};
74
+ stroke-width: ${chartHairline};
75
+ }
76
+
77
+ .sw-chart-callout-text {
78
+ fill: var(--sw-chart-ink, var(--sw-color-text));
79
+ font-weight: 600;
80
+ }`;
81
+ }
82
+ /*
83
+ * On a compact chart the callouts are a list under the plot: each its
84
+ * words in its hue's ink, after a dot in its hue's fill (the colour of its
85
+ * column) centred on their first line.
86
+ */
87
+ function calloutListRules() {
88
+ return `.sw-chart-callouts {
89
+ display: grid;
90
+ font-family: var(--sw-font-sans);
91
+ font-size: ${caption.fontSize}px;
92
+ gap: var(--sw-space-1);
93
+ letter-spacing: ${caption.letterSpacing}px;
94
+ line-height: ${caption.lineHeight}px;
95
+ list-style: none;
96
+ margin: 0;
97
+ padding: 0;
98
+ }
99
+
100
+ .sw-chart-callout {
101
+ align-items: flex-start;
102
+ color: var(--sw-chart-ink, var(--sw-color-text));
103
+ display: flex;
104
+ font-weight: 600;
105
+ gap: var(--sw-space-2);
106
+ }
107
+
108
+ .sw-chart-callout-dot {
109
+ background: var(--sw-chart-fill, currentColor);
110
+ border-radius: var(--sw-radius-pill);
111
+ flex: none;
112
+ height: var(--sw-space-2);
113
+ margin-block-start: calc((${caption.lineHeight}px - var(--sw-space-2)) / 2);
114
+ width: var(--sw-space-2);
115
+ }`;
116
+ }
117
+ /*
118
+ * Forced colours keep the drawing legible in the system colours: marks in
119
+ * the text colour (columns outlined in the canvas colour so a stack's
120
+ * parts stay apart), the line and its last value in the highlight colour,
121
+ * grid lines in the grey text colour, and every word in the text colour.
122
+ * The hidden table carries the figures there as everywhere.
123
+ */
124
+ function forcedColorRules() {
125
+ return `@media (forced-colors: active) {
126
+ .sw-chart-column { fill: CanvasText; stroke: Canvas; }
127
+ .sw-chart-grid { stroke: GrayText; }
128
+ .sw-chart-zero,
129
+ .sw-chart-highlight,
130
+ .sw-chart-leader { stroke: CanvasText; }
131
+ .sw-chart-line { stroke: Highlight; }
132
+ .sw-chart-dot,
133
+ .sw-chart-end-label { fill: Highlight; }
134
+ .sw-chart-tick,
135
+ .sw-chart-category,
136
+ .sw-chart-callout-text { fill: CanvasText; }
137
+ .sw-chart-callout { color: CanvasText; }
138
+ .sw-chart-callout-dot { background: CanvasText; }
139
+ }`;
140
+ }
141
+ export function cssChartPlotClasses() {
142
+ return `${plotRules()}
143
+
144
+ .sw-chart-column { fill: var(--sw-chart-fill); }
145
+
146
+ ${calloutListRules()}
147
+
148
+ ${forcedColorRules()}`;
149
+ }
150
+ export function chartPlotClassCatalog() {
151
+ return [
152
+ 'sw-chart',
153
+ 'sw-chart-svg',
154
+ 'sw-chart-tick',
155
+ 'sw-chart-tick-line',
156
+ 'sw-chart-category',
157
+ 'sw-chart-grid',
158
+ 'sw-chart-zero',
159
+ 'sw-chart-highlight',
160
+ 'sw-chart-line',
161
+ 'sw-chart-dot',
162
+ 'sw-chart-end-label',
163
+ 'sw-chart-leader',
164
+ 'sw-chart-callout-text',
165
+ 'sw-chart-column',
166
+ 'sw-chart-callouts',
167
+ 'sw-chart-callout',
168
+ 'sw-chart-callout-dot',
169
+ ];
170
+ }
@@ -1,9 +1,13 @@
1
+ import { cssChartToneClasses } from './chart-tones.js';
1
2
  import { cssActionBarClasses } from './css-action-bar.js';
2
3
  import { cssActionMenuClasses } from './css-action-menu.js';
3
4
  import { cssAccordionClasses } from './css-accordion.js';
4
5
  import { cssButtonClasses } from './css-button.js';
5
6
  import { cssCalendarButtonClasses } from './css-calendar-button.js';
6
- import { cssChartClasses } from './css-chart.js';
7
+ import { cssBarChartClasses } from './css-bar-chart.js';
8
+ import { cssChartLegendClasses } from './css-chart-legend.js';
9
+ import { cssChartPlotClasses } from './css-chart-plot.js';
10
+ import { cssLineChartClasses } from './css-line-chart.js';
7
11
  import { cssDataBarClasses } from './css-data-bar.js';
8
12
  import { cssPaginationClasses } from './css-pagination.js';
9
13
  import { cssCheckboxClasses } from './css-checkbox.js';
@@ -137,10 +141,18 @@ ${cssDateFieldClasses()}
137
141
 
138
142
  ${cssCalendarButtonClasses()}
139
143
 
140
- ${cssChartClasses()}
144
+ ${cssBarChartClasses()}
141
145
 
142
146
  ${cssDataBarClasses()}
143
147
 
148
+ ${cssChartToneClasses()}
149
+
150
+ ${cssChartLegendClasses()}
151
+
152
+ ${cssChartPlotClasses()}
153
+
154
+ ${cssLineChartClasses()}
155
+
144
156
  ${cssPaginationClasses()}
145
157
 
146
158
  ${cssChromeClasses()}
@@ -1,16 +1,11 @@
1
1
  /**
2
2
  * What a range bar's fill means: the start or a carried figure (`neutral`),
3
3
  * money in (`success`), money out (`muted`, never danger: an outflow is not
4
- * an error), a subtotal (`strong`) and what was counted or recorded
5
- * (`accent`).
4
+ * an error), a subtotal (`strong`), what was counted or recorded
5
+ * (`accent`), and a shortage (`danger`, light red: for a shortage, never
6
+ * for cash leaving).
6
7
  */
7
- export declare const dataBarTones: readonly ["neutral", "success", "muted", "strong", "accent"];
8
+ export declare const dataBarTones: readonly ["neutral", "success", "muted", "strong", "accent", "danger"];
8
9
  export type DataBarTone = (typeof dataBarTones)[number];
9
- export declare const dataBarToneMixes: Record<DataBarTone, {
10
- color: 'muted' | 'success' | 'text' | 'accent';
11
- share: number;
12
- }>;
13
- /** A tone's fill: its colour, mixed into the surface by its share. */
14
- export declare function dataBarToneFill(tone: DataBarTone): string;
15
10
  export declare function cssDataBarClasses(): string;
16
11
  export declare function dataBarClassCatalog(): string[];
@@ -1,42 +1,26 @@
1
+ import { chartFill, statementFillTones } from './chart-tones.js';
1
2
  /**
2
3
  * What a range bar's fill means: the start or a carried figure (`neutral`),
3
4
  * money in (`success`), money out (`muted`, never danger: an outflow is not
4
- * an error), a subtotal (`strong`) and what was counted or recorded
5
- * (`accent`).
5
+ * an error), a subtotal (`strong`), what was counted or recorded
6
+ * (`accent`), and a shortage (`danger`, light red: for a shortage, never
7
+ * for cash leaving).
6
8
  */
7
- export const dataBarTones = [
8
- 'neutral',
9
- 'success',
10
- 'muted',
11
- 'strong',
12
- 'accent',
13
- ];
9
+ export const dataBarTones = statementFillTones;
14
10
  /*
15
- * Each tone is a semantic colour, mixed into the surface where the board
16
- * draws a lighter fill: the bar is decorative (the figure is the cell's
17
- * text), so the mixes keep the tones apart from one another rather than
18
- * meeting a text contrast: every tone at 1.5:1 or more on the surface, and
19
- * the three greys (out, start, subtotal) 1.5:1 or more from the next one,
20
- * in every palette and scheme (`data-bar.test.tsx`). `accent` is the
21
- * accent itself.
11
+ * Each tone is a chart fill (`chart-tones.ts`, shared with ChartLegend's
12
+ * `bar` swatch so a statement's legend matches its bars): a semantic
13
+ * colour mixed into the surface where the board draws a lighter fill. The
14
+ * bar is decorative (the figure is the cell's text), so the mixes keep the
15
+ * tones apart from one another rather than meeting a text contrast: every
16
+ * tone at 1.5:1 or more on the surface, and the three greys (out, start,
17
+ * subtotal) 1.5:1 or more from the next one, in every palette and scheme
18
+ * (`data-bar.test.tsx`). `accent` is the accent itself; `danger` is the
19
+ * danger colour at 40 %.
22
20
  */
23
- export const dataBarToneMixes = {
24
- neutral: { color: 'muted', share: 0.65 },
25
- success: { color: 'success', share: 0.55 },
26
- muted: { color: 'muted', share: 0.35 },
27
- strong: { color: 'text', share: 0.85 },
28
- accent: { color: 'accent', share: 1 },
29
- };
30
- /** A tone's fill: its colour, mixed into the surface by its share. */
31
- export function dataBarToneFill(tone) {
32
- const { color, share } = dataBarToneMixes[tone];
33
- if (share === 1)
34
- return `var(--sw-color-${color})`;
35
- return `color-mix(in srgb, var(--sw-color-${color}) ${Math.round(share * 100)}%, var(--sw-color-surface))`;
36
- }
37
21
  function toneRules() {
38
22
  return dataBarTones
39
- .map((tone) => `.sw-data-bar-${tone} > .sw-data-bar-fill { background: ${dataBarToneFill(tone)}; }`)
23
+ .map((tone) => `.sw-data-bar-${tone} > .sw-data-bar-fill { background: ${chartFill(tone)}; }`)
40
24
  .join('\n');
41
25
  }
42
26
  /*
@@ -0,0 +1,2 @@
1
+ export declare function cssLineChartClasses(): string;
2
+ export declare function lineChartClassCatalog(): string[];
@@ -0,0 +1,31 @@
1
+ import { chartAreaShare } from './chart-tones.js';
2
+ /*
3
+ * The marks only a line chart draws, beside the shared plot classes
4
+ * (`css-chart-plot.ts`): the area under the line, a quiet tint of its
5
+ * stroke; a marker's triangle in its tone's stroke; and the marker's
6
+ * words in its tone's ink. Forced colours drop the area and draw markers
7
+ * and their words in the text colour, apart from the line's highlight
8
+ * colour.
9
+ */
10
+ export function cssLineChartClasses() {
11
+ return `.sw-chart-area {
12
+ fill: color-mix(in srgb, var(--sw-chart-stroke) ${chartAreaShare * 100}%, transparent);
13
+ }
14
+
15
+ .sw-chart-marker { fill: var(--sw-chart-stroke); }
16
+
17
+ .sw-chart-marker-label {
18
+ fill: var(--sw-chart-ink);
19
+ font-variant-numeric: tabular-nums;
20
+ font-weight: 600;
21
+ }
22
+
23
+ @media (forced-colors: active) {
24
+ .sw-chart-area { fill: none; }
25
+ .sw-chart-marker,
26
+ .sw-chart-marker-label { fill: CanvasText; }
27
+ }`;
28
+ }
29
+ export function lineChartClassCatalog() {
30
+ return ['sw-chart-area', 'sw-chart-marker', 'sw-chart-marker-label'];
31
+ }
@@ -1,4 +1,5 @@
1
1
  import { cardVariants, darkTheme, lightTheme, typographyVariants, } from '@scalewing/tokens';
2
+ import { chartToneClassCatalog } from './chart-tones.js';
2
3
  import { actionBarClassCatalog } from './css-action-bar.js';
3
4
  import { actionMenuClassCatalog } from './css-action-menu.js';
4
5
  import { accordionClassCatalog } from './css-accordion.js';
@@ -30,7 +31,10 @@ import { boxBorderClassCatalog } from './css-box-border.js';
30
31
  import { boxLinkClassCatalog } from './css-box-link.js';
31
32
  import { cssComponentClasses } from './css-components.js';
32
33
  import { buttonClassCatalog } from './css-button.js';
33
- import { chartClassCatalog } from './css-chart.js';
34
+ import { barChartClassCatalog } from './css-bar-chart.js';
35
+ import { chartLegendClassCatalog } from './css-chart-legend.js';
36
+ import { chartPlotClassCatalog } from './css-chart-plot.js';
37
+ import { lineChartClassCatalog } from './css-line-chart.js';
34
38
  import { dataBarClassCatalog } from './css-data-bar.js';
35
39
  import { paginationClassCatalog } from './css-pagination.js';
36
40
  import { dataClassCatalog } from './css-data.js';
@@ -70,8 +74,12 @@ export function utilityClassCatalog() {
70
74
  ...segmentedClassCatalog(),
71
75
  ...tableClassCatalog(),
72
76
  ...scrollRegionClassCatalog(),
73
- ...chartClassCatalog(),
77
+ ...barChartClassCatalog(),
74
78
  ...dataBarClassCatalog(),
79
+ ...chartToneClassCatalog(),
80
+ ...chartLegendClassCatalog(),
81
+ ...chartPlotClassCatalog(),
82
+ ...lineChartClassCatalog(),
75
83
  ...paginationClassCatalog(),
76
84
  ...chromeClassCatalog(),
77
85
  ...sectionNavClassCatalog(),
package/dist/index.d.ts CHANGED
@@ -16,6 +16,9 @@ export { RadioGroup, type RadioGroupOption, type RadioGroupProps, } from './comp
16
16
  export { AppHeader, appHeaderAppearances, type AppHeaderAppearance, type AppHeaderProps, } from './components/AppHeader.js';
17
17
  export { Badge, type BadgeProps, type BadgeSize, type BadgeTone, badgeSizes, badgeTones, } from './components/Badge.js';
18
18
  export { BarChart, type BarChartItem, type BarChartProps, type BarChartTone, barChartTones, } from './components/BarChart.js';
19
+ export { ChartLegend, type ChartFillTone, type ChartLegendItem, type ChartLegendProps, type ChartLegendSwatch, type ChartStrokeTone, type ChartTone, chartFillTones, chartLegendSwatches, chartStrokeTones, } from './components/ChartLegend.js';
20
+ export { ColumnChart, type ColumnChartCallout, type ColumnChartLine, type ColumnChartMode, type ColumnChartProps, type ColumnChartSeries, columnChartModes, } from './components/ColumnChart.js';
21
+ export { LineChart, type LineChartCurve, type LineChartMarker, type LineChartPeriod, type LineChartPoint, type LineChartProps, lineChartCurves, } from './components/LineChart.js';
19
22
  export { DataBar, type DataBarProps, type DataBarTone, dataBarTones, } from './components/DataBar.js';
20
23
  export { Pagination, type PaginationLabels, type PaginationProps, } from './components/Pagination.js';
21
24
  export { Button, type ButtonDisabledAppearance, type ButtonProps, type ButtonSize, type ButtonVariant, } from './components/Button.js';
package/dist/index.js CHANGED
@@ -15,6 +15,9 @@ export { RadioGroup, } from './components/RadioGroup.js';
15
15
  export { AppHeader, appHeaderAppearances, } from './components/AppHeader.js';
16
16
  export { Badge, badgeSizes, badgeTones, } from './components/Badge.js';
17
17
  export { BarChart, barChartTones, } from './components/BarChart.js';
18
+ export { ChartLegend, chartFillTones, chartLegendSwatches, chartStrokeTones, } from './components/ChartLegend.js';
19
+ export { ColumnChart, columnChartModes, } from './components/ColumnChart.js';
20
+ export { LineChart, lineChartCurves, } from './components/LineChart.js';
18
21
  export { DataBar, dataBarTones, } from './components/DataBar.js';
19
22
  export { Pagination, } from './components/Pagination.js';
20
23
  export { Button, } from './components/Button.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Whether a value is one of a list of names, narrowing it to the list's
3
+ * type: a component's check of a prop against its allowed values.
4
+ */
5
+ export declare function isOneOf<Name extends string>(names: readonly Name[], value: unknown): value is Name;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Whether a value is one of a list of names, narrowing it to the list's
3
+ * type: a component's check of a prop against its allowed values.
4
+ */
5
+ export function isOneOf(names, value) {
6
+ return names.includes(value);
7
+ }