@opendata-ai/openchart-core 7.11.0 → 8.0.0-rc.10

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 (59) hide show
  1. package/dist/index.d.ts +1348 -132
  2. package/dist/index.js +556 -48
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +2 -1
  5. package/dist/styles.css.map +1 -0
  6. package/package.json +9 -3
  7. package/schema/chart.schema.json +9086 -0
  8. package/schema/table.schema.json +861 -0
  9. package/schema/vizspec.schema.json +17922 -0
  10. package/src/accessibility/alt-text.ts +39 -1
  11. package/src/accessibility/aria.ts +4 -2
  12. package/src/colors/__tests__/colorblind.test.ts +12 -0
  13. package/src/colors/colorblind.ts +11 -2
  14. package/src/colors/contrast.ts +11 -0
  15. package/src/colors/index.ts +9 -1
  16. package/src/colors/palettes.ts +47 -0
  17. package/src/helpers/__tests__/deep-merge.test.ts +54 -0
  18. package/src/helpers/__tests__/spec-builders.test.ts +3 -3
  19. package/src/helpers/deep-merge.ts +29 -0
  20. package/src/helpers/spec-builders.ts +7 -7
  21. package/src/index.ts +29 -1
  22. package/src/labels/collision.ts +1 -0
  23. package/src/layout/chrome.ts +24 -0
  24. package/src/layout/index.ts +1 -1
  25. package/src/locale/__tests__/format.test.ts +347 -11
  26. package/src/locale/format.ts +243 -18
  27. package/src/locale/index.ts +10 -1
  28. package/src/responsive/breakpoints.ts +7 -2
  29. package/src/responsive/index.ts +2 -0
  30. package/src/responsive/metrics.ts +77 -10
  31. package/src/schema/__tests__/generated-artifacts.test.ts +42 -0
  32. package/src/schema/__tests__/schema.test.ts +179 -0
  33. package/src/styles/__tests__/reduced-motion-selectors.test.ts +28 -0
  34. package/src/styles/animation.css +211 -168
  35. package/src/styles/base.css +89 -62
  36. package/src/styles/chrome.css +173 -179
  37. package/src/styles/dark.css +38 -35
  38. package/src/styles/graph.css +116 -111
  39. package/src/styles/index.css +5 -0
  40. package/src/styles/keyframes.css +130 -99
  41. package/src/styles/legend.css +14 -12
  42. package/src/styles/reduced-motion.css +61 -40
  43. package/src/styles/series-search.css +153 -0
  44. package/src/styles/sparkline.css +14 -12
  45. package/src/styles/table-animation.css +82 -80
  46. package/src/styles/table.css +314 -302
  47. package/src/styles/token-definitions.ts +199 -0
  48. package/src/styles/tokens.css +132 -128
  49. package/src/styles/tooltip.css +109 -115
  50. package/src/styles/you-draw-it.css +126 -0
  51. package/src/types/__tests__/encoding.test.ts +86 -17
  52. package/src/types/__tests__/spec.test.ts +16 -12
  53. package/src/types/encoding.ts +69 -25
  54. package/src/types/events.ts +107 -13
  55. package/src/types/index.ts +42 -3
  56. package/src/types/layout.ts +484 -11
  57. package/src/types/schema-roots.ts +32 -0
  58. package/src/types/spec.ts +718 -87
  59. 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
+ }
@@ -1,14 +1,16 @@
1
- /**
2
- * Sparkline display mode.
3
- *
4
- * Stamped on the SVG root as data-display="sparkline" by the renderer when
5
- * the spec sets display: 'sparkline'. Strips any inherited padding/margin
6
- * so the mark renders truly edge-to-edge in tight container layouts (KPI
7
- * cards, table cells, dashboard tiles).
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
- display: block;
12
- margin: 0;
13
- padding: 0;
11
+ .oc-chart[data-display="sparkline"] {
12
+ display: block;
13
+ margin: 0;
14
+ padding: 0;
15
+ }
14
16
  }
@@ -1,91 +1,93 @@
1
- /* ---------------------------------------------------------------------------
2
- * Table entrance animations (.oc-table-wrapper.oc-animate)
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
- /* Chrome (title/subtitle): fade + slide up */
7
- & > .oc-chrome {
8
- animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)
9
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
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
- /* Table header: quick fade before rows start */
13
- & thead {
14
- animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4)
15
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
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
- /* Row entrance: slide up only, no opacity (cells handle their own fading
19
- to avoid opacity compounding between row and cell animations) */
20
- & tbody tr {
21
- animation: oc-table-enter-row var(--oc-animation-duration)
22
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
23
- animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));
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
- /* Cell text: fade in synced with row slide */
27
- & tbody td {
28
- animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)
29
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
30
- animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));
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
- /* Heatmap/category cell backgrounds: longer fade, delayed after row appears */
34
- & td.oc-table-heatmap,
35
- & td.oc-table-category {
36
- animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.7)
37
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
38
- animation-delay: calc(
39
- var(--oc-animation-stagger) *
40
- var(--oc-row-index, 0) +
41
- var(--oc-animation-duration) *
42
- 0.3
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
- /* Bar fill: clip-path grow only (no opacity change to preserve resting
47
- opacity: 0.15 from table.css) */
48
- & .oc-table-bar-fill {
49
- animation: oc-table-enter-bar-fill calc(var(--oc-animation-duration) * 0.8)
50
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
51
- animation-delay: calc(
52
- var(--oc-animation-stagger) *
53
- var(--oc-row-index, 0) +
54
- var(--oc-animation-duration) *
55
- 0.3
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
- /* Sparkline SVG: clip-path reveal left-to-right. Targets the SVG directly
60
- (not the wrapper) to avoid clipping absolutely-positioned dots and labels. */
61
- & .oc-table-sparkline > svg {
62
- animation: oc-enter-line calc(var(--oc-animation-duration) * 0.8)
63
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
64
- animation-delay: calc(
65
- var(--oc-animation-stagger) *
66
- var(--oc-row-index, 0) +
67
- var(--oc-animation-duration) *
68
- 0.4
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
- /* Sparkline dots and labels: fade in after the line draws through */
73
- & .oc-table-sparkline-dot,
74
- & .oc-table-sparkline-labels {
75
- animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.3)
76
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
77
- animation-delay: calc(
78
- var(--oc-animation-stagger) *
79
- var(--oc-row-index, 0) +
80
- var(--oc-animation-duration) *
81
- 0.8
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
- /* Search and pagination: quick fade on mount */
86
- & .oc-table-search,
87
- & .oc-table-pagination {
88
- animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)
89
- var(--oc-animation-ease, var(--oc-ease-smooth)) both;
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
  }