@opendata-ai/openchart-vue 6.3.0 → 6.5.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/index.d.ts +16 -1
- package/dist/index.js +46 -5
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -764
- package/package.json +4 -4
- package/src/Chart.ts +56 -3
- package/src/DataTable.ts +1 -1
- package/src/Graph.ts +1 -1
- package/src/__tests__/Chart.test.ts +6 -6
- package/src/__tests__/DataTable.test.ts +2 -2
- package/src/__tests__/Graph.test.ts +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opendata-ai/openchart-vue",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.0",
|
|
4
4
|
"description": "Vue 3 components for openchart: <Chart />, <DataTable />, <Graph />, <VizThemeProvider />",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Riley Hilliard",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"typecheck": "tsc --noEmit"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@opendata-ai/openchart-core": "6.
|
|
53
|
-
"@opendata-ai/openchart-engine": "6.
|
|
54
|
-
"@opendata-ai/openchart-vanilla": "6.
|
|
52
|
+
"@opendata-ai/openchart-core": "6.5.0",
|
|
53
|
+
"@opendata-ai/openchart-engine": "6.5.0",
|
|
54
|
+
"@opendata-ai/openchart-vanilla": "6.5.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"vue": ">=3.3.0"
|
package/src/Chart.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
ChartSpec,
|
|
13
13
|
DarkMode,
|
|
14
14
|
ElementEdit,
|
|
15
|
+
ElementRef,
|
|
15
16
|
GraphSpec,
|
|
16
17
|
LayerSpec,
|
|
17
18
|
MarkEvent,
|
|
@@ -64,6 +65,10 @@ export const Chart = defineComponent({
|
|
|
64
65
|
type: [String, Object] as PropType<string | CSSProperties>,
|
|
65
66
|
default: undefined,
|
|
66
67
|
},
|
|
68
|
+
selectedElement: {
|
|
69
|
+
type: Object as PropType<ElementRef>,
|
|
70
|
+
default: undefined,
|
|
71
|
+
},
|
|
67
72
|
},
|
|
68
73
|
emits: {
|
|
69
74
|
'mark-click': (_event: MarkEvent) => true,
|
|
@@ -73,9 +78,12 @@ export const Chart = defineComponent({
|
|
|
73
78
|
'annotation-click': (_annotation: Annotation, _event: MouseEvent) => true,
|
|
74
79
|
'annotation-edit': (_annotation: TextAnnotation, _updatedOffset: AnnotationOffset) => true,
|
|
75
80
|
edit: (_edit: ElementEdit) => true,
|
|
81
|
+
select: (_element: ElementRef) => true,
|
|
82
|
+
deselect: (_element: ElementRef) => true,
|
|
83
|
+
'text-edit': (_element: ElementRef, _oldText: string, _newText: string) => true,
|
|
76
84
|
'data-point-click': (_data: Record<string, unknown>) => true,
|
|
77
85
|
},
|
|
78
|
-
setup(props, { emit }) {
|
|
86
|
+
setup(props, { emit, expose }) {
|
|
79
87
|
const containerRef = ref<HTMLDivElement | null>(null);
|
|
80
88
|
let instance: ChartInstance | null = null;
|
|
81
89
|
let prevSpec = '';
|
|
@@ -92,6 +100,9 @@ export const Chart = defineComponent({
|
|
|
92
100
|
const hasAnnotationEditListener =
|
|
93
101
|
'onAnnotation-edit' in vnodeProps || 'onAnnotationEdit' in vnodeProps;
|
|
94
102
|
const hasEditListener = 'onEdit' in vnodeProps;
|
|
103
|
+
const hasSelectListener = 'onSelect' in vnodeProps;
|
|
104
|
+
const hasDeselectListener = 'onDeselect' in vnodeProps;
|
|
105
|
+
const hasTextEditListener = 'onText-edit' in vnodeProps || 'onTextEdit' in vnodeProps;
|
|
95
106
|
|
|
96
107
|
function resolveTheme(): ThemeConfig | undefined {
|
|
97
108
|
return props.theme ?? contextTheme?.value;
|
|
@@ -125,6 +136,19 @@ export const Chart = defineComponent({
|
|
|
125
136
|
}
|
|
126
137
|
: {}),
|
|
127
138
|
...(hasEditListener ? { onEdit: (edit: ElementEdit) => emit('edit', edit) } : {}),
|
|
139
|
+
...(hasSelectListener
|
|
140
|
+
? { onSelect: (element: ElementRef) => emit('select', element) }
|
|
141
|
+
: {}),
|
|
142
|
+
...(hasDeselectListener
|
|
143
|
+
? { onDeselect: (element: ElementRef) => emit('deselect', element) }
|
|
144
|
+
: {}),
|
|
145
|
+
...(hasTextEditListener
|
|
146
|
+
? {
|
|
147
|
+
onTextEdit: (element: ElementRef, oldText: string, newText: string) =>
|
|
148
|
+
emit('text-edit', element, oldText, newText),
|
|
149
|
+
}
|
|
150
|
+
: {}),
|
|
151
|
+
...(props.selectedElement ? { selectedElement: props.selectedElement } : {}),
|
|
128
152
|
responsive: true,
|
|
129
153
|
};
|
|
130
154
|
|
|
@@ -138,6 +162,22 @@ export const Chart = defineComponent({
|
|
|
138
162
|
prevSpec = '';
|
|
139
163
|
}
|
|
140
164
|
|
|
165
|
+
// Expose imperative methods for parent ref access
|
|
166
|
+
expose({
|
|
167
|
+
getSelectedElement(): ElementRef | null {
|
|
168
|
+
return instance?.getSelectedElement() ?? null;
|
|
169
|
+
},
|
|
170
|
+
select(elementRef: ElementRef): void {
|
|
171
|
+
instance?.select(elementRef);
|
|
172
|
+
},
|
|
173
|
+
deselect(): void {
|
|
174
|
+
instance?.deselect();
|
|
175
|
+
},
|
|
176
|
+
get instance() {
|
|
177
|
+
return instance;
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
141
181
|
onMounted(() => {
|
|
142
182
|
mountChart();
|
|
143
183
|
});
|
|
@@ -153,7 +193,20 @@ export const Chart = defineComponent({
|
|
|
153
193
|
if (!instance) return;
|
|
154
194
|
if (newVal !== prevSpec) {
|
|
155
195
|
prevSpec = newVal;
|
|
156
|
-
instance.update(props.spec);
|
|
196
|
+
instance.update(props.spec, { selectedElement: props.selectedElement });
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// Watch selectedElement prop changes
|
|
202
|
+
watch(
|
|
203
|
+
() => props.selectedElement,
|
|
204
|
+
(newVal) => {
|
|
205
|
+
if (!instance) return;
|
|
206
|
+
if (newVal) {
|
|
207
|
+
instance.select(newVal);
|
|
208
|
+
} else {
|
|
209
|
+
instance.deselect();
|
|
157
210
|
}
|
|
158
211
|
},
|
|
159
212
|
);
|
|
@@ -174,7 +227,7 @@ export const Chart = defineComponent({
|
|
|
174
227
|
);
|
|
175
228
|
|
|
176
229
|
const rootClass = () => {
|
|
177
|
-
const base = '
|
|
230
|
+
const base = 'oc-chart-root';
|
|
178
231
|
return props.class ? `${base} ${props.class}` : base;
|
|
179
232
|
};
|
|
180
233
|
|
package/src/DataTable.ts
CHANGED
package/src/Graph.ts
CHANGED
|
@@ -67,21 +67,21 @@ describe('Chart', () => {
|
|
|
67
67
|
const wrapper = await mountChart({ spec: lineSpec });
|
|
68
68
|
const svg = wrapper.find('svg');
|
|
69
69
|
expect(svg.exists()).toBe(true);
|
|
70
|
-
expect(svg.attributes('class')).toBe('
|
|
70
|
+
expect(svg.attributes('class')).toBe('oc-chart');
|
|
71
71
|
wrapper.unmount();
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
it('renders chrome text elements', async () => {
|
|
75
75
|
const wrapper = await mountChart({ spec: lineSpec });
|
|
76
76
|
|
|
77
|
-
const title = wrapper.find('.
|
|
77
|
+
const title = wrapper.find('.oc-title');
|
|
78
78
|
expect(title.exists()).toBe(true);
|
|
79
79
|
expect(title.text()).toBe('GDP Growth');
|
|
80
80
|
|
|
81
|
-
const subtitle = wrapper.find('.
|
|
81
|
+
const subtitle = wrapper.find('.oc-subtitle');
|
|
82
82
|
expect(subtitle.text()).toBe('US vs UK over time');
|
|
83
83
|
|
|
84
|
-
const source = wrapper.find('.
|
|
84
|
+
const source = wrapper.find('.oc-source');
|
|
85
85
|
expect(source.text()).toBe('World Bank');
|
|
86
86
|
wrapper.unmount();
|
|
87
87
|
});
|
|
@@ -89,13 +89,13 @@ describe('Chart', () => {
|
|
|
89
89
|
it('spec changes trigger re-render', async () => {
|
|
90
90
|
const wrapper = await mountChart({ spec: lineSpec });
|
|
91
91
|
|
|
92
|
-
const titleBefore = wrapper.find('.
|
|
92
|
+
const titleBefore = wrapper.find('.oc-title');
|
|
93
93
|
expect(titleBefore.text()).toBe('GDP Growth');
|
|
94
94
|
|
|
95
95
|
await wrapper.setProps({ spec: barSpec });
|
|
96
96
|
await flushPromises();
|
|
97
97
|
|
|
98
|
-
const titleAfter = wrapper.find('.
|
|
98
|
+
const titleAfter = wrapper.find('.oc-title');
|
|
99
99
|
expect(titleAfter.text()).toBe('Updated Title');
|
|
100
100
|
wrapper.unmount();
|
|
101
101
|
});
|
|
@@ -79,13 +79,13 @@ describe('DataTable', () => {
|
|
|
79
79
|
it('spec changes trigger re-render', async () => {
|
|
80
80
|
const wrapper = await mountTable({ spec: tableSpec });
|
|
81
81
|
|
|
82
|
-
const titleBefore = wrapper.find('.
|
|
82
|
+
const titleBefore = wrapper.find('.oc-table-title');
|
|
83
83
|
expect(titleBefore.text()).toBe('People Table');
|
|
84
84
|
|
|
85
85
|
await wrapper.setProps({ spec: updatedSpec });
|
|
86
86
|
await flushPromises();
|
|
87
87
|
|
|
88
|
-
const titleAfter = wrapper.find('.
|
|
88
|
+
const titleAfter = wrapper.find('.oc-table-title');
|
|
89
89
|
expect(titleAfter.text()).toBe('Updated Table');
|
|
90
90
|
|
|
91
91
|
const headersAfter = wrapper.findAll('thead th');
|
|
@@ -72,11 +72,11 @@ describe('Graph', () => {
|
|
|
72
72
|
it('renders chrome text elements', async () => {
|
|
73
73
|
const wrapper = await mountGraph({ spec: basicSpec });
|
|
74
74
|
|
|
75
|
-
const title = wrapper.find('.
|
|
75
|
+
const title = wrapper.find('.oc-title');
|
|
76
76
|
expect(title.exists()).toBe(true);
|
|
77
77
|
expect(title.text()).toBe('Test Graph');
|
|
78
78
|
|
|
79
|
-
const subtitle = wrapper.find('.
|
|
79
|
+
const subtitle = wrapper.find('.oc-subtitle');
|
|
80
80
|
expect(subtitle.text()).toBe('A simple test graph');
|
|
81
81
|
wrapper.unmount();
|
|
82
82
|
});
|
|
@@ -84,13 +84,13 @@ describe('Graph', () => {
|
|
|
84
84
|
it('spec changes trigger re-render', async () => {
|
|
85
85
|
const wrapper = await mountGraph({ spec: basicSpec });
|
|
86
86
|
|
|
87
|
-
const titleBefore = wrapper.find('.
|
|
87
|
+
const titleBefore = wrapper.find('.oc-title');
|
|
88
88
|
expect(titleBefore.text()).toBe('Test Graph');
|
|
89
89
|
|
|
90
90
|
await wrapper.setProps({ spec: updatedSpec });
|
|
91
91
|
await flushPromises();
|
|
92
92
|
|
|
93
|
-
const titleAfter = wrapper.find('.
|
|
93
|
+
const titleAfter = wrapper.find('.oc-title');
|
|
94
94
|
expect(titleAfter.text()).toBe('Updated Graph');
|
|
95
95
|
wrapper.unmount();
|
|
96
96
|
});
|