@oslokommune/punkt-elements 13.4.2 → 13.5.1

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/calendar-32W9p9uc.cjs +115 -0
  3. package/dist/{calendar-DevQhOup.js → calendar-CJSxvwAq.js} +353 -340
  4. package/dist/{card-Dtw26f7i.js → card-BDz4RWxK.js} +1 -1
  5. package/dist/{card-BUITGoqX.cjs → card-DBlFf1ry.cjs} +1 -1
  6. package/dist/{datepicker-CYOn3tRm.js → datepicker-BJKJBoy_.js} +102 -59
  7. package/dist/datepicker-CmTrG5GE.cjs +164 -0
  8. package/dist/{heading-D6jXE_Mz.js → heading-Bdh9absf.js} +22 -22
  9. package/dist/heading-CNycsyMj.cjs +1 -0
  10. package/dist/index.d.ts +6 -2
  11. package/dist/pkt-calendar.cjs +1 -1
  12. package/dist/pkt-calendar.js +1 -1
  13. package/dist/pkt-card.cjs +1 -1
  14. package/dist/pkt-card.js +1 -1
  15. package/dist/pkt-datepicker.cjs +1 -1
  16. package/dist/pkt-datepicker.js +1 -1
  17. package/dist/pkt-heading.cjs +1 -1
  18. package/dist/pkt-heading.js +1 -1
  19. package/dist/pkt-index.cjs +1 -1
  20. package/dist/pkt-index.js +5 -5
  21. package/package.json +3 -3
  22. package/src/components/calendar/calendar.accessibility.test.ts +111 -0
  23. package/src/components/calendar/calendar.constraints.test.ts +110 -0
  24. package/src/components/calendar/calendar.core.test.ts +367 -0
  25. package/src/components/calendar/calendar.interaction.test.ts +139 -0
  26. package/src/components/calendar/calendar.selection.test.ts +273 -0
  27. package/src/components/calendar/calendar.ts +74 -42
  28. package/src/components/card/card.test.ts +19 -5
  29. package/src/components/consent/consent.test.ts +436 -0
  30. package/src/components/datepicker/datepicker.accessibility.test.ts +193 -0
  31. package/src/components/datepicker/datepicker.core.test.ts +322 -0
  32. package/src/components/datepicker/datepicker.input.test.ts +268 -0
  33. package/src/components/datepicker/datepicker.selection.test.ts +286 -0
  34. package/src/components/datepicker/datepicker.ts +121 -19
  35. package/src/components/datepicker/datepicker.validation.test.ts +176 -0
  36. package/src/components/heading/heading.test.ts +458 -0
  37. package/src/components/heading/heading.ts +3 -0
  38. package/src/components/helptext/helptext.test.ts +474 -0
  39. package/dist/calendar-BZe2D4Sr.cjs +0 -108
  40. package/dist/datepicker-B9rhz_AF.cjs +0 -154
  41. package/dist/heading-BRE_iFtR.cjs +0 -1
@@ -1,10 +1,10 @@
1
- import { b as p, x as u, n as d, a as o } from "./element-CgEWt74-.js";
2
- var g = Object.defineProperty, c = Object.getOwnPropertyDescriptor, l = (t, i, e, r) => {
3
- for (var s = r > 1 ? void 0 : r ? c(i, e) : i, n = t.length - 1, h; n >= 0; n--)
4
- (h = t[n]) && (s = (r ? h(i, e, s) : h(s)) || s);
5
- return r && s && g(i, e, s), s;
1
+ import { b as p, x as u, n, a as o } from "./element-CgEWt74-.js";
2
+ var g = Object.defineProperty, f = Object.getOwnPropertyDescriptor, a = (t, i, e, d) => {
3
+ for (var s = d > 1 ? void 0 : d ? f(i, e) : i, r = t.length - 1, h; r >= 0; r--)
4
+ (h = t[r]) && (s = (d ? h(i, e, s) : h(s)) || s);
5
+ return d && s && g(i, e, s), s;
6
6
  };
7
- let a = class extends p {
7
+ let l = class extends p {
8
8
  constructor() {
9
9
  super(...arguments), this.size = "medium", this.level = 2, this.visuallyHidden = !1, this.align = "start";
10
10
  }
@@ -12,7 +12,7 @@ let a = class extends p {
12
12
  super.connectedCallback(), this.setAttribute("role", "heading"), this.setAttribute("aria-level", String(this.level)), this.updateHostClasses();
13
13
  }
14
14
  attributeChangedCallback(t, i, e) {
15
- super.attributeChangedCallback(t, i, e), t === "level" && e && this.setLevel(Number(e)), (t === "size" || t === "visuallyHidden" || t === "align") && this.updateHostClasses();
15
+ super.attributeChangedCallback(t, i, e), t === "level" && e && this.setLevel(Number(e)), t === "visuallyHidden" && (this.visuallyHidden = e !== null && e !== "false"), (t === "size" || t === "visuallyHidden" || t === "align") && this.updateHostClasses();
16
16
  }
17
17
  updated(t) {
18
18
  super.updated(t), t.has("level") && this.setLevel(this.level), (t.has("size") || t.has("visuallyHidden") || t.has("align")) && this.updateHostClasses();
@@ -38,21 +38,21 @@ let a = class extends p {
38
38
  return u`<slot></slot>`;
39
39
  }
40
40
  };
41
- l([
42
- d({ type: String, reflect: !0 })
43
- ], a.prototype, "size", 2);
44
- l([
45
- d({ type: Number, reflect: !0 })
46
- ], a.prototype, "level", 2);
47
- l([
48
- d({ type: Boolean, reflect: !0 })
49
- ], a.prototype, "visuallyHidden", 2);
50
- l([
51
- d({ type: String, reflect: !0 })
52
- ], a.prototype, "align", 2);
53
- a = l([
41
+ a([
42
+ n({ type: String, reflect: !0 })
43
+ ], l.prototype, "size", 2);
44
+ a([
45
+ n({ type: Number, reflect: !0 })
46
+ ], l.prototype, "level", 2);
47
+ a([
48
+ n({ type: Boolean, reflect: !0 })
49
+ ], l.prototype, "visuallyHidden", 2);
50
+ a([
51
+ n({ type: String, reflect: !0 })
52
+ ], l.prototype, "align", 2);
53
+ l = a([
54
54
  o("pkt-heading")
55
- ], a);
55
+ ], l);
56
56
  export {
57
- a as P
57
+ l as P
58
58
  };
@@ -0,0 +1 @@
1
+ "use strict";const i=require("./element-6DBpyGQm.cjs");var h=Object.defineProperty,p=Object.getOwnPropertyDescriptor,l=(n,t,a,e)=>{for(var s=e>1?void 0:e?p(t,a):t,d=n.length-1,r;d>=0;d--)(r=n[d])&&(s=(e?r(t,a,s):r(s))||s);return e&&s&&h(t,a,s),s};exports.PktHeading=class extends i.PktShadowElement{constructor(){super(...arguments),this.size="medium",this.level=2,this.visuallyHidden=!1,this.align="start"}connectedCallback(){super.connectedCallback(),this.setAttribute("role","heading"),this.setAttribute("aria-level",String(this.level)),this.updateHostClasses()}attributeChangedCallback(t,a,e){super.attributeChangedCallback(t,a,e),t==="level"&&e&&this.setLevel(Number(e)),t==="visuallyHidden"&&(this.visuallyHidden=e!==null&&e!=="false"),(t==="size"||t==="visuallyHidden"||t==="align")&&this.updateHostClasses()}updated(t){super.updated(t),t.has("level")&&this.setLevel(this.level),(t.has("size")||t.has("visuallyHidden")||t.has("align"))&&this.updateHostClasses()}setLevel(t){t>=1&&t<=6?(this.level=t,this.setAttribute("aria-level",String(t))):console.warn(`Invalid heading level: ${t}. Must be between 1 and 6.`)}updateHostClasses(){this.classList.remove("pkt-heading","pkt-heading--xsmall","pkt-heading--small","pkt-heading--medium","pkt-heading--large","pkt-heading--xlarge","pkt-sr-only","pkt-heading--start","pkt-heading--center","pkt-heading--end"),this.classList.add("pkt-heading"),this.size&&this.classList.add(`pkt-heading--${this.size}`),this.visuallyHidden&&this.classList.add("pkt-sr-only"),this.align&&this.classList.add(`pkt-heading--${this.align}`)}render(){return i.x`<slot></slot>`}};l([i.n({type:String,reflect:!0})],exports.PktHeading.prototype,"size",2);l([i.n({type:Number,reflect:!0})],exports.PktHeading.prototype,"level",2);l([i.n({type:Boolean,reflect:!0})],exports.PktHeading.prototype,"visuallyHidden",2);l([i.n({type:String,reflect:!0})],exports.PktHeading.prototype,"align",2);exports.PktHeading=l([i.t("pkt-heading")],exports.PktHeading);
package/dist/index.d.ts CHANGED
@@ -456,7 +456,6 @@ export declare class PktCalendar extends PktElement {
456
456
  isNextMonthAllowed(): boolean;
457
457
  private nextMonth;
458
458
  private changeMonth;
459
- private isInRange;
460
459
  private isRangeAllowed;
461
460
  private emptySelected;
462
461
  addToSelected(selectedDate: Date): void;
@@ -661,7 +660,9 @@ export declare class PktDatepicker extends PktInputElement {
661
660
  /**
662
661
  * Element attributes and properties
663
662
  */
664
- value: string | string[];
663
+ private _valueProperty;
664
+ get value(): string;
665
+ set value(newValue: string | string[]);
665
666
  _value: string[];
666
667
  label: string;
667
668
  dateformat: string;
@@ -686,6 +687,8 @@ export declare class PktDatepicker extends PktInputElement {
686
687
  constructor();
687
688
  connectedCallback(): Promise<void>;
688
689
  disconnectedCallback(): void;
690
+ onInput(): void;
691
+ valueChanged(newValue: string | null, oldValue: string | null): void;
689
692
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
690
693
  updated(changedProperties: PropertyValues): void;
691
694
  /**
@@ -715,6 +718,7 @@ export declare class PktDatepicker extends PktInputElement {
715
718
  showCalendar(): Promise<void>;
716
719
  hideCalendar(): void;
717
720
  toggleCalendar(e: Event): Promise<void>;
721
+ clearInputValue(): void;
718
722
  }
719
723
 
720
724
  /**
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./calendar-BZe2D4Sr.cjs"),t=e.PktCalendar;Object.defineProperty(exports,"PktCalendar",{enumerable:!0,get:()=>e.PktCalendar});exports.default=t;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./calendar-32W9p9uc.cjs"),t=e.PktCalendar;Object.defineProperty(exports,"PktCalendar",{enumerable:!0,get:()=>e.PktCalendar});exports.default=t;
@@ -1,4 +1,4 @@
1
- import { P as a } from "./calendar-DevQhOup.js";
1
+ import { P as a } from "./calendar-CJSxvwAq.js";
2
2
  const r = a;
3
3
  export {
4
4
  a as PktCalendar,
package/dist/pkt-card.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./card-BUITGoqX.cjs"),t=e.PktCard;Object.defineProperty(exports,"PktCard",{enumerable:!0,get:()=>e.PktCard});exports.default=t;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./card-DBlFf1ry.cjs"),t=e.PktCard;Object.defineProperty(exports,"PktCard",{enumerable:!0,get:()=>e.PktCard});exports.default=t;
package/dist/pkt-card.js CHANGED
@@ -1,4 +1,4 @@
1
- import { P as a } from "./card-Dtw26f7i.js";
1
+ import { P as a } from "./card-BDz4RWxK.js";
2
2
  const r = a;
3
3
  export {
4
4
  a as PktCard,
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./datepicker-B9rhz_AF.cjs"),t=e.PktDatepicker;Object.defineProperty(exports,"PktDatepicker",{enumerable:!0,get:()=>e.PktDatepicker});exports.default=t;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./datepicker-CmTrG5GE.cjs"),t=e.PktDatepicker;Object.defineProperty(exports,"PktDatepicker",{enumerable:!0,get:()=>e.PktDatepicker});exports.default=t;
@@ -1,4 +1,4 @@
1
- import { P as t } from "./datepicker-CYOn3tRm.js";
1
+ import { P as t } from "./datepicker-BJKJBoy_.js";
2
2
  const a = t;
3
3
  export {
4
4
  t as PktDatepicker,
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./heading-BRE_iFtR.cjs"),t=e.PktHeading;Object.defineProperty(exports,"PktHeading",{enumerable:!0,get:()=>e.PktHeading});exports.default=t;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./heading-CNycsyMj.cjs"),t=e.PktHeading;Object.defineProperty(exports,"PktHeading",{enumerable:!0,get:()=>e.PktHeading});exports.default=t;
@@ -1,4 +1,4 @@
1
- import { P as a } from "./heading-D6jXE_Mz.js";
1
+ import { P as a } from "./heading-Bdh9absf.js";
2
2
  const e = a;
3
3
  export {
4
4
  a as PktHeading,
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("./alert-DQNBDKjT.cjs"),l=require("./accordionitem-Csh7iSVG.cjs"),d=require("./backlink-JbBNi3qg.cjs"),b=require("./button-B8rdtaHB.cjs"),k=require("./calendar-BZe2D4Sr.cjs"),m=require("./card-BUITGoqX.cjs"),g=require("./combobox-DjO0RMUB.cjs"),h=require("./consent-hYeFWNFr.cjs"),f=require("./checkbox-Gn7Wtk9h.cjs"),t=require("./element-6DBpyGQm.cjs"),y=require("./pkt-slot-controller-BzddBp7z.cjs"),s=require("./ref-iJtiv3o2.cjs"),O=require("./class-map-BBG2gMX4.cjs"),j=require("./datepicker-B9rhz_AF.cjs"),q=require("./helptext-CzQX6YVE.cjs"),x=require("./heading-BRE_iFtR.cjs"),C=require("./icon-B_ryAy4Q.cjs"),v=require("./input-wrapper-CZ-a00V7.cjs"),S=require("./link-Cjl0xwSq.cjs"),$=require("./linkcard-BlMhPNry.cjs"),L=require("./loader-CHPxY9c6.cjs"),_=require("./messagebox-CqUBJs_D.cjs"),A=require("./modal-CRtxhCaP.cjs"),B=require("./progressbar-DhMBXkww.cjs"),p=require("./radiobutton-CdT6v1oq.cjs"),T=require("./tag-Bbs0U_Au.cjs"),I=require("./textarea-CPXsMFUq.cjs"),M=require("./textinput-aNI5kibM.cjs"),R=require("./select-Dkl0KhGW.cjs");var H=Object.defineProperty,w=Object.getOwnPropertyDescriptor,o=(a,e,r,i)=>{for(var n=i>1?void 0:i?w(e,r):e,u=a.length-1,c;u>=0;u--)(c=a[u])&&(n=(i?c(e,r,n):c(n))||n);return i&&n&&H(e,r,n),n};exports.PktComponent=class extends t.PktElement{constructor(){super(),this.string="",this.strings=[],this.darkmode=!1,this._list=[],this.defaultSlot=s.e(),this.namedSlot=s.e(),this.slotController=new y.PktSlotController(this,this.defaultSlot,this.namedSlot)}connectedCallback(){this.strings.length&&this.strings.forEach(e=>{this._list.push(e.toUpperCase())}),super.connectedCallback()}render(){const e={"pkt-component":!0,"pkt-component--has-list":this.strings.length>0,"pkt-darkmode":this.darkmode};return t.x`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const P=require("./alert-DQNBDKjT.cjs"),l=require("./accordionitem-Csh7iSVG.cjs"),d=require("./backlink-JbBNi3qg.cjs"),b=require("./button-B8rdtaHB.cjs"),k=require("./calendar-32W9p9uc.cjs"),m=require("./card-DBlFf1ry.cjs"),g=require("./combobox-DjO0RMUB.cjs"),h=require("./consent-hYeFWNFr.cjs"),f=require("./checkbox-Gn7Wtk9h.cjs"),t=require("./element-6DBpyGQm.cjs"),y=require("./pkt-slot-controller-BzddBp7z.cjs"),s=require("./ref-iJtiv3o2.cjs"),O=require("./class-map-BBG2gMX4.cjs"),j=require("./datepicker-CmTrG5GE.cjs"),q=require("./helptext-CzQX6YVE.cjs"),x=require("./heading-CNycsyMj.cjs"),C=require("./icon-B_ryAy4Q.cjs"),v=require("./input-wrapper-CZ-a00V7.cjs"),S=require("./link-Cjl0xwSq.cjs"),$=require("./linkcard-BlMhPNry.cjs"),L=require("./loader-CHPxY9c6.cjs"),_=require("./messagebox-CqUBJs_D.cjs"),A=require("./modal-CRtxhCaP.cjs"),B=require("./progressbar-DhMBXkww.cjs"),p=require("./radiobutton-CdT6v1oq.cjs"),T=require("./tag-Bbs0U_Au.cjs"),I=require("./textarea-CPXsMFUq.cjs"),M=require("./textinput-aNI5kibM.cjs"),R=require("./select-Dkl0KhGW.cjs");var H=Object.defineProperty,w=Object.getOwnPropertyDescriptor,o=(a,e,r,i)=>{for(var n=i>1?void 0:i?w(e,r):e,u=a.length-1,c;u>=0;u--)(c=a[u])&&(n=(i?c(e,r,n):c(n))||n);return i&&n&&H(e,r,n),n};exports.PktComponent=class extends t.PktElement{constructor(){super(),this.string="",this.strings=[],this.darkmode=!1,this._list=[],this.defaultSlot=s.e(),this.namedSlot=s.e(),this.slotController=new y.PktSlotController(this,this.defaultSlot,this.namedSlot)}connectedCallback(){this.strings.length&&this.strings.forEach(e=>{this._list.push(e.toUpperCase())}),super.connectedCallback()}render(){const e={"pkt-component":!0,"pkt-component--has-list":this.strings.length>0,"pkt-darkmode":this.darkmode};return t.x`
2
2
  <div class="${O.e(e)}">
3
3
  <h1 class="pkt-txt-28">${this.string}</h1>
4
4
 
package/dist/pkt-index.js CHANGED
@@ -2,9 +2,9 @@ import { P as A } from "./alert-B07oUpkq.js";
2
2
  import { P as B, a as E } from "./accordionitem-C9T3nlM0.js";
3
3
  import { P as O } from "./backlink-C2jbzu0U.js";
4
4
  import { P as T } from "./button-DhispFOY.js";
5
- import { c as f } from "./calendar-DevQhOup.js";
6
- import { P as D } from "./calendar-DevQhOup.js";
7
- import { P as G } from "./card-Dtw26f7i.js";
5
+ import { c as f } from "./calendar-CJSxvwAq.js";
6
+ import { P as D } from "./calendar-CJSxvwAq.js";
7
+ import { P as G } from "./card-BDz4RWxK.js";
8
8
  import { P as K } from "./combobox-yE4aYhTi.js";
9
9
  import { P as U } from "./consent-BpcQFvbi.js";
10
10
  import { P as q } from "./checkbox-ym7z6cpt.js";
@@ -12,9 +12,9 @@ import { P as k, t as h, x as P, n, a as c } from "./element-CgEWt74-.js";
12
12
  import { P as x } from "./pkt-slot-controller-BPGj-LC5.js";
13
13
  import { e as m, n as d } from "./ref-BBYSqgeW.js";
14
14
  import { e as u } from "./class-map-BpTj9gtz.js";
15
- import { P as F } from "./datepicker-CYOn3tRm.js";
15
+ import { P as F } from "./datepicker-BJKJBoy_.js";
16
16
  import { P as Q } from "./helptext-B7eI0iBQ.js";
17
- import { P as X } from "./heading-D6jXE_Mz.js";
17
+ import { P as X } from "./heading-Bdh9absf.js";
18
18
  import { P as Z } from "./icon-CC1js8eR.js";
19
19
  import { P as et } from "./input-wrapper-Dr__Sxql.js";
20
20
  import { P as ot } from "./link-AIyVfcyH.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oslokommune/punkt-elements",
3
- "version": "13.4.2",
3
+ "version": "13.5.1",
4
4
  "description": "Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo",
5
5
  "homepage": "https://punkt.oslo.kommune.no",
6
6
  "author": "Team Designsystem, Oslo Origo",
@@ -37,7 +37,7 @@
37
37
  "devDependencies": {
38
38
  "@babel/preset-env": "^7.28.3",
39
39
  "@oslokommune/punkt-assets": "^13.3.1",
40
- "@oslokommune/punkt-css": "^13.3.1",
40
+ "@oslokommune/punkt-css": "^13.5.0",
41
41
  "@testing-library/jest-dom": "^6.6.3",
42
42
  "jest": "^29.7.0",
43
43
  "jest-axe": "^9.0.0",
@@ -69,5 +69,5 @@
69
69
  "url": "https://github.com/oslokommune/punkt/issues"
70
70
  },
71
71
  "license": "MIT",
72
- "gitHead": "b8dc1a2d10d756fb0fc6babb0f3b03b4d8eea95a"
72
+ "gitHead": "5892d94f903527e3e228915d86653bfbfdf209c8"
73
73
  }
@@ -0,0 +1,111 @@
1
+ import '@testing-library/jest-dom'
2
+ import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { fireEvent } from '@testing-library/dom'
4
+
5
+ expect.extend(toHaveNoViolations)
6
+
7
+ import './calendar'
8
+ import { PktCalendar } from './calendar'
9
+
10
+ const waitForCustomElements = async () => {
11
+ await customElements.whenDefined('pkt-calendar')
12
+ }
13
+
14
+ // Helper function to create calendar markup
15
+ const createCalendar = async (calendarProps = '') => {
16
+ const container = document.createElement('div')
17
+ container.innerHTML = `
18
+ <pkt-calendar ${calendarProps}></pkt-calendar>
19
+ `
20
+ document.body.appendChild(container)
21
+ await waitForCustomElements()
22
+ return container
23
+ }
24
+
25
+ // Cleanup after each test
26
+ afterEach(() => {
27
+ document.body.innerHTML = ''
28
+ })
29
+
30
+ describe('PktCalendar', () => {
31
+ describe('Accessibility', () => {
32
+ test('has no accessibility violations', async () => {
33
+ const container = await createCalendar('withcontrols weeknumbers')
34
+
35
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
36
+ await calendar.updateComplete
37
+
38
+ const results = await axe(calendar)
39
+ expect(results).toHaveNoViolations()
40
+ })
41
+
42
+ test('has proper ARIA attributes', async () => {
43
+ const container = await createCalendar('withcontrols')
44
+
45
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
46
+ await calendar.updateComplete
47
+
48
+ const calendarTable = calendar.querySelector('.pkt-calendar__body')
49
+ expect(calendarTable).toHaveAttribute('role', 'grid')
50
+
51
+ const dateButtons = calendar.querySelectorAll('.pkt-calendar__date')
52
+ dateButtons.forEach((button) => {
53
+ expect(button).toHaveAttribute('aria-pressed')
54
+ expect(button).toHaveAttribute('tabindex')
55
+ })
56
+ })
57
+
58
+ test('navigation buttons have proper labels', async () => {
59
+ const container = await createCalendar('withcontrols')
60
+
61
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
62
+ await calendar.updateComplete
63
+
64
+ const prevButton = calendar.querySelector('.pkt-calendar__prev-month')
65
+ const nextButton = calendar.querySelector('.pkt-calendar__next-month')
66
+
67
+ expect(prevButton).toHaveAttribute('aria-label')
68
+ expect(nextButton).toHaveAttribute('aria-label')
69
+ })
70
+
71
+ test('date buttons have proper accessible names', async () => {
72
+ const container = await createCalendar()
73
+
74
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
75
+ await calendar.updateComplete
76
+
77
+ const dateButtons = calendar.querySelectorAll('.pkt-calendar__date')
78
+ dateButtons.forEach((button) => {
79
+ expect(button).toHaveAttribute('aria-label')
80
+ expect(button.getAttribute('aria-label')).toBeTruthy()
81
+ })
82
+ })
83
+
84
+ test('selected dates have proper ARIA state', async () => {
85
+ const container = await createCalendar()
86
+
87
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
88
+ await calendar.updateComplete
89
+
90
+ const firstDate = calendar.querySelector(
91
+ '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
92
+ )
93
+ fireEvent.click(firstDate!)
94
+ await calendar.updateComplete
95
+
96
+ expect(firstDate).toHaveAttribute('aria-pressed', 'true')
97
+ })
98
+
99
+ test('disabled dates have proper ARIA state', async () => {
100
+ const container = await createCalendar('excludeweekdays="0,6"')
101
+
102
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
103
+ await calendar.updateComplete
104
+
105
+ const disabledDates = calendar.querySelectorAll('.pkt-calendar__date--disabled')
106
+ disabledDates.forEach((date) => {
107
+ expect(date).toHaveAttribute('disabled')
108
+ })
109
+ })
110
+ })
111
+ })
@@ -0,0 +1,110 @@
1
+ import '@testing-library/jest-dom'
2
+ import { parseISODateString } from '@/utils/dateutils'
3
+
4
+ import './calendar'
5
+ import { PktCalendar } from './calendar'
6
+
7
+ const waitForCustomElements = async () => {
8
+ await customElements.whenDefined('pkt-calendar')
9
+ }
10
+
11
+ // Helper function to create calendar markup
12
+ const createCalendar = async (calendarProps = '') => {
13
+ const container = document.createElement('div')
14
+ container.innerHTML = `
15
+ <pkt-calendar ${calendarProps}></pkt-calendar>
16
+ `
17
+ document.body.appendChild(container)
18
+ await waitForCustomElements()
19
+ return container
20
+ }
21
+
22
+ // Cleanup after each test
23
+ afterEach(() => {
24
+ document.body.innerHTML = ''
25
+ })
26
+
27
+ describe('PktCalendar', () => {
28
+ describe('Date range functionality', () => {
29
+ test('handles earliest date property correctly', async () => {
30
+ const earliestDate = '2024-01-15'
31
+ // Set current month to January 2024 so we can see disabled dates before the 15th
32
+ const container = await createCalendar(`earliest="${earliestDate}" currentmonth="2024-01-01"`)
33
+
34
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
35
+ await calendar.updateComplete
36
+
37
+ expect(calendar.earliest).toBe(earliestDate)
38
+
39
+ // Check that dates before earliest are disabled (dates 1-14 should be disabled)
40
+ const disabledDates = calendar.querySelectorAll('.pkt-calendar__date--disabled')
41
+ expect(disabledDates.length).toBeGreaterThan(0)
42
+ })
43
+
44
+ test('handles latest date property correctly', async () => {
45
+ const latestDate = '2024-12-15'
46
+ const container = await createCalendar(`latest="${latestDate}"`)
47
+
48
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
49
+ await calendar.updateComplete
50
+
51
+ expect(calendar.latest).toBe(latestDate)
52
+ })
53
+
54
+ test('restricts selectable dates between earliest and latest', async () => {
55
+ // Set current month to June 2024 so we can see the date range restrictions
56
+ const container = await createCalendar(
57
+ 'earliest="2024-06-10" latest="2024-06-20" currentmonth="2024-06-01"',
58
+ )
59
+
60
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
61
+ await calendar.updateComplete
62
+
63
+ const enabledDates = calendar.querySelectorAll(
64
+ '.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
65
+ )
66
+ const disabledDates = calendar.querySelectorAll('.pkt-calendar__date--disabled')
67
+
68
+ expect(enabledDates.length).toBeGreaterThan(0)
69
+ expect(disabledDates.length).toBeGreaterThan(0)
70
+ })
71
+ })
72
+
73
+ describe('Date exclusion functionality', () => {
74
+ test('excludes specific dates correctly', async () => {
75
+ const excludedDates = '2024-06-15,2024-06-20'
76
+ const container = await createCalendar(`excludedates="${excludedDates}"`)
77
+
78
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
79
+ await calendar.updateComplete
80
+
81
+ expect(calendar.excludedates).toHaveLength(2)
82
+ expect(calendar.excludedates[0]).toEqual(parseISODateString('2024-06-15'))
83
+ expect(calendar.excludedates[1]).toEqual(parseISODateString('2024-06-20'))
84
+ })
85
+
86
+ test('excludes weekdays correctly', async () => {
87
+ // Exclude weekends (Saturday=6, Sunday=0)
88
+ const container = await createCalendar('excludeweekdays="0,6"')
89
+
90
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
91
+ await calendar.updateComplete
92
+
93
+ expect(calendar.excludeweekdays).toEqual(['0', '6'])
94
+
95
+ // Check that weekend dates are disabled
96
+ const disabledDates = calendar.querySelectorAll('.pkt-calendar__date--disabled')
97
+ expect(disabledDates.length).toBeGreaterThan(0)
98
+ })
99
+
100
+ test('excludes both specific dates and weekdays', async () => {
101
+ const container = await createCalendar('excludedates="2024-06-15" excludeweekdays="0,6"')
102
+
103
+ const calendar = container.querySelector('pkt-calendar') as PktCalendar
104
+ await calendar.updateComplete
105
+
106
+ expect(calendar.excludedates).toHaveLength(1)
107
+ expect(calendar.excludeweekdays).toEqual(['0', '6'])
108
+ })
109
+ })
110
+ })