@internetarchive/histogram-date-range 0.1.12-alpha.2 → 1.0.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.
@@ -13,6 +13,8 @@ export declare class HistogramDateRange extends LitElement {
13
13
  maxDate: string;
14
14
  disabled: boolean;
15
15
  bins: number[];
16
+ /** If true, update events will not be canceled by the date inputs receiving focus */
17
+ updateWhileFocused: boolean;
16
18
  private _tooltipOffset;
17
19
  private _tooltipContent?;
18
20
  private _tooltipVisible;
@@ -115,6 +117,7 @@ export declare class HistogramDateRange extends LitElement {
115
117
  private translateDateToPosition;
116
118
  /** ensure that the returned value is between minValue and maxValue */
117
119
  private clamp;
120
+ private handleInputFocus;
118
121
  private handleMinDateInput;
119
122
  private handleMaxDateInput;
120
123
  private handleKeyUp;
@@ -56,6 +56,8 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
56
56
  this.maxDate = '';
57
57
  this.disabled = false;
58
58
  this.bins = [];
59
+ /** If true, update events will not be canceled by the date inputs receiving focus */
60
+ this.updateWhileFocused = false;
59
61
  // internal reactive properties not exposed as attributes
60
62
  this._tooltipOffset = 0;
61
63
  this._tooltipVisible = false;
@@ -258,9 +260,9 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
258
260
  const formattedNumItems = Number(dataset.numItems).toLocaleString();
259
261
  this._tooltipOffset =
260
262
  x + (this._binWidth - this.sliderWidth - this.tooltipWidth) / 2;
261
- this._tooltipContent = html `
262
- ${formattedNumItems} ${itemsText}<br />
263
- ${dataset.binStart} - ${dataset.binEnd}
263
+ this._tooltipContent = html `
264
+ ${formattedNumItems} ${itemsText}<br />
265
+ ${dataset.binStart} - ${dataset.binEnd}
264
266
  `;
265
267
  this._tooltipVisible = true;
266
268
  }
@@ -377,6 +379,11 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
377
379
  clamp(x, minValue, maxValue) {
378
380
  return Math.min(Math.max(x, minValue), maxValue);
379
381
  }
382
+ handleInputFocus() {
383
+ if (!this.updateWhileFocused) {
384
+ this.cancelPendingUpdateEvent();
385
+ }
386
+ }
380
387
  handleMinDateInput(e) {
381
388
  const target = e.currentTarget;
382
389
  if (target.value !== this.minSelectedDate) {
@@ -450,25 +457,25 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
450
457
  // border-radius); used as part of a SVG quadratic curve. see
451
458
  // https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths#curve_commands
452
459
  const cs = SLIDER_CORNER_SIZE;
453
- const sliderShape = `
454
- M${this.minSliderX},0
455
- h-${this.sliderWidth - cs}
456
- q-${cs},0 -${cs},${cs}
457
- v${this.height - cs * 2}
458
- q0,${cs} ${cs},${cs}
459
- h${this.sliderWidth - cs}
460
+ const sliderShape = `
461
+ M${this.minSliderX},0
462
+ h-${this.sliderWidth - cs}
463
+ q-${cs},0 -${cs},${cs}
464
+ v${this.height - cs * 2}
465
+ q0,${cs} ${cs},${cs}
466
+ h${this.sliderWidth - cs}
460
467
  `;
461
468
  return this.generateSliderSVG(this.minSliderX, 'slider-min', sliderShape);
462
469
  }
463
470
  get maxSliderTemplate() {
464
471
  const cs = SLIDER_CORNER_SIZE;
465
- const sliderShape = `
466
- M${this.maxSliderX},0
467
- h${this.sliderWidth - cs}
468
- q${cs},0 ${cs},${cs}
469
- v${this.height - cs * 2}
470
- q0,${cs} -${cs},${cs}
471
- h-${this.sliderWidth - cs}
472
+ const sliderShape = `
473
+ M${this.maxSliderX},0
474
+ h${this.sliderWidth - cs}
475
+ q${cs},0 ${cs},${cs}
476
+ v${this.height - cs * 2}
477
+ q0,${cs} -${cs},${cs}
478
+ h-${this.sliderWidth - cs}
472
479
  `;
473
480
  return this.generateSliderSVG(this.maxSliderX, 'slider-max', sliderShape);
474
481
  }
@@ -476,40 +483,40 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
476
483
  // whether the curved part of the slider is facing towards the left (1), ie
477
484
  // minimum, or facing towards the right (-1), ie maximum
478
485
  const k = id === 'slider-min' ? 1 : -1;
479
- return svg `
480
- <svg
481
- id="${id}"
482
- class="
483
- ${this.disabled ? '' : 'draggable'}
484
- ${this._isDragging ? 'dragging' : ''}"
485
- @pointerdown="${this.drag}"
486
- >
487
- <path d="${sliderShape} z" fill="${sliderColor}" />
488
- <rect
489
- x="${sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.4 * k}"
490
- y="${this.height / 3}"
491
- width="1"
492
- height="${this.height / 3}"
493
- fill="white"
494
- />
495
- <rect
496
- x="${sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.6 * k}"
497
- y="${this.height / 3}"
498
- width="1"
499
- height="${this.height / 3}"
500
- fill="white"
501
- />
502
- </svg>
486
+ return svg `
487
+ <svg
488
+ id="${id}"
489
+ class="
490
+ ${this.disabled ? '' : 'draggable'}
491
+ ${this._isDragging ? 'dragging' : ''}"
492
+ @pointerdown="${this.drag}"
493
+ >
494
+ <path d="${sliderShape} z" fill="${sliderColor}" />
495
+ <rect
496
+ x="${sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.4 * k}"
497
+ y="${this.height / 3}"
498
+ width="1"
499
+ height="${this.height / 3}"
500
+ fill="white"
501
+ />
502
+ <rect
503
+ x="${sliderPositionX - this.sliderWidth * k + this.sliderWidth * 0.6 * k}"
504
+ y="${this.height / 3}"
505
+ width="1"
506
+ height="${this.height / 3}"
507
+ fill="white"
508
+ />
509
+ </svg>
503
510
  `;
504
511
  }
505
512
  get selectedRangeTemplate() {
506
- return svg `
507
- <rect
508
- x="${this.minSliderX}"
509
- y="0"
510
- width="${this.maxSliderX - this.minSliderX}"
511
- height="${this.height}"
512
- fill="${selectedRangeColor}"
513
+ return svg `
514
+ <rect
515
+ x="${this.minSliderX}"
516
+ y="0"
517
+ width="${this.maxSliderX - this.minSliderX}"
518
+ height="${this.height}"
519
+ fill="${selectedRangeColor}"
513
520
  />`;
514
521
  }
515
522
  get histogramTemplate() {
@@ -521,23 +528,23 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
521
528
  // between adjacent bars (eg when viewing the tooltips or when trying to
522
529
  // extend the range by clicking on a bar)
523
530
  return this._histData.map(data => {
524
- const bar = svg `
525
- <rect
526
- class="bar"
527
- style='stroke-dasharray: 0 ${barWidth} ${data.height} ${barWidth} 0 ${data.height};'
528
- x="${x}"
529
- y="${this.height - data.height}"
530
- width="${barWidth}"
531
- height="${data.height}"
532
- @pointerenter="${this.showTooltip}"
533
- @pointerleave="${this.hideTooltip}"
534
- @click="${this.handleBarClick}"
531
+ const bar = svg `
532
+ <rect
533
+ class="bar"
534
+ style='stroke-dasharray: 0 ${barWidth} ${data.height} ${barWidth} 0 ${data.height};'
535
+ x="${x}"
536
+ y="${this.height - data.height}"
537
+ width="${barWidth}"
538
+ height="${data.height}"
539
+ @pointerenter="${this.showTooltip}"
540
+ @pointerleave="${this.hideTooltip}"
541
+ @click="${this.handleBarClick}"
535
542
  fill="${x + barWidth >= this.minSliderX && x <= this.maxSliderX
536
543
  ? barIncludedFill
537
- : barExcludedFill}"
538
- data-num-items="${data.value}"
539
- data-bin-start="${data.binStart}"
540
- data-bin-end="${data.binEnd}"
544
+ : barExcludedFill}"
545
+ data-num-items="${data.value}"
546
+ data-bin-start="${data.binStart}"
547
+ data-bin-end="${data.binEnd}"
541
548
  />`;
542
549
  x += xScale;
543
550
  return bar;
@@ -562,31 +569,31 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
562
569
  * https://lit.dev/docs/templates/directives/#live
563
570
  */
564
571
  get minInputTemplate() {
565
- return html `
566
- <input
567
- id="date-min"
568
- placeholder="${this.dateFormat}"
569
- type="text"
570
- @focus="${this.cancelPendingUpdateEvent}"
571
- @blur="${this.handleMinDateInput}"
572
- @keyup="${this.handleKeyUp}"
573
- .value="${live(this.minSelectedDate)}"
574
- ?disabled="${this.disabled}"
575
- />
572
+ return html `
573
+ <input
574
+ id="date-min"
575
+ placeholder="${this.dateFormat}"
576
+ type="text"
577
+ @focus="${this.handleInputFocus}"
578
+ @blur="${this.handleMinDateInput}"
579
+ @keyup="${this.handleKeyUp}"
580
+ .value="${live(this.minSelectedDate)}"
581
+ ?disabled="${this.disabled}"
582
+ />
576
583
  `;
577
584
  }
578
585
  get maxInputTemplate() {
579
- return html `
580
- <input
581
- id="date-max"
582
- placeholder="${this.dateFormat}"
583
- type="text"
584
- @focus="${this.cancelPendingUpdateEvent}"
585
- @blur="${this.handleMaxDateInput}"
586
- @keyup="${this.handleKeyUp}"
587
- .value="${live(this.maxSelectedDate)}"
588
- ?disabled="${this.disabled}"
589
- />
586
+ return html `
587
+ <input
588
+ id="date-max"
589
+ placeholder="${this.dateFormat}"
590
+ type="text"
591
+ @focus="${this.handleInputFocus}"
592
+ @blur="${this.handleMaxDateInput}"
593
+ @keyup="${this.handleKeyUp}"
594
+ .value="${live(this.maxSelectedDate)}"
595
+ ?disabled="${this.disabled}"
596
+ />
590
597
  `;
591
598
  }
592
599
  get minLabelTemplate() {
@@ -596,184 +603,184 @@ let HistogramDateRange = class HistogramDateRange extends LitElement {
596
603
  return html `<label for="date-max" class="sr-only">Maximum date:</label>`;
597
604
  }
598
605
  get tooltipTemplate() {
599
- return html `
600
- <style>
601
- #tooltip {
602
- width: ${this.tooltipWidth}px;
603
- height: ${this.tooltipHeight}px;
604
- top: ${-9 - this.tooltipHeight}px;
605
- left: ${this._tooltipOffset}px;
606
- display: ${this._tooltipVisible ? 'block' : 'none'};
607
- }
608
- #tooltip:after {
609
- left: ${this.tooltipWidth / 2}px;
610
- }
611
- </style>
612
- <div id="tooltip">${this._tooltipContent}</div>
606
+ return html `
607
+ <style>
608
+ #tooltip {
609
+ width: ${this.tooltipWidth}px;
610
+ height: ${this.tooltipHeight}px;
611
+ top: ${-9 - this.tooltipHeight}px;
612
+ left: ${this._tooltipOffset}px;
613
+ display: ${this._tooltipVisible ? 'block' : 'none'};
614
+ }
615
+ #tooltip:after {
616
+ left: ${this.tooltipWidth / 2}px;
617
+ }
618
+ </style>
619
+ <div id="tooltip">${this._tooltipContent}</div>
613
620
  `;
614
621
  }
615
622
  get noDataTemplate() {
616
- return html `
617
- <div class="missing-data-message">${this.missingDataMessage}</div>
623
+ return html `
624
+ <div class="missing-data-message">${this.missingDataMessage}</div>
618
625
  `;
619
626
  }
620
627
  get activityIndicatorTemplate() {
621
628
  if (!this.loading) {
622
629
  return nothing;
623
630
  }
624
- return html `
625
- <ia-activity-indicator mode="processing"> </ia-activity-indicator>
631
+ return html `
632
+ <ia-activity-indicator mode="processing"> </ia-activity-indicator>
626
633
  `;
627
634
  }
628
635
  render() {
629
636
  if (!this.hasBinData) {
630
637
  return this.noDataTemplate;
631
638
  }
632
- return html `
633
- <div
634
- id="container"
635
- class="
636
- noselect
637
- ${this._isDragging ? 'dragging' : ''}
638
- "
639
- style="width: ${this.width}px"
640
- >
641
- ${this.activityIndicatorTemplate} ${this.tooltipTemplate}
642
- <div
643
- class="inner-container
644
- ${this.disabled ? 'disabled' : ''}"
645
- >
646
- <svg
647
- width="${this.width}"
648
- height="${this.height}"
649
- @pointerleave="${this.drop}"
650
- >
651
- ${this.selectedRangeTemplate}
652
- <svg id="histogram">${this.histogramTemplate}</svg>
653
- ${this.minSliderTemplate} ${this.maxSliderTemplate}
654
- </svg>
655
- <div id="inputs">
656
- ${this.minLabelTemplate} ${this.minInputTemplate}
657
- <div class="dash">-</div>
658
- ${this.maxLabelTemplate} ${this.maxInputTemplate}
659
- <slot name="inputs-right-side"></slot>
660
- </div>
661
- </div>
662
- </div>
639
+ return html `
640
+ <div
641
+ id="container"
642
+ class="
643
+ noselect
644
+ ${this._isDragging ? 'dragging' : ''}
645
+ "
646
+ style="width: ${this.width}px"
647
+ >
648
+ ${this.activityIndicatorTemplate} ${this.tooltipTemplate}
649
+ <div
650
+ class="inner-container
651
+ ${this.disabled ? 'disabled' : ''}"
652
+ >
653
+ <svg
654
+ width="${this.width}"
655
+ height="${this.height}"
656
+ @pointerleave="${this.drop}"
657
+ >
658
+ ${this.selectedRangeTemplate}
659
+ <svg id="histogram">${this.histogramTemplate}</svg>
660
+ ${this.minSliderTemplate} ${this.maxSliderTemplate}
661
+ </svg>
662
+ <div id="inputs">
663
+ ${this.minLabelTemplate} ${this.minInputTemplate}
664
+ <div class="dash">-</div>
665
+ ${this.maxLabelTemplate} ${this.maxInputTemplate}
666
+ <slot name="inputs-right-side"></slot>
667
+ </div>
668
+ </div>
669
+ </div>
663
670
  `;
664
671
  }
665
672
  };
666
- HistogramDateRange.styles = css `
667
- .missing-data-message {
668
- text-align: center;
669
- }
670
- #container {
671
- margin: 0;
672
- touch-action: none;
673
- position: relative;
674
- }
675
- .disabled {
676
- opacity: 0.3;
677
- }
678
- ia-activity-indicator {
679
- position: absolute;
680
- left: calc(50% - 10px);
681
- top: 10px;
682
- width: 20px;
683
- height: 20px;
684
- --activityIndicatorLoadingDotColor: rgba(0, 0, 0, 0);
685
- --activityIndicatorLoadingRingColor: ${activityIndicatorColor};
686
- }
687
-
688
- /* prevent selection from interfering with tooltip, especially on mobile */
689
- /* https://stackoverflow.com/a/4407335/1163042 */
690
- .noselect {
691
- -webkit-touch-callout: none; /* iOS Safari */
692
- -webkit-user-select: none; /* Safari */
693
- -moz-user-select: none; /* Old versions of Firefox */
694
- -ms-user-select: none; /* Internet Explorer/Edge */
695
- user-select: none; /* current Chrome, Edge, Opera and Firefox */
696
- }
697
- .bar {
698
- /* create a transparent border around the hist bars to prevent "gaps" and
699
- flickering when moving around between bars. this also helps with handling
700
- clicks on the bars, preventing users from being able to click in between
701
- bars */
702
- stroke: rgba(0, 0, 0, 0);
703
- /* ensure transparent stroke wide enough to cover gap between bars */
704
- stroke-width: 2px;
705
- }
706
- .bar:hover {
707
- /* highlight currently hovered bar */
708
- fill-opacity: 0.7;
709
- }
710
- .disabled .bar:hover {
711
- /* ensure no visual hover interaction when disabled */
712
- fill-opacity: 1;
713
- }
714
- /****** histogram ********/
715
- #tooltip {
716
- position: absolute;
717
- background: ${tooltipBackgroundColor};
718
- color: ${tooltipTextColor};
719
- text-align: center;
720
- border-radius: 3px;
721
- padding: 2px;
722
- font-size: ${tooltipFontSize};
723
- font-family: ${tooltipFontFamily};
724
- touch-action: none;
725
- pointer-events: none;
726
- }
727
- #tooltip:after {
728
- content: '';
729
- position: absolute;
730
- margin-left: -5px;
731
- top: 100%;
732
- /* arrow */
733
- border: 5px solid ${tooltipTextColor};
734
- border-color: ${tooltipBackgroundColor} transparent transparent
735
- transparent;
736
- }
737
- /****** slider ********/
738
- .draggable:hover {
739
- cursor: grab;
740
- }
741
- .dragging {
742
- cursor: grabbing !important;
743
- }
744
- /****** inputs ********/
745
- #inputs {
746
- display: flex;
747
- justify-content: center;
748
- margin: ${inputRowMargin};
749
- }
750
- #inputs .dash {
751
- position: relative;
752
- bottom: -1px;
753
- align-self: center; /* Otherwise the dash sticks to the top while the inputs grow */
754
- }
755
- input {
756
- width: ${inputWidth};
757
- margin: 0 3px;
758
- border: ${inputBorder};
759
- border-radius: 2px !important;
760
- text-align: center;
761
- font-size: ${inputFontSize};
762
- font-family: ${inputFontFamily};
763
- }
764
- .sr-only {
765
- position: absolute !important;
766
- width: 1px !important;
767
- height: 1px !important;
768
- margin: 0 !important;
769
- padding: 0 !important;
770
- border: 0 !important;
771
- overflow: hidden !important;
772
- white-space: nowrap !important;
773
- clip: rect(1px, 1px, 1px, 1px) !important;
774
- -webkit-clip-path: inset(50%) !important;
775
- clip-path: inset(50%) !important;
776
- }
673
+ HistogramDateRange.styles = css `
674
+ .missing-data-message {
675
+ text-align: center;
676
+ }
677
+ #container {
678
+ margin: 0;
679
+ touch-action: none;
680
+ position: relative;
681
+ }
682
+ .disabled {
683
+ opacity: 0.3;
684
+ }
685
+ ia-activity-indicator {
686
+ position: absolute;
687
+ left: calc(50% - 10px);
688
+ top: 10px;
689
+ width: 20px;
690
+ height: 20px;
691
+ --activityIndicatorLoadingDotColor: rgba(0, 0, 0, 0);
692
+ --activityIndicatorLoadingRingColor: ${activityIndicatorColor};
693
+ }
694
+
695
+ /* prevent selection from interfering with tooltip, especially on mobile */
696
+ /* https://stackoverflow.com/a/4407335/1163042 */
697
+ .noselect {
698
+ -webkit-touch-callout: none; /* iOS Safari */
699
+ -webkit-user-select: none; /* Safari */
700
+ -moz-user-select: none; /* Old versions of Firefox */
701
+ -ms-user-select: none; /* Internet Explorer/Edge */
702
+ user-select: none; /* current Chrome, Edge, Opera and Firefox */
703
+ }
704
+ .bar {
705
+ /* create a transparent border around the hist bars to prevent "gaps" and
706
+ flickering when moving around between bars. this also helps with handling
707
+ clicks on the bars, preventing users from being able to click in between
708
+ bars */
709
+ stroke: rgba(0, 0, 0, 0);
710
+ /* ensure transparent stroke wide enough to cover gap between bars */
711
+ stroke-width: 2px;
712
+ }
713
+ .bar:hover {
714
+ /* highlight currently hovered bar */
715
+ fill-opacity: 0.7;
716
+ }
717
+ .disabled .bar:hover {
718
+ /* ensure no visual hover interaction when disabled */
719
+ fill-opacity: 1;
720
+ }
721
+ /****** histogram ********/
722
+ #tooltip {
723
+ position: absolute;
724
+ background: ${tooltipBackgroundColor};
725
+ color: ${tooltipTextColor};
726
+ text-align: center;
727
+ border-radius: 3px;
728
+ padding: 2px;
729
+ font-size: ${tooltipFontSize};
730
+ font-family: ${tooltipFontFamily};
731
+ touch-action: none;
732
+ pointer-events: none;
733
+ }
734
+ #tooltip:after {
735
+ content: '';
736
+ position: absolute;
737
+ margin-left: -5px;
738
+ top: 100%;
739
+ /* arrow */
740
+ border: 5px solid ${tooltipTextColor};
741
+ border-color: ${tooltipBackgroundColor} transparent transparent
742
+ transparent;
743
+ }
744
+ /****** slider ********/
745
+ .draggable:hover {
746
+ cursor: grab;
747
+ }
748
+ .dragging {
749
+ cursor: grabbing !important;
750
+ }
751
+ /****** inputs ********/
752
+ #inputs {
753
+ display: flex;
754
+ justify-content: center;
755
+ margin: ${inputRowMargin};
756
+ }
757
+ #inputs .dash {
758
+ position: relative;
759
+ bottom: -1px;
760
+ align-self: center; /* Otherwise the dash sticks to the top while the inputs grow */
761
+ }
762
+ input {
763
+ width: ${inputWidth};
764
+ margin: 0 3px;
765
+ border: ${inputBorder};
766
+ border-radius: 2px !important;
767
+ text-align: center;
768
+ font-size: ${inputFontSize};
769
+ font-family: ${inputFontFamily};
770
+ }
771
+ .sr-only {
772
+ position: absolute !important;
773
+ width: 1px !important;
774
+ height: 1px !important;
775
+ margin: 0 !important;
776
+ padding: 0 !important;
777
+ border: 0 !important;
778
+ overflow: hidden !important;
779
+ white-space: nowrap !important;
780
+ clip: rect(1px, 1px, 1px, 1px) !important;
781
+ -webkit-clip-path: inset(50%) !important;
782
+ clip-path: inset(50%) !important;
783
+ }
777
784
  `;
778
785
  __decorate([
779
786
  property({ type: Number })
@@ -811,6 +818,9 @@ __decorate([
811
818
  __decorate([
812
819
  property({ type: Object })
813
820
  ], HistogramDateRange.prototype, "bins", void 0);
821
+ __decorate([
822
+ property({ type: Boolean })
823
+ ], HistogramDateRange.prototype, "updateWhileFocused", void 0);
814
824
  __decorate([
815
825
  state()
816
826
  ], HistogramDateRange.prototype, "_tooltipOffset", void 0);