juxscript 1.0.6 → 1.0.8

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,605 @@
1
+ import { State } from '../reactivity/state.js';
2
+ import {
3
+ googleTheme,
4
+ seriesaTheme,
5
+ hrTheme,
6
+ figmaTheme,
7
+ notionTheme,
8
+ chalkTheme,
9
+ mintTheme
10
+ } from '../themes/charts.js';
11
+
12
+ /**
13
+ * KPI card options
14
+ */
15
+ export interface KPICardOptions {
16
+ title?: string;
17
+ value?: string | number;
18
+ delta?: number; // Percentage change (e.g., 10 for +10%, -5 for -5%)
19
+ prefix?: string; // e.g., "$", "€"
20
+ suffix?: string; // e.g., "k", "M", "%"
21
+ width?: number;
22
+ height?: number;
23
+ theme?: 'google' | 'seriesa' | 'hr' | 'figma' | 'notion' | 'chalk' | 'mint';
24
+ styleMode?: 'default' | 'gradient' | 'glass' | 'outline' | 'glow';
25
+ animate?: boolean;
26
+ animationDuration?: number;
27
+ borderRadius?: number;
28
+ showAccentBar?: boolean;
29
+ class?: string;
30
+ style?: string;
31
+ }
32
+
33
+ /**
34
+ * KPI card state
35
+ */
36
+ type KPICardState = {
37
+ title: string;
38
+ value: string | number;
39
+ delta: number;
40
+ prefix: string;
41
+ suffix: string;
42
+ width: number;
43
+ height: number;
44
+ theme: 'google' | 'seriesa' | 'hr' | 'figma' | 'notion' | 'chalk' | 'mint';
45
+ styleMode: 'default' | 'gradient' | 'glass' | 'outline' | 'glow';
46
+ animate: boolean;
47
+ animationDuration: number;
48
+ borderRadius: number;
49
+ showAccentBar: boolean;
50
+ class: string;
51
+ style: string;
52
+ };
53
+
54
+ /**
55
+ * KPI card component - Displays key performance indicators
56
+ *
57
+ * Usage:
58
+ * jux.kpicard('users-kpi')
59
+ * .title('New users')
60
+ * .value('78k')
61
+ * .delta(10)
62
+ * .theme('mint')
63
+ * .styleMode('gradient')
64
+ * .render('#app');
65
+ */
66
+ export class KPICard {
67
+ private _id: string;
68
+ private _element?: HTMLElement;
69
+ private _container?: string;
70
+
71
+ public state: KPICardState = {
72
+ title: 'KPI',
73
+ value: 0,
74
+ delta: 0,
75
+ prefix: '',
76
+ suffix: '',
77
+ width: 280,
78
+ height: 200,
79
+ theme: 'google',
80
+ styleMode: 'default',
81
+ animate: true,
82
+ animationDuration: 600,
83
+ borderRadius: 16,
84
+ showAccentBar: true,
85
+ class: '',
86
+ style: ''
87
+ };
88
+
89
+ private _boundTheme?: State<string>;
90
+ private _boundStyleMode?: State<string>;
91
+ private _boundTitle?: State<string>;
92
+ private _boundValue?: State<string | number>;
93
+ private _boundDelta?: State<number>;
94
+
95
+ constructor(id: string, options: KPICardOptions = {}) {
96
+ this._id = id;
97
+
98
+ // Apply options
99
+ if (options.title !== undefined) this.state.title = options.title;
100
+ if (options.value !== undefined) this.state.value = options.value;
101
+ if (options.delta !== undefined) this.state.delta = options.delta;
102
+ if (options.prefix !== undefined) this.state.prefix = options.prefix;
103
+ if (options.suffix !== undefined) this.state.suffix = options.suffix;
104
+ if (options.width !== undefined) this.state.width = options.width;
105
+ if (options.height !== undefined) this.state.height = options.height;
106
+ if (options.theme !== undefined) this.state.theme = options.theme;
107
+ if (options.styleMode !== undefined) this.state.styleMode = options.styleMode;
108
+ if (options.animate !== undefined) this.state.animate = options.animate;
109
+ if (options.animationDuration !== undefined) this.state.animationDuration = options.animationDuration;
110
+ if (options.borderRadius !== undefined) this.state.borderRadius = options.borderRadius;
111
+ if (options.showAccentBar !== undefined) this.state.showAccentBar = options.showAccentBar;
112
+ if (options.class !== undefined) this.state.class = options.class;
113
+ if (options.style !== undefined) this.state.style = options.style;
114
+ }
115
+
116
+ // Chainable setters
117
+ title(value: string | State<string>): this {
118
+ if (value instanceof State) {
119
+ this._boundTitle = value;
120
+ this.state.title = value.value;
121
+ value.subscribe((newValue) => {
122
+ this.state.title = newValue;
123
+ this._updateCard();
124
+ });
125
+ } else {
126
+ this.state.title = value;
127
+ }
128
+ return this;
129
+ }
130
+
131
+ value(value: string | number | State<string | number>): this {
132
+ if (value instanceof State) {
133
+ this._boundValue = value;
134
+ this.state.value = value.value;
135
+ value.subscribe((newValue) => {
136
+ this.state.value = newValue;
137
+ this._updateCard();
138
+ });
139
+ } else {
140
+ this.state.value = value;
141
+ }
142
+ return this;
143
+ }
144
+
145
+ delta(value: number | State<number>): this {
146
+ if (value instanceof State) {
147
+ this._boundDelta = value;
148
+ this.state.delta = value.value;
149
+ value.subscribe((newValue) => {
150
+ this.state.delta = newValue;
151
+ this._updateCard();
152
+ });
153
+ } else {
154
+ this.state.delta = value;
155
+ }
156
+ return this;
157
+ }
158
+
159
+ prefix(value: string): this {
160
+ this.state.prefix = value;
161
+ return this;
162
+ }
163
+
164
+ suffix(value: string): this {
165
+ this.state.suffix = value;
166
+ return this;
167
+ }
168
+
169
+ width(value: number): this {
170
+ this.state.width = value;
171
+ return this;
172
+ }
173
+
174
+ height(value: number): this {
175
+ this.state.height = value;
176
+ return this;
177
+ }
178
+
179
+ theme(value: string | State<string>): this {
180
+ if (value instanceof State) {
181
+ this._boundTheme = value;
182
+ this.state.theme = value.value as any;
183
+ value.subscribe((newValue) => {
184
+ this.state.theme = newValue as any;
185
+ this._updateCard();
186
+ });
187
+ } else {
188
+ this.state.theme = value as any;
189
+ }
190
+ return this;
191
+ }
192
+
193
+ styleMode(value: string | State<string>): this {
194
+ if (value instanceof State) {
195
+ this._boundStyleMode = value;
196
+ this.state.styleMode = value.value as any;
197
+ value.subscribe((newValue) => {
198
+ this.state.styleMode = newValue as any;
199
+ this._updateCard();
200
+ });
201
+ } else {
202
+ this.state.styleMode = value as any;
203
+ }
204
+ return this;
205
+ }
206
+
207
+ animate(value: boolean): this {
208
+ this.state.animate = value;
209
+ return this;
210
+ }
211
+
212
+ animationDuration(value: number): this {
213
+ this.state.animationDuration = value;
214
+ return this;
215
+ }
216
+
217
+ borderRadius(value: number): this {
218
+ this.state.borderRadius = value;
219
+ return this;
220
+ }
221
+
222
+ showAccentBar(value: boolean): this {
223
+ this.state.showAccentBar = value;
224
+ return this;
225
+ }
226
+
227
+ class(value: string): this {
228
+ this.state.class = value;
229
+ return this;
230
+ }
231
+
232
+ style(value: string): this {
233
+ this.state.style = value;
234
+ return this;
235
+ }
236
+
237
+ render(container: string): this {
238
+ this._container = container;
239
+ const element = document.querySelector(container);
240
+ if (!element) {
241
+ console.warn(`Container ${container} not found`);
242
+ return this;
243
+ }
244
+
245
+ this._loadThemeFont();
246
+ this._buildCard(element as HTMLElement);
247
+ return this;
248
+ }
249
+
250
+ private _updateCard(): void {
251
+ if (!this._container) return;
252
+
253
+ const element = document.querySelector(this._container);
254
+ if (!element) return;
255
+
256
+ // Clear and rebuild
257
+ element.innerHTML = '';
258
+ this._loadThemeFont();
259
+ this._buildCard(element as HTMLElement);
260
+ }
261
+
262
+ private _loadThemeFont(): void {
263
+ const themeConfig = this._getThemeConfig();
264
+
265
+ if (themeConfig.font && !document.querySelector(`link[href="${themeConfig.font}"]`)) {
266
+ const link = document.createElement('link');
267
+ link.rel = 'stylesheet';
268
+ link.href = themeConfig.font;
269
+ document.head.appendChild(link);
270
+ }
271
+ }
272
+
273
+ private _buildCard(container: HTMLElement): void {
274
+ const { width, height, class: className, style, animate, animationDuration } = this.state;
275
+
276
+ // Create wrapper
277
+ const wrapper = document.createElement('div');
278
+ wrapper.className = `jux-kpicard ${className}`;
279
+ wrapper.id = this._id;
280
+ wrapper.style.cssText = `
281
+ width: ${width}px;
282
+ height: ${height}px;
283
+ ${style}
284
+ `;
285
+
286
+ // Apply theme colors and style mode
287
+ this._applyThemeAndStyle(wrapper);
288
+
289
+ // Build card content
290
+ const content = this._createContent();
291
+ wrapper.appendChild(content);
292
+
293
+ // Add animation
294
+ if (animate) {
295
+ wrapper.style.opacity = '0';
296
+ wrapper.style.transform = 'translateY(20px)';
297
+ wrapper.style.transition = `opacity ${animationDuration}ms ease-out, transform ${animationDuration}ms ease-out`;
298
+
299
+ requestAnimationFrame(() => {
300
+ setTimeout(() => {
301
+ wrapper.style.opacity = '1';
302
+ wrapper.style.transform = 'translateY(0)';
303
+ }, 50);
304
+ });
305
+ }
306
+
307
+ container.appendChild(wrapper);
308
+ this._element = wrapper;
309
+ }
310
+
311
+ private _createContent(): HTMLElement {
312
+ const { title, value, delta, prefix, suffix, animate, animationDuration, styleMode, width, height } = this.state;
313
+ const themeConfig = this._getThemeConfig();
314
+
315
+ // Calculate scale factor based on default dimensions (280x200)
316
+ const baseWidth = 280;
317
+ const baseHeight = 200;
318
+ const scaleFactor = Math.min(width / baseWidth, height / baseHeight);
319
+
320
+ const content = document.createElement('div');
321
+ content.className = 'jux-kpicard-content';
322
+ content.style.cssText = `
323
+ padding: ${24 * scaleFactor}px;
324
+ display: flex;
325
+ flex-direction: column;
326
+ height: 100%;
327
+ position: relative;
328
+ `;
329
+
330
+ // Title
331
+ const titleEl = document.createElement('div');
332
+ titleEl.className = 'jux-kpicard-title';
333
+ titleEl.textContent = title;
334
+ titleEl.style.cssText = `
335
+ font-size: ${16 * scaleFactor}px;
336
+ font-weight: 500;
337
+ color: ${styleMode === 'gradient' ? 'rgba(255, 255, 255, 0.95)' : '#6b7280'};
338
+ margin-bottom: ${16 * scaleFactor}px;
339
+ font-family: ${themeConfig.variables['--chart-font-family']};
340
+ `;
341
+ content.appendChild(titleEl);
342
+
343
+ // Value container
344
+ const valueContainer = document.createElement('div');
345
+ valueContainer.style.cssText = `
346
+ display: flex;
347
+ align-items: baseline;
348
+ margin-bottom: ${12 * scaleFactor}px;
349
+ `;
350
+
351
+ // Value
352
+ const valueEl = document.createElement('div');
353
+ valueEl.className = 'jux-kpicard-value';
354
+ valueEl.textContent = `${prefix}${value}${suffix}`;
355
+ valueEl.style.cssText = `
356
+ font-size: ${56 * scaleFactor}px;
357
+ font-weight: 800;
358
+ color: ${styleMode === 'gradient' ? '#ffffff' : '#1f2937'};
359
+ line-height: 1;
360
+ font-family: ${themeConfig.variables['--chart-font-family']};
361
+ ${styleMode === 'glow' ? `text-shadow: 0 0 ${20 * scaleFactor}px ${themeConfig.colors[0]}40;` : ''}
362
+ `;
363
+
364
+ if (animate) {
365
+ valueEl.style.opacity = '0';
366
+ valueEl.style.transform = 'scale(0.8)';
367
+ valueEl.style.transition = `opacity ${animationDuration}ms ease-out ${animationDuration / 2}ms, transform ${animationDuration}ms cubic-bezier(0.34, 1.56, 0.64, 1) ${animationDuration / 2}ms`;
368
+
369
+ requestAnimationFrame(() => {
370
+ setTimeout(() => {
371
+ valueEl.style.opacity = '1';
372
+ valueEl.style.transform = 'scale(1)';
373
+ }, 100);
374
+ });
375
+ }
376
+
377
+ valueContainer.appendChild(valueEl);
378
+ content.appendChild(valueContainer);
379
+
380
+ // Delta with arrow
381
+ if (delta !== 0) {
382
+ const deltaContainer = document.createElement('div');
383
+ deltaContainer.className = 'jux-kpicard-delta';
384
+ deltaContainer.style.cssText = `
385
+ display: flex;
386
+ align-items: center;
387
+ gap: ${8 * scaleFactor}px;
388
+ `;
389
+
390
+ // Arrow SVG
391
+ const arrow = this._createArrowSVG(delta > 0, styleMode === 'gradient', scaleFactor);
392
+ deltaContainer.appendChild(arrow);
393
+
394
+ // Delta text
395
+ const deltaText = document.createElement('span');
396
+ deltaText.textContent = `${delta > 0 ? '+' : ''}${delta}%`;
397
+ const deltaColor = styleMode === 'gradient'
398
+ ? (delta > 0 ? 'rgba(255, 255, 255, 0.95)' : 'rgba(255, 200, 200, 0.95)')
399
+ : (delta > 0 ? '#10b981' : '#ef4444');
400
+
401
+ deltaText.style.cssText = `
402
+ font-size: ${18 * scaleFactor}px;
403
+ font-weight: 700;
404
+ color: ${deltaColor};
405
+ font-family: ${themeConfig.variables['--chart-font-family']};
406
+ `;
407
+
408
+ if (animate) {
409
+ deltaContainer.style.opacity = '0';
410
+ deltaContainer.style.transform = 'translateX(-10px)';
411
+ deltaContainer.style.transition = `opacity ${animationDuration}ms ease-out ${animationDuration}ms, transform ${animationDuration}ms ease-out ${animationDuration}ms`;
412
+
413
+ requestAnimationFrame(() => {
414
+ setTimeout(() => {
415
+ deltaContainer.style.opacity = '1';
416
+ deltaContainer.style.transform = 'translateX(0)';
417
+ }, 150);
418
+ });
419
+ }
420
+
421
+ deltaContainer.appendChild(deltaText);
422
+ content.appendChild(deltaContainer);
423
+ }
424
+
425
+ return content;
426
+ }
427
+
428
+ private _createArrowSVG(isUp: boolean, isGradientMode: boolean, scaleFactor: number = 1): SVGSVGElement {
429
+ const baseWidth = 120;
430
+ const baseHeight = 32;
431
+ const width = baseWidth * scaleFactor;
432
+ const height = baseHeight * scaleFactor;
433
+
434
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
435
+ svg.setAttribute('width', width.toString());
436
+ svg.setAttribute('height', height.toString());
437
+ svg.setAttribute('viewBox', `0 0 ${baseWidth} ${baseHeight}`);
438
+ svg.setAttribute('fill', 'none');
439
+ svg.style.flexShrink = '0';
440
+
441
+ const color = isGradientMode
442
+ ? (isUp ? 'rgba(255, 255, 255, 0.9)' : 'rgba(255, 200, 200, 0.9)')
443
+ : (isUp ? '#10b981' : '#ef4444');
444
+
445
+ if (isUp) {
446
+ // Upward trending arrow - wider
447
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
448
+ path.setAttribute('d', 'M4 26 L22 18 L40 22 L58 14 L76 18 L94 10');
449
+ path.setAttribute('stroke', color);
450
+ path.setAttribute('stroke-width', '3');
451
+ path.setAttribute('stroke-linecap', 'round');
452
+ path.setAttribute('stroke-linejoin', 'round');
453
+ path.setAttribute('fill', 'none');
454
+ svg.appendChild(path);
455
+
456
+ // Points at each vertex - bigger circles
457
+ const points = [
458
+ { x: 4, y: 26 },
459
+ { x: 22, y: 18 },
460
+ { x: 40, y: 22 },
461
+ { x: 58, y: 14 },
462
+ { x: 76, y: 18 },
463
+ { x: 94, y: 10 }
464
+ ];
465
+
466
+ points.forEach(point => {
467
+ const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
468
+ circle.setAttribute('cx', point.x.toString());
469
+ circle.setAttribute('cy', point.y.toString());
470
+ circle.setAttribute('r', '4.5');
471
+ circle.setAttribute('fill', color);
472
+ svg.appendChild(circle);
473
+ });
474
+ } else {
475
+ // Downward trending arrow - wider
476
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
477
+ path.setAttribute('d', 'M4 6 L22 14 L40 10 L58 18 L76 14 L94 22');
478
+ path.setAttribute('stroke', color);
479
+ path.setAttribute('stroke-width', '3');
480
+ path.setAttribute('stroke-linecap', 'round');
481
+ path.setAttribute('stroke-linejoin', 'round');
482
+ path.setAttribute('fill', 'none');
483
+ svg.appendChild(path);
484
+
485
+ // Points at each vertex - bigger circles
486
+ const points = [
487
+ { x: 4, y: 6 },
488
+ { x: 22, y: 14 },
489
+ { x: 40, y: 10 },
490
+ { x: 58, y: 18 },
491
+ { x: 76, y: 14 },
492
+ { x: 94, y: 22 }
493
+ ];
494
+
495
+ points.forEach(point => {
496
+ const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
497
+ circle.setAttribute('cx', point.x.toString());
498
+ circle.setAttribute('cy', point.y.toString());
499
+ circle.setAttribute('r', '4.5');
500
+ circle.setAttribute('fill', color);
501
+ svg.appendChild(circle);
502
+ });
503
+ }
504
+
505
+ return svg;
506
+ }
507
+
508
+ private _getThemeConfig() {
509
+ const { theme } = this.state;
510
+
511
+ switch (theme) {
512
+ case 'google':
513
+ return googleTheme;
514
+ case 'seriesa':
515
+ return seriesaTheme;
516
+ case 'hr':
517
+ return hrTheme;
518
+ case 'figma':
519
+ return figmaTheme;
520
+ case 'notion':
521
+ return notionTheme;
522
+ case 'chalk':
523
+ return chalkTheme;
524
+ case 'mint':
525
+ return mintTheme;
526
+ default:
527
+ return googleTheme;
528
+ }
529
+ }
530
+
531
+ private _applyThemeAndStyle(wrapper: HTMLElement): void {
532
+ const { styleMode, borderRadius, showAccentBar, width, height } = this.state;
533
+ const themeConfig = this._getThemeConfig();
534
+ const colors = themeConfig.colors;
535
+
536
+ // Calculate scale factor for accent bar
537
+ const baseWidth = 280;
538
+ const scaleFactor = width / baseWidth;
539
+ const accentBarHeight = 4 * scaleFactor;
540
+
541
+ const baseStyles = `
542
+ border-radius: ${borderRadius}px;
543
+ overflow: hidden;
544
+ position: relative;
545
+ font-family: ${themeConfig.variables['--chart-font-family']};
546
+ `;
547
+
548
+ if (styleMode === 'gradient') {
549
+ wrapper.style.cssText += `
550
+ ${baseStyles}
551
+ background: linear-gradient(135deg, ${colors[0]} 0%, ${colors[1]} 50%, ${colors[2]} 100%);
552
+ box-shadow: 0 ${8 * scaleFactor}px ${32 * scaleFactor}px ${colors[0]}40;
553
+ `;
554
+ } else if (styleMode === 'glass') {
555
+ wrapper.style.cssText += `
556
+ ${baseStyles}
557
+ background: linear-gradient(135deg, ${colors[0]}20 0%, ${colors[1]}20 100%);
558
+ backdrop-filter: blur(${12 * scaleFactor}px) saturate(180%);
559
+ border: ${1 * scaleFactor}px solid ${colors[0]}30;
560
+ box-shadow: 0 ${8 * scaleFactor}px ${32 * scaleFactor}px rgba(0, 0, 0, 0.1);
561
+ `;
562
+ } else if (styleMode === 'outline') {
563
+ wrapper.style.cssText += `
564
+ ${baseStyles}
565
+ background: #ffffff;
566
+ border: ${3 * scaleFactor}px solid ${colors[0]};
567
+ box-shadow: 0 ${4 * scaleFactor}px ${12 * scaleFactor}px ${colors[0]}20;
568
+ `;
569
+ } else if (styleMode === 'glow') {
570
+ wrapper.style.cssText += `
571
+ ${baseStyles}
572
+ background: #ffffff;
573
+ border: ${2 * scaleFactor}px solid ${colors[0]}40;
574
+ box-shadow: 0 0 ${30 * scaleFactor}px ${colors[0]}30, 0 ${4 * scaleFactor}px ${12 * scaleFactor}px rgba(0, 0, 0, 0.1);
575
+ `;
576
+ } else {
577
+ // default
578
+ wrapper.style.cssText += `
579
+ ${baseStyles}
580
+ background: #ffffff;
581
+ border: ${1 * scaleFactor}px solid #e5e7eb;
582
+ box-shadow: 0 ${1 * scaleFactor}px ${3 * scaleFactor}px rgba(0, 0, 0, 0.1);
583
+ `;
584
+ }
585
+
586
+ // Apply theme color accent bar (optional)
587
+ if (showAccentBar) {
588
+ const accentBar = document.createElement('div');
589
+ accentBar.style.cssText = `
590
+ position: absolute;
591
+ top: 0;
592
+ left: 0;
593
+ right: 0;
594
+ height: ${accentBarHeight}px;
595
+ background: linear-gradient(90deg, ${colors[0]}, ${colors[1]}, ${colors[2]});
596
+ border-radius: ${borderRadius}px ${borderRadius}px 0 0;
597
+ `;
598
+ wrapper.appendChild(accentBar);
599
+ }
600
+ }
601
+ }
602
+
603
+ export function kpicard(id: string, options: KPICardOptions = {}): KPICard {
604
+ return new KPICard(id, options);
605
+ }
package/lib/jux.ts CHANGED
@@ -50,7 +50,10 @@ import { req, Req, type RequestInfo } from './components/req.js';
50
50
  import { heading, Heading, type HeadingOptions } from './components/heading.js';
51
51
  import { paragraph, Paragraph, type ParagraphOptions } from './components/paragraph.js';
52
52
  import { barchart, BarChart, type BarChartOptions, type BarChartDataPoint } from './components/barchart.js';
53
-
53
+ import { areachart, AreaChart, type AreaChartOptions, type AreaChartDataPoint } from './components/areachart.js';
54
+ import { areachartsmooth, AreaChartSmooth, type AreaChartSmoothOptions, AreaChartSmoothDataPoint } from './components/areachartsmooth.js';
55
+ import { doughnutchart, DoughnutChart, type DoughnutChartOptions, type DoughnutChartDataPoint } from './components/doughnutchart.js';
56
+ import { kpicard, KPICard, type KPICardOptions } from './components/kpicard.js';
54
57
 
55
58
  /* -------------------------
56
59
  * Type Exports
@@ -106,7 +109,14 @@ export type {
106
109
  HeadingOptions,
107
110
  ParagraphOptions,
108
111
  BarChartOptions,
109
- BarChartDataPoint
112
+ BarChartDataPoint,
113
+ AreaChartOptions,
114
+ AreaChartDataPoint,
115
+ AreaChartSmoothOptions,
116
+ AreaChartSmoothDataPoint,
117
+ DoughnutChartOptions,
118
+ DoughnutChartDataPoint,
119
+ KPICardOptions
110
120
  };
111
121
 
112
122
  /* -------------------------
@@ -158,7 +168,11 @@ export {
158
168
  Req,
159
169
  Heading,
160
170
  Paragraph,
161
- BarChart
171
+ BarChart,
172
+ AreaChart,
173
+ AreaChartSmooth,
174
+ DoughnutChart,
175
+ KPICard
162
176
  };
163
177
 
164
178
  /* -------------------------
@@ -216,6 +230,10 @@ export interface JuxAPI {
216
230
  heading: typeof heading;
217
231
  paragraph: typeof paragraph;
218
232
  barchart: typeof barchart;
233
+ areachart: typeof areachart;
234
+ areachartsmooth: typeof areachartsmooth;
235
+ doughnutchart: typeof doughnutchart;
236
+ kpicard: typeof kpicard;
219
237
  }
220
238
 
221
239
  /* -------------------------
@@ -289,6 +307,10 @@ class Jux implements JuxAPI {
289
307
  heading = heading;
290
308
  paragraph = paragraph;
291
309
  barchart = barchart;
310
+ areachart = areachart;
311
+ areachartsmooth = areachartsmooth;
312
+ doughnutchart = doughnutchart;
313
+ kpicard = kpicard;
292
314
  }
293
315
 
294
316
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "lib/jux.js",