@nyaruka/temba-components 0.128.0 → 0.129.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/CHANGELOG.md +12 -0
- package/demo/chart/horizontal-demo.html +81 -0
- package/demo/components/datepicker/example.html +63 -0
- package/demo/components/datepicker/range-picker-demo.html +161 -0
- package/demo/index.html +8 -0
- package/demo/static/css/prism.css +2 -0
- package/demo/static/js/prism-loader.js +12 -0
- package/demo/styles.css +71 -1
- package/dist/temba-components.js +172 -10
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/chart/TembaChart.js +116 -59
- package/out-tsc/src/chart/TembaChart.js.map +1 -1
- package/out-tsc/src/datepicker/DatePicker.js +11 -1
- package/out-tsc/src/datepicker/DatePicker.js.map +1 -1
- package/out-tsc/src/datepicker/RangePicker.js +595 -0
- package/out-tsc/src/datepicker/RangePicker.js.map +1 -0
- package/out-tsc/src/interfaces.js +1 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/temba-modules.js +3 -1
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-chart.test.js +36 -0
- package/out-tsc/test/temba-chart.test.js.map +1 -1
- package/out-tsc/test/temba-datepicker.test.js +1 -1
- package/out-tsc/test/temba-datepicker.test.js.map +1 -1
- package/out-tsc/test/temba-range-picker.test.js +123 -0
- package/out-tsc/test/temba-range-picker.test.js.map +1 -0
- package/out-tsc/test/temba-select.test.js +1 -1
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/temba-webchat.test.js +4 -0
- package/out-tsc/test/temba-webchat.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/datepicker/range-picker-all.png +0 -0
- package/screenshots/truth/datepicker/range-picker-button-states.png +0 -0
- package/screenshots/truth/datepicker/range-picker-default.png +0 -0
- package/screenshots/truth/datepicker/range-picker-editing-start.png +0 -0
- package/screenshots/truth/datepicker/range-picker-initial-values.png +0 -0
- package/screenshots/truth/datepicker/range-picker-min-max.png +0 -0
- package/screenshots/truth/datepicker/range-picker-week.png +0 -0
- package/screenshots/truth/datepicker/range-picker-year.png +0 -0
- package/screenshots/truth/webchat/connected-state.png +0 -0
- package/src/chart/TembaChart.ts +124 -63
- package/src/datepicker/DatePicker.ts +9 -1
- package/src/datepicker/RangePicker.ts +602 -0
- package/src/interfaces.ts +2 -1
- package/temba-modules.ts +3 -1
- package/test/temba-chart.test.ts +47 -0
- package/test/temba-datepicker.test.ts +1 -1
- package/test/temba-range-picker.test.ts +193 -0
- package/test/temba-select.test.ts +1 -1
- package/test/temba-webchat.test.ts +7 -0
- package/web-test-runner.config.mjs +2 -0
- package/demo/datepicker/example.html +0 -69
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/chart/TembaChart.ts
CHANGED
|
@@ -268,9 +268,18 @@ export class TembaChart extends RapidElement {
|
|
|
268
268
|
@property({ type: String })
|
|
269
269
|
chartType: ChartType = 'bar';
|
|
270
270
|
|
|
271
|
+
@property({ type: Boolean })
|
|
272
|
+
horizontal: boolean = false;
|
|
273
|
+
|
|
271
274
|
@property({ type: String })
|
|
272
275
|
url: string;
|
|
273
276
|
|
|
277
|
+
@property({ type: String })
|
|
278
|
+
start: string;
|
|
279
|
+
|
|
280
|
+
@property({ type: String })
|
|
281
|
+
end: string;
|
|
282
|
+
|
|
274
283
|
@property({ type: String })
|
|
275
284
|
header: string = '';
|
|
276
285
|
|
|
@@ -441,11 +450,33 @@ export class TembaChart extends RapidElement {
|
|
|
441
450
|
this.updateChart();
|
|
442
451
|
}
|
|
443
452
|
|
|
444
|
-
if (changes.has('
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
453
|
+
if (changes.has('horizontal')) {
|
|
454
|
+
this.updateChart();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (changes.has('url') || changes.has('start') || changes.has('end')) {
|
|
458
|
+
if (this.url) {
|
|
459
|
+
const store = getStore();
|
|
460
|
+
let fullUrl = this.url;
|
|
461
|
+
|
|
462
|
+
// Add query parameters for date range if provided
|
|
463
|
+
const params = new URLSearchParams();
|
|
464
|
+
if (this.start) {
|
|
465
|
+
params.append('since', this.start);
|
|
466
|
+
}
|
|
467
|
+
if (this.end) {
|
|
468
|
+
params.append('until', this.end);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (params.toString()) {
|
|
472
|
+
const separator = this.url.includes('?') ? '&' : '?';
|
|
473
|
+
fullUrl = `${this.url}${separator}${params.toString()}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
store.getUrl(fullUrl, { skipCache: true }).then((response) => {
|
|
477
|
+
this.data = response.json.data;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
449
480
|
}
|
|
450
481
|
|
|
451
482
|
if (changes.has('chartType')) {
|
|
@@ -455,11 +486,14 @@ export class TembaChart extends RapidElement {
|
|
|
455
486
|
}
|
|
456
487
|
|
|
457
488
|
if (changes.has('showPercent') && this.chart) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
489
|
+
// in horizontal charts, the value axis is X, in vertical charts it's Y
|
|
490
|
+
const valueScale = this.horizontal
|
|
491
|
+
? (this.chart.options.scales as any).x
|
|
492
|
+
: (this.chart.options.scales as any).y;
|
|
493
|
+
valueScale.ticks.display = !this.showPercent;
|
|
494
|
+
valueScale.grid.display = !this.showPercent;
|
|
495
|
+
valueScale.border.display = !this.showPercent;
|
|
496
|
+
valueScale.max = this.showPercent ? this.getInflatedMax() : undefined;
|
|
463
497
|
this.chart.update();
|
|
464
498
|
}
|
|
465
499
|
}
|
|
@@ -627,23 +661,17 @@ export class TembaChart extends RapidElement {
|
|
|
627
661
|
}
|
|
628
662
|
this.chart.options.plugins.datalabels = datalabels;
|
|
629
663
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const first = Date.parse(firstDate);
|
|
638
|
-
const last = Date.parse(lastDate);
|
|
639
|
-
|
|
640
|
-
const dayDiff = Math.ceil((last - first) / (1000 * 60 * 60 * 24));
|
|
641
|
-
format = 'MMM dd';
|
|
642
|
-
if (dayDiff > 365) {
|
|
643
|
-
format = 'MMM yyyy';
|
|
644
|
-
}
|
|
664
|
+
// the scale config could have changed, so we need to update it
|
|
665
|
+
if (this.horizontal) {
|
|
666
|
+
this.chart.options.scales.x = this.getValueAxisConfig();
|
|
667
|
+
this.chart.options.scales.y = this.getCategoryAxisConfig() as any;
|
|
668
|
+
} else {
|
|
669
|
+
this.chart.options.scales.x = this.getCategoryAxisConfig() as any;
|
|
670
|
+
this.chart.options.scales.y = this.getValueAxisConfig();
|
|
645
671
|
}
|
|
646
672
|
|
|
673
|
+
this.chart.update();
|
|
674
|
+
} else {
|
|
647
675
|
const chartData = {
|
|
648
676
|
type: this.chartType,
|
|
649
677
|
data: {
|
|
@@ -651,6 +679,7 @@ export class TembaChart extends RapidElement {
|
|
|
651
679
|
datasets: this.datasets
|
|
652
680
|
},
|
|
653
681
|
options: {
|
|
682
|
+
...(this.horizontal && { indexAxis: 'y' }),
|
|
654
683
|
maxBarThickness: 80,
|
|
655
684
|
plugins: {
|
|
656
685
|
legend: { display: this.legend },
|
|
@@ -658,7 +687,10 @@ export class TembaChart extends RapidElement {
|
|
|
658
687
|
callbacks: {
|
|
659
688
|
label: (context: any) => {
|
|
660
689
|
const label = context.dataset.label || '';
|
|
661
|
-
|
|
690
|
+
// in horizontal charts, the value is on parsed.x, in vertical charts on parsed.y
|
|
691
|
+
const value = this.horizontal
|
|
692
|
+
? context.parsed.x
|
|
693
|
+
: context.parsed.y;
|
|
662
694
|
if (this.yType === 'duration') {
|
|
663
695
|
return `${label}: ${formatDurationFromSeconds(value)}`;
|
|
664
696
|
}
|
|
@@ -690,44 +722,15 @@ export class TembaChart extends RapidElement {
|
|
|
690
722
|
duration: 0
|
|
691
723
|
}
|
|
692
724
|
},
|
|
693
|
-
scales:
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
drawBorder: !this.showPercent // hides axis line when false
|
|
702
|
-
},
|
|
703
|
-
border: {
|
|
704
|
-
display: !this.showPercent // Chart.js >= 4
|
|
705
|
-
},
|
|
706
|
-
ticks: {
|
|
707
|
-
display: !this.showPercent,
|
|
708
|
-
|
|
709
|
-
...(this.yType === 'duration' &&
|
|
710
|
-
!this.showPercent && {
|
|
711
|
-
callback: (value: any) => formatDurationFromSeconds(value)
|
|
712
|
-
})
|
|
725
|
+
scales: this.horizontal
|
|
726
|
+
? {
|
|
727
|
+
x: this.getValueAxisConfig(),
|
|
728
|
+
y: this.getCategoryAxisConfig()
|
|
729
|
+
}
|
|
730
|
+
: {
|
|
731
|
+
y: this.getValueAxisConfig(),
|
|
732
|
+
x: this.getCategoryAxisConfig()
|
|
713
733
|
}
|
|
714
|
-
},
|
|
715
|
-
x: {
|
|
716
|
-
type: this.xType,
|
|
717
|
-
grid: { display: false },
|
|
718
|
-
stacked: true,
|
|
719
|
-
ticks: {
|
|
720
|
-
maxTicksLimit: this.xMaxTicks
|
|
721
|
-
},
|
|
722
|
-
...(this.xType === 'time' && {
|
|
723
|
-
time: {
|
|
724
|
-
unit: 'day',
|
|
725
|
-
tooltipFormat: 'DDD',
|
|
726
|
-
displayFormats: { day: format }
|
|
727
|
-
}
|
|
728
|
-
})
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
734
|
}
|
|
732
735
|
};
|
|
733
736
|
|
|
@@ -750,6 +753,64 @@ export class TembaChart extends RapidElement {
|
|
|
750
753
|
}
|
|
751
754
|
}
|
|
752
755
|
|
|
756
|
+
private getValueAxisConfig() {
|
|
757
|
+
return {
|
|
758
|
+
min: 0,
|
|
759
|
+
...(this.showPercent && { max: this.getInflatedMax() }),
|
|
760
|
+
stacked: true,
|
|
761
|
+
grid: {
|
|
762
|
+
color: 'rgba(0,0,0,0.04)',
|
|
763
|
+
display: !this.showPercent,
|
|
764
|
+
drawBorder: !this.showPercent
|
|
765
|
+
},
|
|
766
|
+
border: {
|
|
767
|
+
display: !this.showPercent
|
|
768
|
+
},
|
|
769
|
+
ticks: {
|
|
770
|
+
display: !this.showPercent,
|
|
771
|
+
...(this.yType === 'duration' &&
|
|
772
|
+
!this.showPercent && {
|
|
773
|
+
callback: (value: any) => formatDurationFromSeconds(value)
|
|
774
|
+
})
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
private getCategoryAxisConfig() {
|
|
780
|
+
let format = this.xFormat;
|
|
781
|
+
if (this.xType === 'time' && this.xFormat === 'auto') {
|
|
782
|
+
const firstDate = this.data.labels[0];
|
|
783
|
+
const lastDate = this.data.labels[this.data.labels.length - 1];
|
|
784
|
+
|
|
785
|
+
const first = Date.parse(firstDate);
|
|
786
|
+
const last = Date.parse(lastDate);
|
|
787
|
+
|
|
788
|
+
const dayDiff = Math.ceil((last - first) / (1000 * 60 * 60 * 24));
|
|
789
|
+
format = 'MMM dd';
|
|
790
|
+
if (dayDiff > 365) {
|
|
791
|
+
format = 'MMM yyyy';
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return {
|
|
796
|
+
max: this.xType === 'time' ? this.end : this.xMaxTicks,
|
|
797
|
+
min: this.xType === 'time' ? this.start : 0,
|
|
798
|
+
type: this.xType,
|
|
799
|
+
grid: { display: false },
|
|
800
|
+
stacked: true,
|
|
801
|
+
ticks: {
|
|
802
|
+
maxTicksLimit: this.xMaxTicks
|
|
803
|
+
},
|
|
804
|
+
...(this.xType === 'time' && {
|
|
805
|
+
time: {
|
|
806
|
+
unit: 'day',
|
|
807
|
+
tooltipFormat: 'DDD',
|
|
808
|
+
displayFormats: { day: format }
|
|
809
|
+
}
|
|
810
|
+
})
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
|
|
753
814
|
protected render(): TemplateResult {
|
|
754
815
|
return html`<div>
|
|
755
816
|
${this.header
|
|
@@ -4,7 +4,7 @@ import { FormElement } from '../FormElement';
|
|
|
4
4
|
import { getClasses } from '../utils';
|
|
5
5
|
import { DateTime } from 'luxon';
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export class DatePicker extends FormElement {
|
|
8
8
|
static get styles() {
|
|
9
9
|
return css`
|
|
10
10
|
:host {
|
|
@@ -131,6 +131,12 @@ export default class DatePicker extends FormElement {
|
|
|
131
131
|
@property({ type: Boolean })
|
|
132
132
|
time = false;
|
|
133
133
|
|
|
134
|
+
@property({ type: String })
|
|
135
|
+
min = '';
|
|
136
|
+
|
|
137
|
+
@property({ type: String })
|
|
138
|
+
max = '';
|
|
139
|
+
|
|
134
140
|
/** we just return the value since it should be a string */
|
|
135
141
|
public serializeValue(value: any): string {
|
|
136
142
|
return value;
|
|
@@ -229,6 +235,8 @@ export default class DatePicker extends FormElement {
|
|
|
229
235
|
value=${dateWidgetValue}
|
|
230
236
|
type="${this.time ? 'datetime-local' : 'date'}"
|
|
231
237
|
@change=${this.handleChange}
|
|
238
|
+
min=${this.min || undefined}
|
|
239
|
+
max=${this.max || undefined}
|
|
232
240
|
/>
|
|
233
241
|
</div>
|
|
234
242
|
${this.time
|