@opendata-ai/openchart-core 8.0.0-rc.2 → 8.0.0-rc.21
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 +490 -25
- package/dist/index.js +57 -19
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -2
- package/schema/chart.schema.json +485 -35
- package/schema/table.schema.json +35 -1
- package/schema/vizspec.schema.json +1305 -120
- package/src/accessibility/__tests__/alt-text.test.ts +0 -110
- package/src/accessibility/__tests__/aria.test.ts +0 -125
- package/src/accessibility/alt-text.ts +0 -155
- package/src/accessibility/aria.ts +0 -75
- package/src/accessibility/index.ts +0 -6
- package/src/colors/__tests__/colorblind.test.ts +0 -75
- package/src/colors/__tests__/contrast.test.ts +0 -119
- package/src/colors/__tests__/palettes.test.ts +0 -74
- package/src/colors/colorblind.ts +0 -131
- package/src/colors/contrast.ts +0 -143
- package/src/colors/index.ts +0 -36
- package/src/colors/palettes.ts +0 -206
- package/src/helpers/__tests__/deep-merge.test.ts +0 -54
- package/src/helpers/__tests__/spec-builders.test.ts +0 -338
- package/src/helpers/deep-merge.ts +0 -29
- package/src/helpers/spec-builders.ts +0 -479
- package/src/index.ts +0 -215
- package/src/labels/__tests__/collision.test.ts +0 -310
- package/src/labels/collision.ts +0 -249
- package/src/labels/index.ts +0 -13
- package/src/layout/__tests__/chrome.test.ts +0 -208
- package/src/layout/__tests__/text-measure.test.ts +0 -57
- package/src/layout/chrome.ts +0 -470
- package/src/layout/index.ts +0 -18
- package/src/layout/text-measure.ts +0 -404
- package/src/layout/text-wrap.ts +0 -93
- package/src/locale/__tests__/format.test.ts +0 -606
- package/src/locale/format.ts +0 -459
- package/src/locale/index.ts +0 -21
- package/src/responsive/__tests__/breakpoints.test.ts +0 -146
- package/src/responsive/__tests__/metrics.test.ts +0 -52
- package/src/responsive/breakpoints.ts +0 -172
- package/src/responsive/index.ts +0 -53
- package/src/responsive/metrics.ts +0 -299
- package/src/schema/__tests__/generated-artifacts.test.ts +0 -42
- package/src/schema/__tests__/schema.test.ts +0 -179
- package/src/styles/__tests__/reduced-motion-selectors.test.ts +0 -28
- package/src/styles/animation.css +0 -199
- package/src/styles/base.css +0 -102
- package/src/styles/chrome.css +0 -174
- package/src/styles/dark.css +0 -44
- package/src/styles/graph.css +0 -135
- package/src/styles/index.css +0 -28
- package/src/styles/keyframes.css +0 -135
- package/src/styles/legend.css +0 -18
- package/src/styles/reduced-motion.css +0 -67
- package/src/styles/series-search.css +0 -153
- package/src/styles/sparkline.css +0 -16
- package/src/styles/table-animation.css +0 -93
- package/src/styles/table.css +0 -398
- package/src/styles/token-definitions.ts +0 -199
- package/src/styles/tokens.css +0 -156
- package/src/styles/tooltip.css +0 -126
- package/src/styles/you-draw-it.css +0 -126
- package/src/theme/__tests__/dark-mode.test.ts +0 -232
- package/src/theme/__tests__/defaults.test.ts +0 -73
- package/src/theme/__tests__/resolve.test.ts +0 -277
- package/src/theme/dark-mode.ts +0 -258
- package/src/theme/defaults.ts +0 -110
- package/src/theme/index.ts +0 -8
- package/src/theme/presets.ts +0 -64
- package/src/theme/resolve.ts +0 -312
- package/src/types/__tests__/encoding.test.ts +0 -368
- package/src/types/__tests__/gradient.test.ts +0 -95
- package/src/types/__tests__/spec.test.ts +0 -499
- package/src/types/encoding.ts +0 -280
- package/src/types/events.ts +0 -154
- package/src/types/index.ts +0 -287
- package/src/types/layout.ts +0 -1966
- package/src/types/schema-roots.ts +0 -32
- package/src/types/spec.ts +0 -2867
- package/src/types/table.ts +0 -108
- package/src/types/theme.ts +0 -209
|
@@ -1,368 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { MARK_ENCODING_RULES } from '../encoding';
|
|
3
|
-
import type { MarkType } from '../spec';
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// Helpers
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
function getChannelNames(markType: MarkType): string[] {
|
|
10
|
-
return Object.keys(MARK_ENCODING_RULES[markType]);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function getRequiredChannels(markType: MarkType): string[] {
|
|
14
|
-
return Object.entries(MARK_ENCODING_RULES[markType])
|
|
15
|
-
.filter(([, rule]) => rule.required)
|
|
16
|
-
.map(([ch]) => ch);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function getOptionalChannels(markType: MarkType): string[] {
|
|
20
|
-
return Object.entries(MARK_ENCODING_RULES[markType])
|
|
21
|
-
.filter(([, rule]) => !rule.required)
|
|
22
|
-
.map(([ch]) => ch);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
// Tests
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
|
|
29
|
-
describe('MARK_ENCODING_RULES', () => {
|
|
30
|
-
it('has entries for all 16 mark types', () => {
|
|
31
|
-
const expectedTypes: MarkType[] = [
|
|
32
|
-
'bar',
|
|
33
|
-
'line',
|
|
34
|
-
'area',
|
|
35
|
-
'point',
|
|
36
|
-
'circle',
|
|
37
|
-
'arc',
|
|
38
|
-
'text',
|
|
39
|
-
'rule',
|
|
40
|
-
'tick',
|
|
41
|
-
'rect',
|
|
42
|
-
'lollipop',
|
|
43
|
-
'beeswarm',
|
|
44
|
-
'range',
|
|
45
|
-
'waffle',
|
|
46
|
-
'calendar',
|
|
47
|
-
'parliament',
|
|
48
|
-
];
|
|
49
|
-
for (const type of expectedTypes) {
|
|
50
|
-
expect(MARK_ENCODING_RULES[type]).toBeDefined();
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('every mark type has x, y, color, size, and detail channels', () => {
|
|
55
|
-
const baseChannels = ['x', 'y', 'color', 'size', 'detail'];
|
|
56
|
-
for (const [_markType, rules] of Object.entries(MARK_ENCODING_RULES)) {
|
|
57
|
-
for (const ch of baseChannels) {
|
|
58
|
-
expect(rules[ch as keyof typeof rules]).toBeDefined();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('bar encoding rules', () => {
|
|
65
|
-
it('requires x and y', () => {
|
|
66
|
-
expect(getRequiredChannels('bar')).toContain('x');
|
|
67
|
-
expect(getRequiredChannels('bar')).toContain('y');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('supports x2 and y2 as optional', () => {
|
|
71
|
-
expect(getOptionalChannels('bar')).toContain('x2');
|
|
72
|
-
expect(getOptionalChannels('bar')).toContain('y2');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('supports opacity, tooltip, detail', () => {
|
|
76
|
-
const optionals = getOptionalChannels('bar');
|
|
77
|
-
expect(optionals).toContain('opacity');
|
|
78
|
-
expect(optionals).toContain('tooltip');
|
|
79
|
-
expect(optionals).toContain('detail');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('does not support shape, strokeDash, text, theta, href, order, radius', () => {
|
|
83
|
-
const channels = getChannelNames('bar');
|
|
84
|
-
expect(channels).not.toContain('shape');
|
|
85
|
-
expect(channels).not.toContain('strokeDash');
|
|
86
|
-
expect(channels).not.toContain('text');
|
|
87
|
-
expect(channels).not.toContain('theta');
|
|
88
|
-
expect(channels).not.toContain('href');
|
|
89
|
-
expect(channels).not.toContain('order');
|
|
90
|
-
expect(channels).not.toContain('radius');
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
describe('line encoding rules', () => {
|
|
95
|
-
it('requires x (temporal/ordinal) and y (quantitative)', () => {
|
|
96
|
-
const rules = MARK_ENCODING_RULES.line;
|
|
97
|
-
expect(rules.x.required).toBe(true);
|
|
98
|
-
expect(rules.x.allowedTypes).toContain('temporal');
|
|
99
|
-
expect(rules.y.required).toBe(true);
|
|
100
|
-
expect(rules.y.allowedTypes).toContain('quantitative');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('supports strokeDash as optional', () => {
|
|
104
|
-
expect(getOptionalChannels('line')).toContain('strokeDash');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('does not support shape, text, theta, radius, x2, y2', () => {
|
|
108
|
-
const channels = getChannelNames('line');
|
|
109
|
-
expect(channels).not.toContain('shape');
|
|
110
|
-
expect(channels).not.toContain('text');
|
|
111
|
-
expect(channels).not.toContain('theta');
|
|
112
|
-
expect(channels).not.toContain('radius');
|
|
113
|
-
expect(channels).not.toContain('x2');
|
|
114
|
-
expect(channels).not.toContain('y2');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('does not support href or order (removed dead channels)', () => {
|
|
118
|
-
const channels = getChannelNames('line');
|
|
119
|
-
expect(channels).not.toContain('href');
|
|
120
|
-
expect(channels).not.toContain('order');
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('point encoding rules', () => {
|
|
125
|
-
it('accepts all four field types on x and y', () => {
|
|
126
|
-
const rules = MARK_ENCODING_RULES.point;
|
|
127
|
-
for (const axis of ['x', 'y'] as const) {
|
|
128
|
-
expect(rules[axis].required).toBe(true);
|
|
129
|
-
expect(rules[axis].allowedTypes).toContain('quantitative');
|
|
130
|
-
expect(rules[axis].allowedTypes).toContain('temporal');
|
|
131
|
-
expect(rules[axis].allowedTypes).toContain('nominal');
|
|
132
|
-
expect(rules[axis].allowedTypes).toContain('ordinal');
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('does not support shape (removed dead channel)', () => {
|
|
137
|
-
expect(getChannelNames('point')).not.toContain('shape');
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('supports size as optional quantitative', () => {
|
|
141
|
-
const rules = MARK_ENCODING_RULES.point;
|
|
142
|
-
expect(rules.size.required).toBe(false);
|
|
143
|
-
expect(rules.size.allowedTypes).toContain('quantitative');
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
describe('arc encoding rules', () => {
|
|
148
|
-
it('requires theta (quantitative) and color (nominal/ordinal)', () => {
|
|
149
|
-
const rules = MARK_ENCODING_RULES.arc;
|
|
150
|
-
expect(rules.theta.required).toBe(true);
|
|
151
|
-
expect(rules.theta.allowedTypes).toContain('quantitative');
|
|
152
|
-
expect(rules.color.required).toBe(true);
|
|
153
|
-
expect(rules.color.allowedTypes).toContain('nominal');
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('supports y as optional deprecated alias (radius was removed)', () => {
|
|
157
|
-
const optionals = getOptionalChannels('arc');
|
|
158
|
-
expect(optionals).toContain('y');
|
|
159
|
-
expect(getChannelNames('arc')).not.toContain('radius');
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe('text encoding rules', () => {
|
|
164
|
-
it('requires text channel', () => {
|
|
165
|
-
const rules = MARK_ENCODING_RULES.text;
|
|
166
|
-
expect(rules.text!.required).toBe(true);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('has optional x and y', () => {
|
|
170
|
-
const rules = MARK_ENCODING_RULES.text;
|
|
171
|
-
expect(rules.x.required).toBe(false);
|
|
172
|
-
expect(rules.y.required).toBe(false);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('supports size as optional quantitative', () => {
|
|
176
|
-
const rules = MARK_ENCODING_RULES.text;
|
|
177
|
-
expect(rules.size.required).toBe(false);
|
|
178
|
-
expect(rules.size.allowedTypes).toContain('quantitative');
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
describe('rule encoding rules', () => {
|
|
183
|
-
it('has optional x, y, x2, y2', () => {
|
|
184
|
-
const rules = MARK_ENCODING_RULES.rule;
|
|
185
|
-
expect(rules.x.required).toBe(false);
|
|
186
|
-
expect(rules.y.required).toBe(false);
|
|
187
|
-
expect(rules.x2!.required).toBe(false);
|
|
188
|
-
expect(rules.y2!.required).toBe(false);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('supports strokeDash as optional', () => {
|
|
192
|
-
expect(getOptionalChannels('rule')).toContain('strokeDash');
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
describe('tick encoding rules', () => {
|
|
197
|
-
it('requires x and y', () => {
|
|
198
|
-
expect(getRequiredChannels('tick')).toContain('x');
|
|
199
|
-
expect(getRequiredChannels('tick')).toContain('y');
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('supports opacity, tooltip, detail', () => {
|
|
203
|
-
const optionals = getOptionalChannels('tick');
|
|
204
|
-
expect(optionals).toContain('opacity');
|
|
205
|
-
expect(optionals).toContain('tooltip');
|
|
206
|
-
expect(optionals).toContain('detail');
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
describe('rect encoding rules', () => {
|
|
211
|
-
it('requires x and y', () => {
|
|
212
|
-
expect(getRequiredChannels('rect')).toContain('x');
|
|
213
|
-
expect(getRequiredChannels('rect')).toContain('y');
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('supports x2, y2, opacity', () => {
|
|
217
|
-
const optionals = getOptionalChannels('rect');
|
|
218
|
-
expect(optionals).toContain('x2');
|
|
219
|
-
expect(optionals).toContain('y2');
|
|
220
|
-
expect(optionals).toContain('opacity');
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe('lollipop encoding rules', () => {
|
|
225
|
-
it('has the same rules as circle (semantic alias)', () => {
|
|
226
|
-
const lollipopRules = MARK_ENCODING_RULES.lollipop;
|
|
227
|
-
const circleRules = MARK_ENCODING_RULES.circle;
|
|
228
|
-
expect(lollipopRules).toEqual(circleRules);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('requires x (quantitative) and y (nominal/ordinal)', () => {
|
|
232
|
-
const rules = MARK_ENCODING_RULES.lollipop;
|
|
233
|
-
expect(rules.x.required).toBe(true);
|
|
234
|
-
expect(rules.x.allowedTypes).toEqual(['quantitative']);
|
|
235
|
-
expect(rules.y.required).toBe(true);
|
|
236
|
-
expect(rules.y.allowedTypes).toContain('nominal');
|
|
237
|
-
expect(rules.y.allowedTypes).toContain('ordinal');
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
describe('beeswarm encoding rules', () => {
|
|
242
|
-
it('marks both axes optional (the compiler enforces the combination)', () => {
|
|
243
|
-
const rules = MARK_ENCODING_RULES.beeswarm;
|
|
244
|
-
expect(rules.x.required).toBe(false);
|
|
245
|
-
expect(rules.y.required).toBe(false);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it('accepts quantitative and nominal/ordinal on both axes', () => {
|
|
249
|
-
const rules = MARK_ENCODING_RULES.beeswarm;
|
|
250
|
-
for (const axis of [rules.x, rules.y]) {
|
|
251
|
-
expect(axis.allowedTypes).toContain('quantitative');
|
|
252
|
-
expect(axis.allowedTypes).toContain('nominal');
|
|
253
|
-
expect(axis.allowedTypes).toContain('ordinal');
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('supports optional size (quantitative) for sized dots', () => {
|
|
258
|
-
const rules = MARK_ENCODING_RULES.beeswarm;
|
|
259
|
-
expect(rules.size.required).toBe(false);
|
|
260
|
-
expect(rules.size.allowedTypes).toEqual(['quantitative']);
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
describe('waffle encoding rules', () => {
|
|
265
|
-
it('requires a quantitative y (the share value) and a categorical color', () => {
|
|
266
|
-
const rules = MARK_ENCODING_RULES.waffle;
|
|
267
|
-
expect(rules.y.required).toBe(true);
|
|
268
|
-
expect(rules.y.allowedTypes).toEqual(['quantitative']);
|
|
269
|
-
expect(rules.color.required).toBe(true);
|
|
270
|
-
expect(rules.color.allowedTypes).toContain('nominal');
|
|
271
|
-
expect(rules.color.allowedTypes).toContain('ordinal');
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it('accepts theta as an optional quantitative channel (arc parity)', () => {
|
|
275
|
-
const rules = MARK_ENCODING_RULES.waffle;
|
|
276
|
-
expect(rules.theta?.required).toBe(false);
|
|
277
|
-
expect(rules.theta?.allowedTypes).toEqual(['quantitative']);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('does not require positional x (no axes)', () => {
|
|
281
|
-
const rules = MARK_ENCODING_RULES.waffle;
|
|
282
|
-
expect(rules.x.required).toBe(false);
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
describe('common channels across marks', () => {
|
|
287
|
-
it('tooltip is optional on all mark types', () => {
|
|
288
|
-
const allTypes: MarkType[] = [
|
|
289
|
-
'bar',
|
|
290
|
-
'line',
|
|
291
|
-
'area',
|
|
292
|
-
'point',
|
|
293
|
-
'circle',
|
|
294
|
-
'arc',
|
|
295
|
-
'text',
|
|
296
|
-
'rule',
|
|
297
|
-
'tick',
|
|
298
|
-
'rect',
|
|
299
|
-
'lollipop',
|
|
300
|
-
'beeswarm',
|
|
301
|
-
'range',
|
|
302
|
-
'waffle',
|
|
303
|
-
'calendar',
|
|
304
|
-
'parliament',
|
|
305
|
-
];
|
|
306
|
-
for (const type of allTypes) {
|
|
307
|
-
const rules = MARK_ENCODING_RULES[type];
|
|
308
|
-
if (rules.tooltip) {
|
|
309
|
-
expect(rules.tooltip.required).toBe(false);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it('href is optional on all mark types that have it', () => {
|
|
315
|
-
const allTypes: MarkType[] = [
|
|
316
|
-
'bar',
|
|
317
|
-
'line',
|
|
318
|
-
'area',
|
|
319
|
-
'point',
|
|
320
|
-
'circle',
|
|
321
|
-
'arc',
|
|
322
|
-
'text',
|
|
323
|
-
'rule',
|
|
324
|
-
'tick',
|
|
325
|
-
'rect',
|
|
326
|
-
'lollipop',
|
|
327
|
-
'beeswarm',
|
|
328
|
-
'range',
|
|
329
|
-
'waffle',
|
|
330
|
-
'calendar',
|
|
331
|
-
'parliament',
|
|
332
|
-
];
|
|
333
|
-
for (const type of allTypes) {
|
|
334
|
-
const rules = MARK_ENCODING_RULES[type];
|
|
335
|
-
if (rules.href) {
|
|
336
|
-
expect(rules.href.required).toBe(false);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
it('opacity is optional quantitative on all mark types that have it', () => {
|
|
342
|
-
const allTypes: MarkType[] = [
|
|
343
|
-
'bar',
|
|
344
|
-
'line',
|
|
345
|
-
'area',
|
|
346
|
-
'point',
|
|
347
|
-
'circle',
|
|
348
|
-
'arc',
|
|
349
|
-
'text',
|
|
350
|
-
'rule',
|
|
351
|
-
'tick',
|
|
352
|
-
'rect',
|
|
353
|
-
'lollipop',
|
|
354
|
-
'beeswarm',
|
|
355
|
-
'range',
|
|
356
|
-
'waffle',
|
|
357
|
-
'calendar',
|
|
358
|
-
'parliament',
|
|
359
|
-
];
|
|
360
|
-
for (const type of allTypes) {
|
|
361
|
-
const rules = MARK_ENCODING_RULES[type];
|
|
362
|
-
if (rules.opacity) {
|
|
363
|
-
expect(rules.opacity.required).toBe(false);
|
|
364
|
-
expect(rules.opacity.allowedTypes).toContain('quantitative');
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
});
|
|
368
|
-
});
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { GradientDef } from '../spec';
|
|
3
|
-
import { getRepresentativeColor, isGradientDef } from '../spec';
|
|
4
|
-
|
|
5
|
-
describe('isGradientDef', () => {
|
|
6
|
-
it('returns true for a valid linear gradient', () => {
|
|
7
|
-
expect(
|
|
8
|
-
isGradientDef({
|
|
9
|
-
gradient: 'linear',
|
|
10
|
-
stops: [
|
|
11
|
-
{ offset: 0, color: '#f00' },
|
|
12
|
-
{ offset: 1, color: '#00f' },
|
|
13
|
-
],
|
|
14
|
-
}),
|
|
15
|
-
).toBe(true);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('returns true for a valid radial gradient', () => {
|
|
19
|
-
expect(
|
|
20
|
-
isGradientDef({
|
|
21
|
-
gradient: 'radial',
|
|
22
|
-
stops: [{ offset: 0, color: '#f00' }],
|
|
23
|
-
}),
|
|
24
|
-
).toBe(true);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('returns false for a plain string', () => {
|
|
28
|
-
expect(isGradientDef('#ff0000')).toBe(false);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('returns false for null', () => {
|
|
32
|
-
expect(isGradientDef(null)).toBe(false);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('returns false for undefined', () => {
|
|
36
|
-
expect(isGradientDef(undefined)).toBe(false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('returns false for an object without gradient property', () => {
|
|
40
|
-
expect(isGradientDef({ stops: [] })).toBe(false);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('returns false for an object without stops', () => {
|
|
44
|
-
expect(isGradientDef({ gradient: 'linear' })).toBe(false);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('returns false for an object with invalid gradient type', () => {
|
|
48
|
-
expect(isGradientDef({ gradient: 'mesh', stops: [] })).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('getRepresentativeColor', () => {
|
|
53
|
-
it('returns the string directly when given a string', () => {
|
|
54
|
-
expect(getRepresentativeColor('#1b7fa3')).toBe('#1b7fa3');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('returns the last stop color for a linear gradient', () => {
|
|
58
|
-
const grad: GradientDef = {
|
|
59
|
-
gradient: 'linear',
|
|
60
|
-
stops: [
|
|
61
|
-
{ offset: 0, color: '#f00' },
|
|
62
|
-
{ offset: 0.5, color: '#0f0' },
|
|
63
|
-
{ offset: 1, color: '#00f' },
|
|
64
|
-
],
|
|
65
|
-
};
|
|
66
|
-
expect(getRepresentativeColor(grad)).toBe('#00f');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('returns the last stop color for a radial gradient', () => {
|
|
70
|
-
const grad: GradientDef = {
|
|
71
|
-
gradient: 'radial',
|
|
72
|
-
stops: [
|
|
73
|
-
{ offset: 0, color: '#fff' },
|
|
74
|
-
{ offset: 1, color: '#000' },
|
|
75
|
-
],
|
|
76
|
-
};
|
|
77
|
-
expect(getRepresentativeColor(grad)).toBe('#000');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('returns #000000 for a gradient with empty stops array', () => {
|
|
81
|
-
const grad: GradientDef = {
|
|
82
|
-
gradient: 'linear',
|
|
83
|
-
stops: [],
|
|
84
|
-
};
|
|
85
|
-
expect(getRepresentativeColor(grad)).toBe('#000000');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('returns the single stop color for a gradient with one stop', () => {
|
|
89
|
-
const grad: GradientDef = {
|
|
90
|
-
gradient: 'radial',
|
|
91
|
-
stops: [{ offset: 0, color: '#abc' }],
|
|
92
|
-
};
|
|
93
|
-
expect(getRepresentativeColor(grad)).toBe('#abc');
|
|
94
|
-
});
|
|
95
|
-
});
|