@incursa/ui-kit 1.8.0 → 1.9.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.
@@ -0,0 +1,629 @@
1
+ import { extent } from "d3-array";
2
+ import { scaleLinear, scaleTime } from "d3-scale";
3
+ import {
4
+ area as d3Area,
5
+ curveLinear,
6
+ curveMonotoneX,
7
+ curveStepAfter,
8
+ line as d3Line,
9
+ } from "d3-shape";
10
+
11
+ import { createUniqueId } from "../shared.js";
12
+
13
+ const SVG_NS = "http://www.w3.org/2000/svg";
14
+ const DEFAULT_WIDTH = 120;
15
+ const DEFAULT_HEIGHT = 32;
16
+ const DEFAULT_PADDING = 3;
17
+ const VALID_VARIANTS = new Set(["line", "area", "bar"]);
18
+ const VALID_TONES = new Set(["default", "positive", "negative", "muted", "accent"]);
19
+ const VALID_CURVES = new Set(["linear", "monotone", "step"]);
20
+ const CURVES = {
21
+ linear: curveLinear,
22
+ monotone: curveMonotoneX,
23
+ step: curveStepAfter,
24
+ };
25
+
26
+ function toFiniteNumber(value) {
27
+ if (value === null || value === undefined || value === "") {
28
+ return null;
29
+ }
30
+
31
+ const parsed = Number(value);
32
+ return Number.isFinite(parsed) ? parsed : null;
33
+ }
34
+
35
+ function normalizeToken(value, allowedValues, fallback) {
36
+ const normalized = String(value ?? "").trim().toLowerCase();
37
+ return allowedValues.has(normalized) ? normalized : fallback;
38
+ }
39
+
40
+ function parseXValue(value, index) {
41
+ if (value instanceof Date && Number.isFinite(value.getTime())) {
42
+ return value;
43
+ }
44
+
45
+ if (typeof value === "number" && Number.isFinite(value)) {
46
+ return value;
47
+ }
48
+
49
+ if (typeof value === "string" && value.trim()) {
50
+ const numeric = Number(value);
51
+ if (Number.isFinite(numeric)) {
52
+ return numeric;
53
+ }
54
+
55
+ const date = new Date(value);
56
+ if (Number.isFinite(date.getTime())) {
57
+ return date;
58
+ }
59
+ }
60
+
61
+ return index;
62
+ }
63
+
64
+ function normalizeInputPoint(item, index) {
65
+ if (typeof item === "number") {
66
+ return { x: index, y: Number.isFinite(item) ? item : null };
67
+ }
68
+
69
+ if (item instanceof Date) {
70
+ return { x: index, y: null };
71
+ }
72
+
73
+ if (item && typeof item === "object") {
74
+ return {
75
+ x: item.x ?? index,
76
+ y: toFiniteNumber(item.y),
77
+ };
78
+ }
79
+
80
+ const numeric = toFiniteNumber(item);
81
+ return { x: index, y: numeric };
82
+ }
83
+
84
+ function parseSparklinePoints(input) {
85
+ if (Array.isArray(input)) {
86
+ return input.map(normalizeInputPoint);
87
+ }
88
+
89
+ if (input === null || input === undefined) {
90
+ return [];
91
+ }
92
+
93
+ if (typeof input === "string") {
94
+ const text = input.trim();
95
+ if (!text) {
96
+ return [];
97
+ }
98
+
99
+ if (text.startsWith("[")) {
100
+ try {
101
+ const parsed = JSON.parse(text);
102
+ return parseSparklinePoints(parsed);
103
+ } catch {
104
+ return [];
105
+ }
106
+ }
107
+
108
+ return text
109
+ .split(/[\s,;]+/u)
110
+ .filter(Boolean)
111
+ .map((part, index) => ({ x: index, y: toFiniteNumber(part) }));
112
+ }
113
+
114
+ return [];
115
+ }
116
+
117
+ function normalizeSparklineExtent(points, options = {}) {
118
+ const normalizedPoints = parseSparklinePoints(points);
119
+ const referenceValue = toFiniteNumber(options.referenceValue);
120
+ const prepared = normalizedPoints.map((point, index) => ({
121
+ x: point.x,
122
+ xValue: parseXValue(point.x, index),
123
+ y: toFiniteNumber(point.y),
124
+ index,
125
+ }));
126
+ const validPoints = prepared.filter((point) => point.y !== null);
127
+ const yValues = validPoints.map((point) => point.y);
128
+
129
+ if (referenceValue !== null) {
130
+ yValues.push(referenceValue);
131
+ }
132
+
133
+ if (!validPoints.length) {
134
+ return {
135
+ empty: true,
136
+ points: prepared,
137
+ validPoints,
138
+ xDomain: [0, 1],
139
+ yDomain: [0, 1],
140
+ xMode: "index",
141
+ referenceValue,
142
+ };
143
+ }
144
+
145
+ let yDomain = extent(yValues);
146
+ if (!Number.isFinite(yDomain[0]) || !Number.isFinite(yDomain[1])) {
147
+ yDomain = [0, 1];
148
+ }
149
+
150
+ if (Object.is(yDomain[0], yDomain[1])) {
151
+ const value = yDomain[0];
152
+ const padding = value === 0 ? 1 : Math.max(Math.abs(value) * 0.08, 1);
153
+ yDomain = [value - padding, value + padding];
154
+ }
155
+
156
+ const allDates = prepared.every((point) => point.xValue instanceof Date);
157
+ const allNumbers = prepared.every((point) => typeof point.xValue === "number" && Number.isFinite(point.xValue));
158
+ const xMode = allDates ? "time" : (allNumbers ? "number" : "index");
159
+ const xValues = prepared.map((point) => xMode === "index" ? point.index : point.xValue);
160
+ let xDomain = extent(xValues);
161
+
162
+ if (xMode === "time") {
163
+ const left = xDomain[0] instanceof Date ? xDomain[0].getTime() : NaN;
164
+ const right = xDomain[1] instanceof Date ? xDomain[1].getTime() : NaN;
165
+ if (!Number.isFinite(left) || !Number.isFinite(right)) {
166
+ xDomain = [new Date(0), new Date(1)];
167
+ } else if (left === right) {
168
+ xDomain = [new Date(left - 1), new Date(right + 1)];
169
+ }
170
+ } else {
171
+ if (!Number.isFinite(xDomain[0]) || !Number.isFinite(xDomain[1])) {
172
+ xDomain = [0, Math.max(prepared.length - 1, 1)];
173
+ } else if (Object.is(xDomain[0], xDomain[1])) {
174
+ xDomain = [xDomain[0] - 1, xDomain[1] + 1];
175
+ }
176
+ }
177
+
178
+ return {
179
+ empty: false,
180
+ points: prepared,
181
+ validPoints,
182
+ xDomain,
183
+ yDomain,
184
+ xMode,
185
+ referenceValue,
186
+ };
187
+ }
188
+
189
+ function clamp(value, min, max) {
190
+ return Math.max(min, Math.min(max, value));
191
+ }
192
+
193
+ function round(value) {
194
+ return Number.isFinite(value) ? Number(value.toFixed(3)) : 0;
195
+ }
196
+
197
+ function createScales(extentInfo, width, height, padding) {
198
+ const xRange = [padding, Math.max(width - padding, padding)];
199
+ const yRange = [Math.max(height - padding, padding), padding];
200
+ const xScale = extentInfo.xMode === "time"
201
+ ? scaleTime(extentInfo.xDomain, xRange)
202
+ : scaleLinear(extentInfo.xDomain, xRange);
203
+ const yScale = scaleLinear(extentInfo.yDomain, yRange);
204
+
205
+ return { xScale, yScale };
206
+ }
207
+
208
+ function getX(point, extentInfo) {
209
+ return extentInfo.xMode === "index" ? point.index : point.xValue;
210
+ }
211
+
212
+ function singlePointPath(point, extentInfo, xScale, yScale, width) {
213
+ const center = round(xScale(getX(point, extentInfo)));
214
+ const y = round(yScale(point.y));
215
+ const half = Math.min(4, Math.max(1, width / 20));
216
+ const left = round(clamp(center - half, 0, width));
217
+ const right = round(clamp(center + half, 0, width));
218
+
219
+ return `M${left},${y}L${right},${y}`;
220
+ }
221
+
222
+ function buildSparklinePath(points, options = {}) {
223
+ const width = Math.max(toFiniteNumber(options.width) ?? DEFAULT_WIDTH, 1);
224
+ const height = Math.max(toFiniteNumber(options.height) ?? DEFAULT_HEIGHT, 1);
225
+ const padding = Math.max(toFiniteNumber(options.padding) ?? DEFAULT_PADDING, 0);
226
+ const variant = normalizeToken(options.variant, VALID_VARIANTS, "line");
227
+ const curve = normalizeToken(options.curve, VALID_CURVES, "linear");
228
+ const extentInfo = normalizeSparklineExtent(points, options);
229
+
230
+ if (extentInfo.empty) {
231
+ return {
232
+ empty: true,
233
+ width,
234
+ height,
235
+ padding,
236
+ variant,
237
+ curve,
238
+ linePath: "",
239
+ areaPath: "",
240
+ bars: [],
241
+ marker: null,
242
+ minPoint: null,
243
+ maxPoint: null,
244
+ referenceY: null,
245
+ extent: extentInfo,
246
+ };
247
+ }
248
+
249
+ const { xScale, yScale } = createScales(extentInfo, width, height, padding);
250
+ const curveFactory = CURVES[curve] || curveLinear;
251
+ const lineGenerator = d3Line()
252
+ .defined((point) => point.y !== null)
253
+ .x((point) => round(xScale(getX(point, extentInfo))))
254
+ .y((point) => round(yScale(point.y)))
255
+ .curve(curveFactory);
256
+ const validPoints = extentInfo.validPoints;
257
+ const linePath = validPoints.length === 1
258
+ ? singlePointPath(validPoints[0], extentInfo, xScale, yScale, width)
259
+ : (lineGenerator(extentInfo.points) || "");
260
+ const baseline = clamp(0, extentInfo.yDomain[0], extentInfo.yDomain[1]);
261
+ const areaGenerator = d3Area()
262
+ .defined((point) => point.y !== null)
263
+ .x((point) => round(xScale(getX(point, extentInfo))))
264
+ .y0(round(yScale(baseline)))
265
+ .y1((point) => round(yScale(point.y)))
266
+ .curve(curveFactory);
267
+ const areaPath = validPoints.length > 1 ? (areaGenerator(extentInfo.points) || "") : "";
268
+ const barWidth = Math.max(1, Math.min(8, (width - (padding * 2)) / Math.max(extentInfo.points.length, 1) * 0.58));
269
+ const baselineY = round(yScale(baseline));
270
+ const bars = validPoints.map((point) => {
271
+ const x = round(xScale(getX(point, extentInfo)) - (barWidth / 2));
272
+ const y = round(yScale(point.y));
273
+ return {
274
+ x,
275
+ y: Math.min(y, baselineY),
276
+ width: round(barWidth),
277
+ height: Math.max(1, round(Math.abs(baselineY - y))),
278
+ };
279
+ });
280
+ const lastPoint = validPoints[validPoints.length - 1] || null;
281
+ const marker = lastPoint ? {
282
+ x: round(xScale(getX(lastPoint, extentInfo))),
283
+ y: round(yScale(lastPoint.y)),
284
+ value: lastPoint.y,
285
+ } : null;
286
+ const minPoint = validPoints.reduce((candidate, point) => point.y < candidate.y ? point : candidate, validPoints[0]);
287
+ const maxPoint = validPoints.reduce((candidate, point) => point.y > candidate.y ? point : candidate, validPoints[0]);
288
+ const mapMarker = (point) => point ? {
289
+ x: round(xScale(getX(point, extentInfo))),
290
+ y: round(yScale(point.y)),
291
+ value: point.y,
292
+ } : null;
293
+
294
+ return {
295
+ empty: false,
296
+ width,
297
+ height,
298
+ padding,
299
+ variant,
300
+ curve,
301
+ linePath,
302
+ areaPath,
303
+ bars,
304
+ marker,
305
+ minPoint: mapMarker(minPoint),
306
+ maxPoint: mapMarker(maxPoint),
307
+ referenceY: extentInfo.referenceValue === null ? null : round(yScale(extentInfo.referenceValue)),
308
+ extent: extentInfo,
309
+ };
310
+ }
311
+
312
+ function svgElement(name) {
313
+ return document.createElementNS(SVG_NS, name);
314
+ }
315
+
316
+ function hasInvalidPathData(value) {
317
+ return /(?:NaN|Infinity|-Infinity)/u.test(String(value ?? ""));
318
+ }
319
+
320
+ class IncSparklineElement extends HTMLElement {
321
+ static observedAttributes = [
322
+ "aria-label",
323
+ "curve",
324
+ "empty-label",
325
+ "height",
326
+ "points",
327
+ "reference-value",
328
+ "show-last-marker",
329
+ "show-min-max",
330
+ "tone",
331
+ "values",
332
+ "variant",
333
+ "width",
334
+ ];
335
+
336
+ #hasPropertyPoints = false;
337
+ #propertyPoints = [];
338
+ #titleId = createUniqueId("inc-sparkline-title");
339
+ #descId = createUniqueId("inc-sparkline-desc");
340
+
341
+ connectedCallback() {
342
+ this.#render();
343
+ }
344
+
345
+ attributeChangedCallback() {
346
+ if (this.isConnected) {
347
+ this.#render();
348
+ }
349
+ }
350
+
351
+ get points() {
352
+ if (this.#hasPropertyPoints) {
353
+ return parseSparklinePoints(this.#propertyPoints);
354
+ }
355
+
356
+ if (this.hasAttribute("points")) {
357
+ return parseSparklinePoints(this.getAttribute("points"));
358
+ }
359
+
360
+ return parseSparklinePoints(this.getAttribute("values"));
361
+ }
362
+
363
+ set points(value) {
364
+ if (value === null || value === undefined) {
365
+ this.#hasPropertyPoints = false;
366
+ this.#propertyPoints = [];
367
+ } else {
368
+ this.#hasPropertyPoints = true;
369
+ this.#propertyPoints = value;
370
+ }
371
+
372
+ if (this.isConnected) {
373
+ this.#render();
374
+ }
375
+ }
376
+
377
+ get values() {
378
+ return this.getAttribute("values") || "";
379
+ }
380
+
381
+ set values(value) {
382
+ if (value === null || value === undefined || value === "") {
383
+ this.removeAttribute("values");
384
+ return;
385
+ }
386
+
387
+ this.setAttribute("values", String(value));
388
+ }
389
+
390
+ get width() {
391
+ return Math.max(toFiniteNumber(this.getAttribute("width")) ?? DEFAULT_WIDTH, 1);
392
+ }
393
+
394
+ set width(value) {
395
+ if (value === null || value === undefined || value === "") {
396
+ this.removeAttribute("width");
397
+ return;
398
+ }
399
+
400
+ this.setAttribute("width", String(value));
401
+ }
402
+
403
+ get height() {
404
+ return Math.max(toFiniteNumber(this.getAttribute("height")) ?? DEFAULT_HEIGHT, 1);
405
+ }
406
+
407
+ set height(value) {
408
+ if (value === null || value === undefined || value === "") {
409
+ this.removeAttribute("height");
410
+ return;
411
+ }
412
+
413
+ this.setAttribute("height", String(value));
414
+ }
415
+
416
+ #render() {
417
+ const width = this.width;
418
+ const height = this.height;
419
+ const variant = normalizeToken(this.getAttribute("variant"), VALID_VARIANTS, "line");
420
+ const tone = normalizeToken(this.getAttribute("tone"), VALID_TONES, "default");
421
+ const curve = normalizeToken(this.getAttribute("curve"), VALID_CURVES, "linear");
422
+ const referenceValue = toFiniteNumber(this.getAttribute("reference-value"));
423
+ const label = this.getAttribute("aria-label") || "Sparkline trend";
424
+ const emptyLabel = this.getAttribute("empty-label") ?? "No data";
425
+ const model = buildSparklinePath(this.points, {
426
+ curve,
427
+ height,
428
+ referenceValue,
429
+ variant,
430
+ width,
431
+ });
432
+
433
+ this.classList.add("inc-sparkline");
434
+ [...this.classList]
435
+ .filter((token) => token.startsWith("inc-sparkline--"))
436
+ .forEach((token) => this.classList.remove(token));
437
+ this.classList.add(`inc-sparkline--${variant}`, `inc-sparkline--tone-${tone}`);
438
+ this.style.setProperty("--inc-sparkline-width", `${width}px`);
439
+ this.style.setProperty("--inc-sparkline-height", `${height}px`);
440
+
441
+ const svg = svgElement("svg");
442
+ svg.classList.add("inc-sparkline__svg");
443
+ svg.setAttribute("part", "svg");
444
+ svg.setAttribute("width", String(width));
445
+ svg.setAttribute("height", String(height));
446
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
447
+ svg.setAttribute("role", "img");
448
+ svg.setAttribute("aria-labelledby", `${this.#titleId} ${this.#descId}`);
449
+ svg.setAttribute("focusable", "false");
450
+
451
+ const title = svgElement("title");
452
+ title.id = this.#titleId;
453
+ title.textContent = label;
454
+
455
+ const desc = svgElement("desc");
456
+ desc.id = this.#descId;
457
+ desc.textContent = model.empty
458
+ ? (emptyLabel || "No sparkline data available.")
459
+ : this.#buildDescription(model);
460
+
461
+ svg.append(title, desc);
462
+
463
+ if (model.empty || hasInvalidPathData(model.linePath) || hasInvalidPathData(model.areaPath)) {
464
+ this.#renderEmpty(svg, width, height, emptyLabel);
465
+ this.replaceChildren(svg);
466
+ return;
467
+ }
468
+
469
+ if (model.referenceY !== null) {
470
+ const reference = svgElement("line");
471
+ reference.classList.add("inc-sparkline__reference");
472
+ reference.setAttribute("part", "reference");
473
+ reference.setAttribute("x1", String(model.padding));
474
+ reference.setAttribute("x2", String(width - model.padding));
475
+ reference.setAttribute("y1", String(model.referenceY));
476
+ reference.setAttribute("y2", String(model.referenceY));
477
+ reference.setAttribute("vector-effect", "non-scaling-stroke");
478
+ svg.append(reference);
479
+ }
480
+
481
+ if (variant === "bar") {
482
+ model.bars.forEach((bar) => {
483
+ const rect = svgElement("rect");
484
+ rect.classList.add("inc-sparkline__bar");
485
+ rect.setAttribute("part", "bar");
486
+ rect.setAttribute("x", String(bar.x));
487
+ rect.setAttribute("y", String(bar.y));
488
+ rect.setAttribute("width", String(bar.width));
489
+ rect.setAttribute("height", String(bar.height));
490
+ svg.append(rect);
491
+ });
492
+ } else {
493
+ if (variant === "area" && model.areaPath) {
494
+ const area = svgElement("path");
495
+ area.classList.add("inc-sparkline__area");
496
+ area.setAttribute("part", "area");
497
+ area.setAttribute("d", model.areaPath);
498
+ area.setAttribute("vector-effect", "non-scaling-stroke");
499
+ svg.append(area);
500
+ }
501
+
502
+ const line = svgElement("path");
503
+ line.classList.add("inc-sparkline__line");
504
+ line.setAttribute("part", "line");
505
+ line.setAttribute("d", model.linePath);
506
+ line.setAttribute("vector-effect", "non-scaling-stroke");
507
+ svg.append(line);
508
+ }
509
+
510
+ if (this.hasAttribute("show-min-max")) {
511
+ this.#appendMarker(svg, model.minPoint, "min");
512
+ if (model.maxPoint?.x !== model.minPoint?.x || model.maxPoint?.y !== model.minPoint?.y) {
513
+ this.#appendMarker(svg, model.maxPoint, "max");
514
+ }
515
+ }
516
+
517
+ if (this.hasAttribute("show-last-marker")) {
518
+ this.#appendMarker(svg, model.marker, "last");
519
+ }
520
+
521
+ this.replaceChildren(svg);
522
+ }
523
+
524
+ #renderEmpty(svg, width, height, emptyLabel) {
525
+ const line = svgElement("line");
526
+ line.classList.add("inc-sparkline__empty-line");
527
+ line.setAttribute("part", "line");
528
+ line.setAttribute("x1", "3");
529
+ line.setAttribute("x2", String(Math.max(width - 3, 3)));
530
+ line.setAttribute("y1", String(round(height / 2)));
531
+ line.setAttribute("y2", String(round(height / 2)));
532
+ line.setAttribute("vector-effect", "non-scaling-stroke");
533
+ svg.append(line);
534
+
535
+ if (emptyLabel) {
536
+ const text = svgElement("text");
537
+ text.classList.add("inc-sparkline__empty");
538
+ text.setAttribute("part", "empty");
539
+ text.setAttribute("x", String(round(width / 2)));
540
+ text.setAttribute("y", String(round((height / 2) + 3)));
541
+ text.setAttribute("text-anchor", "middle");
542
+ text.textContent = emptyLabel;
543
+ svg.append(text);
544
+ }
545
+ }
546
+
547
+ #appendMarker(svg, point, modifier) {
548
+ if (!point || !Number.isFinite(point.x) || !Number.isFinite(point.y)) {
549
+ return;
550
+ }
551
+
552
+ const marker = svgElement("circle");
553
+ marker.classList.add("inc-sparkline__marker", `inc-sparkline__marker--${modifier}`);
554
+ marker.setAttribute("part", "marker");
555
+ marker.setAttribute("cx", String(point.x));
556
+ marker.setAttribute("cy", String(point.y));
557
+ marker.setAttribute("r", modifier === "last" ? "2.4" : "1.8");
558
+ marker.setAttribute("vector-effect", "non-scaling-stroke");
559
+ svg.append(marker);
560
+ }
561
+
562
+ #buildDescription(model) {
563
+ const values = model.extent.validPoints.map((point) => point.y);
564
+ const min = Math.min(...values);
565
+ const max = Math.max(...values);
566
+ const latest = model.marker?.value;
567
+ const parts = [`${values.length} data ${values.length === 1 ? "point" : "points"}.`];
568
+
569
+ if (Number.isFinite(latest)) {
570
+ parts.push(`Latest value ${latest}.`);
571
+ }
572
+
573
+ if (Number.isFinite(min) && Number.isFinite(max)) {
574
+ parts.push(`Range ${min} to ${max}.`);
575
+ }
576
+
577
+ if (model.extent.referenceValue !== null) {
578
+ parts.push(`Reference value ${model.extent.referenceValue}.`);
579
+ }
580
+
581
+ return parts.join(" ");
582
+ }
583
+ }
584
+
585
+ const visualizationDefinitions = [
586
+ ["inc-sparkline", IncSparklineElement],
587
+ ];
588
+
589
+ const visualizationComponents = {
590
+ IncSparklineElement,
591
+ };
592
+
593
+ function defineVisualizationComponents(registry = globalThis.customElements) {
594
+ if (!registry || typeof registry.define !== "function" || typeof registry.get !== "function") {
595
+ return [];
596
+ }
597
+
598
+ const defined = [];
599
+ for (const [tagName, ctor] of visualizationDefinitions) {
600
+ if (!registry.get(tagName)) {
601
+ registry.define(tagName, ctor);
602
+ defined.push(tagName);
603
+ }
604
+ }
605
+
606
+ return defined;
607
+ }
608
+
609
+ if (typeof globalThis !== "undefined") {
610
+ const namespace = globalThis.IncWebComponents || (globalThis.IncWebComponents = {});
611
+ namespace.visualizations = Object.assign({}, namespace.visualizations, {
612
+ buildSparklinePath,
613
+ defineVisualizationComponents,
614
+ normalizeSparklineExtent,
615
+ parseSparklinePoints,
616
+ visualizationDefinitions,
617
+ components: visualizationComponents,
618
+ });
619
+ }
620
+
621
+ export {
622
+ IncSparklineElement,
623
+ buildSparklinePath,
624
+ defineVisualizationComponents,
625
+ normalizeSparklineExtent,
626
+ parseSparklinePoints,
627
+ visualizationComponents,
628
+ visualizationDefinitions,
629
+ };
@@ -7,6 +7,7 @@ import "./components/forms.js";
7
7
  import "./components/feedback.js";
8
8
  import "./components/actions.js";
9
9
  import "./components/collections.js";
10
+ import "./components/visualizations.js";
10
11
  import "./components/overlays.js";
11
12
 
12
13
  const namespace = globalThis.IncWebComponents || (globalThis.IncWebComponents = {});
@@ -51,6 +52,7 @@ function getComponentEntries() {
51
52
  addEntries(entryMap, namespace.feedback?.feedbackDefinitions);
52
53
  addEntries(entryMap, namespace.actions?.actionDefinitions);
53
54
  addEntries(entryMap, namespace.collections?.collectionDefinitions);
55
+ addEntries(entryMap, namespace.visualizations?.visualizationDefinitions);
54
56
 
55
57
  addEntry(entryMap, "inc-disclosure", namespace.overlays?.IncDisclosureElement);
56
58
  addEntry(entryMap, "inc-dialog", namespace.overlays?.IncDialogElement);
@@ -87,6 +89,12 @@ syncNamespace();
87
89
 
88
90
  defineAll();
89
91
 
92
+ export {
93
+ buildSparklinePath,
94
+ normalizeSparklineExtent,
95
+ parseSparklinePoints,
96
+ } from "./components/visualizations.js";
97
+
90
98
  export {
91
99
  defineAll,
92
100
  registerIncWebComponents,