@internetarchive/histogram-date-range 0.1.0-beta → 0.1.3-alpha

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.
@@ -1,4 +1,3 @@
1
- /* eslint-disable no-debugger */
2
1
  import { html, fixture, expect, oneEvent, aTimeout } from '@open-wc/testing';
3
2
 
4
3
  import { HistogramDateRange } from '../src/histogram-date-range';
@@ -13,9 +12,8 @@ const subject = html`
13
12
  tooltipWidth="140"
14
13
  height="50"
15
14
  dateFormat="M/D/YYYY"
16
- updateDelay="10"
17
15
  minDate="1900"
18
- maxDate="Dec 4, 2020"
16
+ maxDate="12/4/2020"
19
17
  bins="[33, 1, 100]"
20
18
  >
21
19
  </histogram-date-range>
@@ -47,9 +45,9 @@ async function createCustomElementInHTMLContainer(): Promise<HistogramDateRange>
47
45
  describe('HistogramDateRange', () => {
48
46
  it('shows scaled histogram bars when provided with data', async () => {
49
47
  const el = await createCustomElementInHTMLContainer();
50
- const bars = (el.shadowRoot?.querySelectorAll(
48
+ const bars = el.shadowRoot?.querySelectorAll(
51
49
  '.bar'
52
- ) as unknown) as SVGRectElement[];
50
+ ) as unknown as SVGRectElement[];
53
51
  const heights = Array.from(bars).map(b => b.height.baseVal.value);
54
52
 
55
53
  expect(heights).to.eql([38, 7, 50]);
@@ -64,19 +62,24 @@ describe('HistogramDateRange', () => {
64
62
  '#date-min'
65
63
  ) as HTMLInputElement;
66
64
 
65
+ const pressEnterEvent = new KeyboardEvent('keyup', {
66
+ key: 'Enter',
67
+ });
68
+
67
69
  // valid min date
68
70
  minDateInput.value = '1950';
69
- minDateInput.dispatchEvent(new Event('blur'));
71
+ minDateInput.dispatchEvent(pressEnterEvent);
70
72
 
71
73
  expect(Math.floor(el.minSliderX)).to.eq(84);
72
74
  expect(el.minSelectedDate).to.eq('1/1/1950'); // set to correct format
73
75
 
74
76
  // attempt to set date earlier than first item
75
- minDateInput.value = 'October 1, 1850';
77
+ minDateInput.value = '10/1/1850';
76
78
  minDateInput.dispatchEvent(new Event('blur'));
77
79
 
78
80
  expect(Math.floor(el.minSliderX)).to.eq(SLIDER_WIDTH); // leftmost valid position
79
- expect(el.minSelectedDate).to.eq('1/1/1900'); // leftmost valid date
81
+ // allow date value less than slider range
82
+ expect(el.minSelectedDate).to.eq('10/1/1850');
80
83
 
81
84
  /* -------------------------- maximum (right) slider ------------------------- */
82
85
  expect(el.maxSliderX).to.eq(WIDTH - SLIDER_WIDTH);
@@ -85,20 +88,20 @@ describe('HistogramDateRange', () => {
85
88
  ) as HTMLInputElement;
86
89
 
87
90
  // set valid max date
88
- maxDateInput.value = 'March 12 1975';
89
- maxDateInput.dispatchEvent(new Event('blur'));
90
- await el.updateComplete;
91
+ maxDateInput.value = '3/12/1975';
92
+ maxDateInput.dispatchEvent(pressEnterEvent);
91
93
 
92
94
  expect(Math.floor(el.maxSliderX)).to.eq(121);
93
95
  expect(maxDateInput.value).to.eq('3/12/1975');
94
96
 
95
97
  // attempt to set date later than last item
96
- maxDateInput.value = 'Dec 31 2199';
98
+ maxDateInput.value = '12/31/2199';
97
99
  maxDateInput.dispatchEvent(new Event('blur'));
98
100
  await el.updateComplete;
99
101
 
100
102
  expect(el.maxSliderX).to.eq(WIDTH - SLIDER_WIDTH); // rightmost valid position
101
- expect(maxDateInput.value).to.eq('12/4/2020'); // rightmost valid date
103
+ // allow date value greater than slider range
104
+ expect(maxDateInput.value).to.eq('12/31/2199');
102
105
  });
103
106
 
104
107
  it('handles invalid date inputs', async () => {
@@ -109,7 +112,7 @@ describe('HistogramDateRange', () => {
109
112
  '#date-min'
110
113
  ) as HTMLInputElement;
111
114
 
112
- minDateInput.value = 'May 17, 1961';
115
+ minDateInput.value = '5/17/1961';
113
116
  minDateInput.dispatchEvent(new Event('blur'));
114
117
  await el.updateComplete;
115
118
 
@@ -220,7 +223,7 @@ describe('HistogramDateRange', () => {
220
223
 
221
224
  it("emits a custom event when the element's date range changes", async () => {
222
225
  const el = await createCustomElementInHTMLContainer();
223
- el.updateDelay = 30; // set slightly longer debounce delay for these tests
226
+ el.updateDelay = 30; // set debounce delay of 30ms
224
227
 
225
228
  const minDateInput = el.shadowRoot?.querySelector(
226
229
  '#date-min'
@@ -231,8 +234,9 @@ describe('HistogramDateRange', () => {
231
234
  minDateInput.value = '1955';
232
235
  minDateInput.dispatchEvent(new Event('blur'));
233
236
 
234
- // verify that event is emitted
237
+ // will wait longer than debounce delay
235
238
  const { detail } = await updateEventPromise;
239
+ // verify that event is emitted
236
240
  expect(detail.minDate).to.equal('1/1/1955');
237
241
  expect(detail.maxDate).to.equal('12/4/2020');
238
242
 
@@ -242,7 +246,7 @@ describe('HistogramDateRange', () => {
242
246
  // events are not sent if no change since the last event that was sent
243
247
  minDateInput.value = '1955';
244
248
  minDateInput.dispatchEvent(new Event('blur'));
245
- await aTimeout(60);
249
+ await aTimeout(60); // wait longer than debounce delay
246
250
  expect(eventCount).to.equal(0);
247
251
 
248
252
  const updateEventPromise2 = oneEvent(el, 'histogramDateRangeUpdated');
@@ -269,16 +273,21 @@ describe('HistogramDateRange', () => {
269
273
 
270
274
  it('shows/hides tooltip when hovering over (or pointing at) a bar', async () => {
271
275
  const el = await createCustomElementInHTMLContainer();
272
- const bars = (el.shadowRoot?.querySelectorAll(
276
+ // include a number which will require commas (1,000,000)
277
+ el.bins = [1000000, 1, 100];
278
+ await aTimeout(10);
279
+ const bars = el.shadowRoot?.querySelectorAll(
273
280
  '.bar'
274
- ) as unknown) as SVGRectElement[];
281
+ ) as unknown as SVGRectElement[];
275
282
  const tooltip = el.shadowRoot?.querySelector('#tooltip') as HTMLDivElement;
276
283
  expect(tooltip.innerText).to.eq('');
277
284
 
278
285
  // hover
279
286
  bars[0].dispatchEvent(new PointerEvent('pointerenter'));
280
287
  await el.updateComplete;
281
- expect(tooltip.innerText).to.match(/^33 items\n1\/1\/1900 - 4\/23\/1940/);
288
+ expect(tooltip.innerText).to.match(
289
+ /^1,000,000 items\n1\/1\/1900 - 4\/23\/1940/
290
+ );
282
291
  expect(getComputedStyle(tooltip).display).to.eq('block');
283
292
 
284
293
  // leave
@@ -295,9 +304,9 @@ describe('HistogramDateRange', () => {
295
304
 
296
305
  it('does not show tooltip while dragging', async () => {
297
306
  const el = await createCustomElementInHTMLContainer();
298
- const bars = (el.shadowRoot?.querySelectorAll(
307
+ const bars = el.shadowRoot?.querySelectorAll(
299
308
  '.bar'
300
- ) as unknown) as SVGRectElement[];
309
+ ) as unknown as SVGRectElement[];
301
310
  const tooltip = el.shadowRoot?.querySelector('#tooltip') as HTMLDivElement;
302
311
  expect(tooltip.innerText).to.eq('');
303
312
  const minSlider = el.shadowRoot?.querySelector('#slider-min') as SVGElement;
@@ -363,6 +372,7 @@ describe('HistogramDateRange', () => {
363
372
  )[1]; // click on second bar to the left
364
373
 
365
374
  leftBarToClick.dispatchEvent(new Event('click'));
375
+ await el.updateComplete;
366
376
  expect(el.minSelectedDate).to.eq('1910'); // range was extended to left
367
377
 
368
378
  const rightBarToClick = Array.from(
@@ -373,6 +383,39 @@ describe('HistogramDateRange', () => {
373
383
  expect(el.maxSelectedDate).to.eq('1998'); // range was extended to right
374
384
  });
375
385
 
386
+ it('narrows the selected range when the histogram is clicked inside of the current range', async () => {
387
+ const el = await fixture<HistogramDateRange>(
388
+ html`
389
+ <histogram-date-range
390
+ minDate="1900"
391
+ maxDate="2020"
392
+ minSelectedDate="1900"
393
+ maxSelectedDate="2020"
394
+ bins="[33, 1, 1, 1, 10, 10, 1, 1, 1, 50, 100]"
395
+ >
396
+ </histogram-date-range>
397
+ `
398
+ );
399
+
400
+ ///////////////////////////////////////////////
401
+ // NB: the slider nearest the clicked bar moves
402
+ ///////////////////////////////////////////////
403
+
404
+ const leftBarToClick = Array.from(
405
+ el.shadowRoot?.querySelectorAll('.bar') as NodeList
406
+ )[3]; // click on fourth bar to the left
407
+
408
+ leftBarToClick.dispatchEvent(new Event('click'));
409
+ expect(el.minSelectedDate).to.eq('1932'); // range was extended to the right
410
+
411
+ const rightBarToClick = Array.from(
412
+ el.shadowRoot?.querySelectorAll('.bar') as NodeList
413
+ )[8]; // click on second bar from the right
414
+
415
+ rightBarToClick.dispatchEvent(new Event('click'));
416
+ expect(el.maxSelectedDate).to.eq('1998'); // range was extended to the left
417
+ });
418
+
376
419
  it('handles invalid pre-selected range by defaulting to overall max and min', async () => {
377
420
  const el = await fixture<HistogramDateRange>(
378
421
  html`
@@ -389,12 +432,39 @@ describe('HistogramDateRange', () => {
389
432
  const minDateInput = el.shadowRoot?.querySelector(
390
433
  '#date-min'
391
434
  ) as HTMLInputElement;
435
+ // malformed min date defaults to overall min
392
436
  expect(minDateInput.value).to.eq('1900');
393
437
 
394
438
  const maxDateInput = el.shadowRoot?.querySelector(
395
439
  '#date-max'
396
440
  ) as HTMLInputElement;
397
- expect(maxDateInput.value).to.eq('2020');
441
+ // well-formed max date is allowed
442
+ expect(maxDateInput.value).to.eq('5000');
443
+ });
444
+
445
+ it('handles year values less than 1000 by overriding date format to just display year', async () => {
446
+ const el = await fixture<HistogramDateRange>(
447
+ html`
448
+ <histogram-date-range
449
+ dateFormat="M/D/YYYY"
450
+ minDate="-2000"
451
+ maxDate="2000"
452
+ minSelectedDate="-500"
453
+ maxSelectedDate="500"
454
+ bins="[33, 1, 100]"
455
+ >
456
+ </histogram-date-range>
457
+ `
458
+ );
459
+ const minDateInput = el.shadowRoot?.querySelector(
460
+ '#date-min'
461
+ ) as HTMLInputElement;
462
+ expect(minDateInput.value).to.eq('-500');
463
+
464
+ const maxDateInput = el.shadowRoot?.querySelector(
465
+ '#date-max'
466
+ ) as HTMLInputElement;
467
+ expect(maxDateInput.value).to.eq('500');
398
468
  });
399
469
 
400
470
  it('handles missing data', async () => {
@@ -415,6 +485,20 @@ describe('HistogramDateRange', () => {
415
485
  expect(el.shadowRoot?.innerHTML).to.contain('no data available');
416
486
  });
417
487
 
488
+ it('correctly displays data consisting of a single bin', async () => {
489
+ const el = await fixture<HistogramDateRange>(
490
+ html`
491
+ <histogram-date-range minDate="2020" maxDate="2020" bins="[50]">
492
+ </histogram-date-range>
493
+ `
494
+ );
495
+ const bars = el.shadowRoot?.querySelectorAll(
496
+ '.bar'
497
+ ) as unknown as SVGRectElement[];
498
+ const heights = Array.from(bars).map(b => b.height.baseVal.value);
499
+ expect(heights).to.eql([157]);
500
+ });
501
+
418
502
  it('has a disabled state', async () => {
419
503
  const el = await fixture<HistogramDateRange>(
420
504
  html`
@@ -1,3 +0,0 @@
1
- export const MODE = "production";
2
- export const NODE_ENV = "production";
3
- export const SSR = false;
@@ -1,8 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2017 Google LLC
4
- * SPDX-License-Identifier: BSD-3-Clause
5
- */
6
- var t,i,s,e;const o=globalThis.trustedTypes,l=o?o.createPolicy("lit-html",{createHTML:t=>t}):void 0,n=`lit$${(Math.random()+"").slice(9)}$`,h="?"+n,r=`<${h}>`,u=document,c=(t="")=>u.createComment(t),d=t=>null===t||"object"!=typeof t&&"function"!=typeof t,v=Array.isArray,a=t=>{var i;return v(t)||"function"==typeof(null===(i=t)||void 0===i?void 0:i[Symbol.iterator])},f=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,_=/-->/g,m=/>/g,p=/>|[ \n \r](?:([^\s"'>=/]+)([ \n \r]*=[ \n \r]*(?:[^ \n \r"'`<>=]|("|')|))|$)/g,$=/'/g,g=/"/g,y=/^(?:script|style|textarea)$/i,b=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),T=b(1),x=b(2),w=Symbol.for("lit-noChange"),A=Symbol.for("lit-nothing"),P=new WeakMap,V=(t,i,s)=>{var e,o;const l=null!==(e=null==s?void 0:s.renderBefore)&&void 0!==e?e:i;let n=l._$litPart$;if(void 0===n){const t=null!==(o=null==s?void 0:s.renderBefore)&&void 0!==o?o:null;l._$litPart$=n=new C(i.insertBefore(c(),t),t,void 0,s);}return n.I(t),n},E=u.createTreeWalker(u,129,null,!1),M=(t,i)=>{const s=t.length-1,e=[];let o,h=2===i?"<svg>":"",u=f;for(let i=0;i<s;i++){const s=t[i];let l,c,d=-1,v=0;for(;v<s.length&&(u.lastIndex=v,c=u.exec(s),null!==c);)v=u.lastIndex,u===f?"!--"===c[1]?u=_:void 0!==c[1]?u=m:void 0!==c[2]?(y.test(c[2])&&(o=RegExp("</"+c[2],"g")),u=p):void 0!==c[3]&&(u=p):u===p?">"===c[0]?(u=null!=o?o:f,d=-1):void 0===c[1]?d=-2:(d=u.lastIndex-c[2].length,l=c[1],u=void 0===c[3]?p:'"'===c[3]?g:$):u===g||u===$?u=p:u===_||u===m?u=f:(u=p,o=void 0);const a=u===p&&t[i+1].startsWith("/>")?" ":"";h+=u===f?s+r:d>=0?(e.push(l),s.slice(0,d)+"$lit$"+s.slice(d)+n+a):s+n+(-2===d?(e.push(void 0),i):a);}const c=h+(t[s]||"<?>")+(2===i?"</svg>":"");return [void 0!==l?l.createHTML(c):c,e]};class N{constructor({strings:t,_$litType$:i},s){let e;this.parts=[];let l=0,r=0;const u=t.length-1,d=this.parts,[v,a]=M(t,i);if(this.el=N.createElement(v,s),E.currentNode=this.el.content,2===i){const t=this.el.content,i=t.firstChild;i.remove(),t.append(...i.childNodes);}for(;null!==(e=E.nextNode())&&d.length<u;){if(1===e.nodeType){if(e.hasAttributes()){const t=[];for(const i of e.getAttributeNames())if(i.endsWith("$lit$")||i.startsWith(n)){const s=a[r++];if(t.push(i),void 0!==s){const t=e.getAttribute(s.toLowerCase()+"$lit$").split(n),i=/([.?@])?(.*)/.exec(s);d.push({type:1,index:l,name:i[2],strings:t,ctor:"."===i[1]?I:"?"===i[1]?L:"@"===i[1]?R:H});}else d.push({type:6,index:l});}for(const i of t)e.removeAttribute(i);}if(y.test(e.tagName)){const t=e.textContent.split(n),i=t.length-1;if(i>0){e.textContent=o?o.emptyScript:"";for(let s=0;s<i;s++)e.append(t[s],c()),E.nextNode(),d.push({type:2,index:++l});e.append(t[i],c());}}}else if(8===e.nodeType)if(e.data===h)d.push({type:2,index:l});else {let t=-1;for(;-1!==(t=e.data.indexOf(n,t+1));)d.push({type:7,index:l}),t+=n.length-1;}l++;}}static createElement(t,i){const s=u.createElement("template");return s.innerHTML=t,s}}function S(t,i,s=t,e){var o,l,n,h;if(i===w)return i;let r=void 0!==e?null===(o=s.Σi)||void 0===o?void 0:o[e]:s.Σo;const u=d(i)?void 0:i._$litDirective$;return (null==r?void 0:r.constructor)!==u&&(null===(l=null==r?void 0:r.O)||void 0===l||l.call(r,!1),void 0===u?r=void 0:(r=new u(t),r.T(t,s,e)),void 0!==e?(null!==(n=(h=s).Σi)&&void 0!==n?n:h.Σi=[])[e]=r:s.Σo=r),void 0!==r&&(i=S(t,r.S(t,i.values),r,e)),i}class k{constructor(t,i){this.l=[],this.N=void 0,this.D=t,this.M=i;}u(t){var i;const{el:{content:s},parts:e}=this.D,o=(null!==(i=null==t?void 0:t.creationScope)&&void 0!==i?i:u).importNode(s,!0);E.currentNode=o;let l=E.nextNode(),n=0,h=0,r=e[0];for(;void 0!==r;){if(n===r.index){let i;2===r.type?i=new C(l,l.nextSibling,this,t):1===r.type?i=new r.ctor(l,r.name,r.strings,this,t):6===r.type&&(i=new z(l,this,t)),this.l.push(i),r=e[++h];}n!==(null==r?void 0:r.index)&&(l=E.nextNode(),n++);}return o}v(t){let i=0;for(const s of this.l)void 0!==s&&(void 0!==s.strings?(s.I(t,s,i),i+=s.strings.length-2):s.I(t[i])),i++;}}class C{constructor(t,i,s,e){this.type=2,this.N=void 0,this.A=t,this.B=i,this.M=s,this.options=e;}setConnected(t){var i;null===(i=this.P)||void 0===i||i.call(this,t);}get parentNode(){return this.A.parentNode}get startNode(){return this.A}get endNode(){return this.B}I(t,i=this){t=S(this,t,i),d(t)?t===A||null==t||""===t?(this.H!==A&&this.R(),this.H=A):t!==this.H&&t!==w&&this.m(t):void 0!==t._$litType$?this._(t):void 0!==t.nodeType?this.$(t):a(t)?this.g(t):this.m(t);}k(t,i=this.B){return this.A.parentNode.insertBefore(t,i)}$(t){this.H!==t&&(this.R(),this.H=this.k(t));}m(t){const i=this.A.nextSibling;null!==i&&3===i.nodeType&&(null===this.B?null===i.nextSibling:i===this.B.previousSibling)?i.data=t:this.$(u.createTextNode(t)),this.H=t;}_(t){var i;const{values:s,_$litType$:e}=t,o="number"==typeof e?this.C(t):(void 0===e.el&&(e.el=N.createElement(e.h,this.options)),e);if((null===(i=this.H)||void 0===i?void 0:i.D)===o)this.H.v(s);else {const t=new k(o,this),i=t.u(this.options);t.v(s),this.$(i),this.H=t;}}C(t){let i=P.get(t.strings);return void 0===i&&P.set(t.strings,i=new N(t)),i}g(t){v(this.H)||(this.H=[],this.R());const i=this.H;let s,e=0;for(const o of t)e===i.length?i.push(s=new C(this.k(c()),this.k(c()),this,this.options)):s=i[e],s.I(o),e++;e<i.length&&(this.R(s&&s.B.nextSibling,e),i.length=e);}R(t=this.A.nextSibling,i){var s;for(null===(s=this.P)||void 0===s||s.call(this,!1,!0,i);t&&t!==this.B;){const i=t.nextSibling;t.remove(),t=i;}}}class H{constructor(t,i,s,e,o){this.type=1,this.H=A,this.N=void 0,this.V=void 0,this.element=t,this.name=i,this.M=e,this.options=o,s.length>2||""!==s[0]||""!==s[1]?(this.H=Array(s.length-1).fill(A),this.strings=s):this.H=A;}get tagName(){return this.element.tagName}I(t,i=this,s,e){const o=this.strings;let l=!1;if(void 0===o)t=S(this,t,i,0),l=!d(t)||t!==this.H&&t!==w,l&&(this.H=t);else {const e=t;let n,h;for(t=o[0],n=0;n<o.length-1;n++)h=S(this,e[s+n],i,n),h===w&&(h=this.H[n]),l||(l=!d(h)||h!==this.H[n]),h===A?t=A:t!==A&&(t+=(null!=h?h:"")+o[n+1]),this.H[n]=h;}l&&!e&&this.W(t);}W(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,null!=t?t:"");}}class I extends H{constructor(){super(...arguments),this.type=3;}W(t){this.element[this.name]=t===A?void 0:t;}}class L extends H{constructor(){super(...arguments),this.type=4;}W(t){t&&t!==A?this.element.setAttribute(this.name,""):this.element.removeAttribute(this.name);}}class R extends H{constructor(){super(...arguments),this.type=5;}I(t,i=this){var s;if((t=null!==(s=S(this,t,i,0))&&void 0!==s?s:A)===w)return;const e=this.H,o=t===A&&e!==A||t.capture!==e.capture||t.once!==e.once||t.passive!==e.passive,l=t!==A&&(e===A||o);o&&this.element.removeEventListener(this.name,this,e),l&&this.element.addEventListener(this.name,this,t),this.H=t;}handleEvent(t){var i,s;"function"==typeof this.H?this.H.call(null!==(s=null===(i=this.options)||void 0===i?void 0:i.host)&&void 0!==s?s:this.element,t):this.H.handleEvent(t);}}class z{constructor(t,i,s){this.element=t,this.type=6,this.N=void 0,this.V=void 0,this.M=i,this.options=s;}I(t){S(this,t);}}null===(i=(t=globalThis).litHtmlPlatformSupport)||void 0===i||i.call(t,N,C),(null!==(s=(e=globalThis).litHtmlVersions)&&void 0!==s?s:e.litHtmlVersions=[]).push("2.0.0-rc.3");
7
-
8
- export { A, T, V, w, x };
package/types/static.d.ts DELETED
@@ -1,4 +0,0 @@
1
- declare module '*.svg' {
2
- const ref: string;
3
- export default ref;
4
- }