@opendata-ai/openchart-core 7.11.0 → 8.0.0-rc.2
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/index.d.ts +1154 -119
- package/dist/index.js +533 -42
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/styles.css.map +1 -0
- package/package.json +9 -3
- package/schema/chart.schema.json +8957 -0
- package/schema/table.schema.json +861 -0
- package/schema/vizspec.schema.json +17694 -0
- package/src/accessibility/alt-text.ts +39 -1
- package/src/accessibility/aria.ts +4 -2
- package/src/colors/__tests__/colorblind.test.ts +12 -0
- package/src/colors/colorblind.ts +11 -2
- package/src/colors/contrast.ts +11 -0
- package/src/colors/index.ts +9 -1
- package/src/colors/palettes.ts +47 -0
- package/src/helpers/__tests__/deep-merge.test.ts +54 -0
- package/src/helpers/__tests__/spec-builders.test.ts +3 -3
- package/src/helpers/deep-merge.ts +29 -0
- package/src/helpers/spec-builders.ts +7 -7
- package/src/index.ts +29 -1
- package/src/labels/collision.ts +1 -0
- package/src/layout/chrome.ts +24 -0
- package/src/layout/index.ts +1 -1
- package/src/locale/__tests__/format.test.ts +347 -11
- package/src/locale/format.ts +243 -18
- package/src/locale/index.ts +10 -1
- package/src/responsive/index.ts +2 -0
- package/src/responsive/metrics.ts +77 -10
- package/src/schema/__tests__/generated-artifacts.test.ts +42 -0
- package/src/schema/__tests__/schema.test.ts +179 -0
- package/src/styles/__tests__/reduced-motion-selectors.test.ts +28 -0
- package/src/styles/animation.css +197 -168
- package/src/styles/base.css +89 -62
- package/src/styles/chrome.css +173 -179
- package/src/styles/dark.css +38 -35
- package/src/styles/graph.css +116 -111
- package/src/styles/index.css +5 -0
- package/src/styles/keyframes.css +115 -100
- package/src/styles/legend.css +14 -12
- package/src/styles/reduced-motion.css +61 -40
- package/src/styles/series-search.css +153 -0
- package/src/styles/sparkline.css +14 -12
- package/src/styles/table-animation.css +82 -80
- package/src/styles/table.css +314 -302
- package/src/styles/token-definitions.ts +199 -0
- package/src/styles/tokens.css +132 -128
- package/src/styles/tooltip.css +109 -115
- package/src/styles/you-draw-it.css +126 -0
- package/src/types/__tests__/encoding.test.ts +86 -17
- package/src/types/__tests__/spec.test.ts +16 -12
- package/src/types/encoding.ts +69 -25
- package/src/types/events.ts +12 -0
- package/src/types/index.ts +39 -3
- package/src/types/layout.ts +414 -8
- package/src/types/schema-roots.ts +32 -0
- package/src/types/spec.ts +643 -84
- package/src/types/table.ts +3 -2
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
@layer oc.components {
|
|
2
|
+
/* ---------------------------------------------------------------------------
|
|
3
|
+
* Series search (seriesSearch)
|
|
4
|
+
*
|
|
5
|
+
* DOM combobox overlaid on the SVG band the engine reserves below chrome.
|
|
6
|
+
* The wrapper is absolutely positioned by the vanilla adapter (inline
|
|
7
|
+
* left/top/width/height), so everything here is visual only. All colors come
|
|
8
|
+
* from --oc-* tokens, which flip in .oc-dark.
|
|
9
|
+
* --------------------------------------------------------------------------- */
|
|
10
|
+
|
|
11
|
+
.oc-series-search {
|
|
12
|
+
position: absolute;
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: flex-end;
|
|
16
|
+
gap: 8px;
|
|
17
|
+
font-family: var(--oc-font-family);
|
|
18
|
+
z-index: 10;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Chips: removable filter tokens for the current selection. They flow to the
|
|
22
|
+
* left of the input and scroll horizontally rather than wrapping over the
|
|
23
|
+
* chart when a reader picks many series. */
|
|
24
|
+
.oc-series-search-chips {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 6px;
|
|
28
|
+
min-width: 0;
|
|
29
|
+
overflow-x: auto;
|
|
30
|
+
scrollbar-width: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.oc-series-search-chips::-webkit-scrollbar {
|
|
34
|
+
display: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.oc-series-search-chip {
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: 4px;
|
|
41
|
+
padding: 3px 4px 3px 10px;
|
|
42
|
+
border: 1px solid var(--oc-border);
|
|
43
|
+
border-radius: 999px;
|
|
44
|
+
background: var(--oc-secondary);
|
|
45
|
+
color: var(--oc-text-secondary);
|
|
46
|
+
font-size: 12px;
|
|
47
|
+
font-weight: 500;
|
|
48
|
+
line-height: 16px;
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.oc-series-search-chip-remove {
|
|
53
|
+
display: inline-flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
/* 16px glyph, but a >=24px hit area (WCAG 2.5.5 target size) via padding
|
|
57
|
+
pulled back with negative margin so the chip layout stays tight. */
|
|
58
|
+
width: 16px;
|
|
59
|
+
height: 16px;
|
|
60
|
+
padding: 4px;
|
|
61
|
+
margin: -4px -2px -4px -4px;
|
|
62
|
+
border: none;
|
|
63
|
+
border-radius: 50%;
|
|
64
|
+
background: transparent;
|
|
65
|
+
color: var(--oc-text-muted);
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
transition:
|
|
68
|
+
color 0.15s,
|
|
69
|
+
background-color 0.15s;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.oc-series-search-chip-remove:hover {
|
|
73
|
+
color: var(--oc-text);
|
|
74
|
+
background: var(--oc-hover-bg);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.oc-series-search-chip-remove:focus-visible {
|
|
78
|
+
outline: 2px solid var(--oc-focus);
|
|
79
|
+
outline-offset: 1px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.oc-series-search-chip-remove svg {
|
|
83
|
+
display: block;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Combobox: input + popup listbox. Styling matches the table search input
|
|
87
|
+
* (border, radius, focus ring) so the two search surfaces read as one system. */
|
|
88
|
+
.oc-series-search-box {
|
|
89
|
+
position: relative;
|
|
90
|
+
flex: 0 1 220px;
|
|
91
|
+
min-width: 120px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.oc-series-search-icon {
|
|
95
|
+
position: absolute;
|
|
96
|
+
left: 9px;
|
|
97
|
+
top: 50%;
|
|
98
|
+
transform: translateY(-50%);
|
|
99
|
+
color: var(--oc-text-muted);
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Shared skin provided by the grouped rule in table.css.
|
|
104
|
+
Only divergent props live here. */
|
|
105
|
+
.oc-series-search-input {
|
|
106
|
+
height: 32px;
|
|
107
|
+
padding: 0 10px 0 28px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.oc-series-search-listbox {
|
|
111
|
+
position: absolute;
|
|
112
|
+
top: calc(100% + 4px);
|
|
113
|
+
right: 0;
|
|
114
|
+
min-width: 100%;
|
|
115
|
+
max-height: 240px;
|
|
116
|
+
overflow-y: auto;
|
|
117
|
+
margin: 0;
|
|
118
|
+
padding: 4px;
|
|
119
|
+
list-style: none;
|
|
120
|
+
border: 1px solid var(--oc-border);
|
|
121
|
+
border-radius: 8px;
|
|
122
|
+
background: var(--oc-card);
|
|
123
|
+
box-shadow: var(--oc-tooltip-shadow);
|
|
124
|
+
z-index: 20;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.oc-series-search-option {
|
|
128
|
+
padding: 6px 10px;
|
|
129
|
+
border-radius: 4px;
|
|
130
|
+
font-size: 13px;
|
|
131
|
+
color: var(--oc-text);
|
|
132
|
+
cursor: pointer;
|
|
133
|
+
white-space: nowrap;
|
|
134
|
+
overflow: hidden;
|
|
135
|
+
text-overflow: ellipsis;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.oc-series-search-option[aria-selected="true"],
|
|
139
|
+
.oc-series-search-option:hover {
|
|
140
|
+
background: var(--oc-hover-bg);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* The typed substring within each suggestion. */
|
|
144
|
+
.oc-series-search-match {
|
|
145
|
+
font-weight: 600;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.oc-series-search-empty {
|
|
149
|
+
padding: 6px 10px;
|
|
150
|
+
font-size: 12px;
|
|
151
|
+
color: var(--oc-text-muted);
|
|
152
|
+
}
|
|
153
|
+
}
|
package/src/styles/sparkline.css
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
@layer oc.components {
|
|
2
|
+
/**
|
|
3
|
+
* Sparkline display mode.
|
|
4
|
+
*
|
|
5
|
+
* Stamped on the SVG root as data-display="sparkline" by the renderer when
|
|
6
|
+
* the spec sets display: 'sparkline'. Strips any inherited padding/margin
|
|
7
|
+
* so the mark renders truly edge-to-edge in tight container layouts (KPI
|
|
8
|
+
* cards, table cells, dashboard tiles).
|
|
9
|
+
*/
|
|
9
10
|
|
|
10
|
-
.oc-chart[data-display="sparkline"] {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
.oc-chart[data-display="sparkline"] {
|
|
12
|
+
display: block;
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
}
|
|
14
16
|
}
|
|
@@ -1,91 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
@layer oc.animation {
|
|
2
|
+
/* ---------------------------------------------------------------------------
|
|
3
|
+
* Table entrance animations (.oc-table-wrapper.oc-animate)
|
|
4
|
+
* --------------------------------------------------------------------------- */
|
|
4
5
|
|
|
5
|
-
.oc-table-wrapper.oc-animate {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
.oc-table-wrapper.oc-animate {
|
|
7
|
+
/* Chrome (title/subtitle): fade + slide up */
|
|
8
|
+
& > .oc-chrome {
|
|
9
|
+
animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)
|
|
10
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
11
|
+
}
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
/* Table header: quick fade before rows start */
|
|
14
|
+
& thead {
|
|
15
|
+
animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4)
|
|
16
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
17
|
+
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
/* Row entrance: slide up only, no opacity (cells handle their own fading
|
|
20
|
+
to avoid opacity compounding between row and cell animations) */
|
|
21
|
+
& tbody tr {
|
|
22
|
+
animation: oc-table-enter-row var(--oc-animation-duration)
|
|
23
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
24
|
+
animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));
|
|
25
|
+
}
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
/* Cell text: fade in synced with row slide */
|
|
28
|
+
& tbody td {
|
|
29
|
+
animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)
|
|
30
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
31
|
+
animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));
|
|
32
|
+
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
34
|
+
/* Heatmap/category cell backgrounds: longer fade, delayed after row appears */
|
|
35
|
+
& td.oc-table-heatmap,
|
|
36
|
+
& td.oc-table-category {
|
|
37
|
+
animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.7)
|
|
38
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
39
|
+
animation-delay: calc(
|
|
40
|
+
var(--oc-animation-stagger) *
|
|
41
|
+
var(--oc-row-index, 0) +
|
|
42
|
+
var(--oc-animation-duration) *
|
|
43
|
+
0.3
|
|
44
|
+
);
|
|
45
|
+
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
/* Bar fill: clip-path grow only (no opacity change to preserve resting
|
|
48
|
+
opacity: 0.15 from table.css) */
|
|
49
|
+
& .oc-table-bar-fill {
|
|
50
|
+
animation: oc-table-enter-bar-fill calc(var(--oc-animation-duration) * 0.8)
|
|
51
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
52
|
+
animation-delay: calc(
|
|
53
|
+
var(--oc-animation-stagger) *
|
|
54
|
+
var(--oc-row-index, 0) +
|
|
55
|
+
var(--oc-animation-duration) *
|
|
56
|
+
0.3
|
|
57
|
+
);
|
|
58
|
+
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
/* Sparkline SVG: clip-path reveal left-to-right. Targets the SVG directly
|
|
61
|
+
(not the wrapper) to avoid clipping absolutely-positioned dots and labels. */
|
|
62
|
+
& .oc-table-sparkline > svg {
|
|
63
|
+
animation: oc-enter-line calc(var(--oc-animation-duration) * 0.8)
|
|
64
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
65
|
+
animation-delay: calc(
|
|
66
|
+
var(--oc-animation-stagger) *
|
|
67
|
+
var(--oc-row-index, 0) +
|
|
68
|
+
var(--oc-animation-duration) *
|
|
69
|
+
0.4
|
|
70
|
+
);
|
|
71
|
+
}
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
/* Sparkline dots and labels: fade in after the line draws through */
|
|
74
|
+
& .oc-table-sparkline-dot,
|
|
75
|
+
& .oc-table-sparkline-labels {
|
|
76
|
+
animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.3)
|
|
77
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
78
|
+
animation-delay: calc(
|
|
79
|
+
var(--oc-animation-stagger) *
|
|
80
|
+
var(--oc-row-index, 0) +
|
|
81
|
+
var(--oc-animation-duration) *
|
|
82
|
+
0.8
|
|
83
|
+
);
|
|
84
|
+
}
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
/* Search and pagination: quick fade on mount */
|
|
87
|
+
& .oc-table-search,
|
|
88
|
+
& .oc-table-pagination {
|
|
89
|
+
animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)
|
|
90
|
+
var(--oc-animation-ease, var(--oc-ease-smooth)) both;
|
|
91
|
+
}
|
|
90
92
|
}
|
|
91
93
|
}
|