@oslokommune/punkt-elements 13.5.12 → 13.6.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/dist/pkt-index.js CHANGED
@@ -1,39 +1,39 @@
1
1
  import { P as A } from "./alert-cUBtwi2k.js";
2
- import { P as B, a as E } from "./accordionitem-C9T3nlM0.js";
3
- import { P as O } from "./backlink-C2jbzu0U.js";
4
- import { P as T } from "./button-DhispFOY.js";
5
- import { c as f } from "./calendar-CJSxvwAq.js";
6
- import { P as D } from "./calendar-CJSxvwAq.js";
2
+ import { P as w, a as B } from "./accordionitem-C9T3nlM0.js";
3
+ import { P as E } from "./backlink-C2jbzu0U.js";
4
+ import { P as O } from "./button-DhispFOY.js";
5
+ import { c as d } from "./calendar-DJVaC_zI.js";
6
+ import { P as j } from "./calendar-DJVaC_zI.js";
7
7
  import { P as G } from "./card-BDz4RWxK.js";
8
8
  import { P as K } from "./combobox-BXP1PL0M.js";
9
9
  import { P as U } from "./consent-BpcQFvbi.js";
10
10
  import { P as q } from "./checkbox-ym7z6cpt.js";
11
- import { P as k, t as h, x as P, n, a as c } from "./element-CgEWt74-.js";
11
+ import { P as f, 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
- import { e as m, n as d } from "./ref-BBYSqgeW.js";
13
+ import { e as m, n as k } from "./ref-BBYSqgeW.js";
14
14
  import { e as u } from "./class-map-BpTj9gtz.js";
15
- import { P as F } from "./datepicker-F3TwE9o7.js";
16
- import { P as Q } from "./helptext-B7eI0iBQ.js";
17
- import { P as X } from "./heading-Bdh9absf.js";
18
- import { P as Z } from "./icon-CC1js8eR.js";
19
- import { P as et } from "./input-wrapper-Dr__Sxql.js";
20
- import { P as ot } from "./link-AIyVfcyH.js";
21
- import { P as at } from "./linkcard-9CNlyT0S.js";
22
- import { P as it } from "./loader-h3d-3D7s.js";
23
- import { P as lt } from "./messagebox-C8KQgCl_.js";
24
- import { P as mt } from "./modal-Zj8yRX3K.js";
15
+ import { P as F, a as J } from "./datepicker-X2o0j5kW.js";
16
+ import { P as V } from "./helptext-B7eI0iBQ.js";
17
+ import { P as Y } from "./heading-Bdh9absf.js";
18
+ import { P as tt } from "./icon-CC1js8eR.js";
19
+ import { P as rt } from "./input-wrapper-Dr__Sxql.js";
20
+ import { P as st } from "./link-AIyVfcyH.js";
21
+ import { P as nt } from "./linkcard-9CNlyT0S.js";
22
+ import { P as pt } from "./loader-h3d-3D7s.js";
23
+ import { P as Pt } from "./messagebox-C8KQgCl_.js";
24
+ import { P as kt } from "./modal-Zj8yRX3K.js";
25
25
  import { P as ft } from "./progressbar-Dj_mI_A6.js";
26
- import { P as ht, P as ct } from "./radiobutton-CWxiIVfA.js";
27
- import { P as ut } from "./tag-DyXzTY68.js";
28
- import { P as vt } from "./textarea-BZL8Mkm0.js";
29
- import { P as bt } from "./textinput-DjPhmmkB.js";
30
- import { P as $t } from "./select-dcaJHvmR.js";
26
+ import { P as ct, P as xt } from "./radiobutton-CWxiIVfA.js";
27
+ import { P as gt } from "./tag-DyXzTY68.js";
28
+ import { P as St } from "./textarea-BZL8Mkm0.js";
29
+ import { P as Ct } from "./textinput-DjPhmmkB.js";
30
+ import { P as yt } from "./select-VpX_cjMM.js";
31
31
  var g = Object.defineProperty, v = Object.getOwnPropertyDescriptor, s = (t, e, i, a) => {
32
32
  for (var r = a > 1 ? void 0 : a ? v(e, i) : e, p = t.length - 1, l; p >= 0; p--)
33
33
  (l = t[p]) && (r = (a ? l(e, i, r) : l(r)) || r);
34
34
  return a && r && g(e, i, r), r;
35
35
  };
36
- let o = class extends k {
36
+ let o = class extends f {
37
37
  constructor() {
38
38
  super(), this.string = "", this.strings = [], this.darkmode = !1, this._list = [], this.defaultSlot = m(), this.namedSlot = m(), this.slotController = new x(this, this.defaultSlot, this.namedSlot);
39
39
  }
@@ -63,11 +63,11 @@ let o = class extends k {
63
63
  <div>${this.renderList(this.doStuff(this._list))}</div>
64
64
 
65
65
  <h2 class="pkt-txt-22">Slot</h2>
66
- <div ${d(this.defaultSlot)}>defaultSlotRef</div>
66
+ <div ${k(this.defaultSlot)}>defaultSlotRef</div>
67
67
  <h2 class="pkt-txt-22">Named slot</h2>
68
68
  <select
69
69
  name="named-slot"
70
- ${d(this.namedSlot)}
70
+ ${k(this.namedSlot)}
71
71
  @change=${(e) => alert(e.target.value)}
72
72
  >
73
73
  namedSlotRef
@@ -108,7 +108,7 @@ s([
108
108
  n({ type: String })
109
109
  ], o.prototype, "string", 2);
110
110
  s([
111
- n({ converter: f })
111
+ n({ converter: d })
112
112
  ], o.prototype, "strings", 2);
113
113
  s([
114
114
  n({ type: Boolean })
@@ -120,32 +120,33 @@ o = s([
120
120
  c("pkt-component")
121
121
  ], o);
122
122
  export {
123
- B as PktAccordion,
124
- E as PktAccordionItem,
123
+ w as PktAccordion,
124
+ B as PktAccordionItem,
125
125
  A as PktAlert,
126
- O as PktBackLink,
127
- T as PktButton,
128
- D as PktCalendar,
126
+ E as PktBackLink,
127
+ O as PktButton,
128
+ j as PktCalendar,
129
129
  G as PktCard,
130
130
  q as PktCheckbox,
131
131
  K as PktCombobox,
132
132
  o as PktComponent,
133
133
  U as PktConsent,
134
- F as PktDatepicker,
135
- X as PktHeading,
136
- Q as PktHelptext,
137
- Z as PktIcon,
138
- et as PktInputWrapper,
139
- ot as PktLink,
140
- at as PktLinkCard,
141
- it as PktLoader,
142
- lt as PktMessagebox,
143
- mt as PktModal,
134
+ F as PktDateTags,
135
+ J as PktDatepicker,
136
+ Y as PktHeading,
137
+ V as PktHelptext,
138
+ tt as PktIcon,
139
+ rt as PktInputWrapper,
140
+ st as PktLink,
141
+ nt as PktLinkCard,
142
+ pt as PktLoader,
143
+ Pt as PktMessagebox,
144
+ kt as PktModal,
144
145
  ft as PktProgressbar,
145
- ht as PktRadioButton,
146
- ct as PktRadiobutton,
147
- $t as PktSelect,
148
- ut as PktTag,
149
- vt as PktTextarea,
150
- bt as PktTextinput
146
+ ct as PktRadioButton,
147
+ xt as PktRadiobutton,
148
+ yt as PktSelect,
149
+ gt as PktTag,
150
+ St as PktTextarea,
151
+ Ct as PktTextinput
151
152
  };
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./select-CD6Zn8YH.cjs"),t=e.PktSelect;Object.defineProperty(exports,"PktSelect",{enumerable:!0,get:()=>e.PktSelect});exports.default=t;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./select-Be--DBcR.cjs"),t=e.PktSelect;Object.defineProperty(exports,"PktSelect",{enumerable:!0,get:()=>e.PktSelect});exports.default=t;
@@ -1,4 +1,4 @@
1
- import { P as t } from "./select-dcaJHvmR.js";
1
+ import { P as t } from "./select-VpX_cjMM.js";
2
2
  const a = t;
3
3
  export {
4
4
  t as PktSelect,
@@ -0,0 +1,49 @@
1
+ "use strict";const h=require("./element-6DBpyGQm.cjs"),u=require("./state-DPobt-Yz.cjs"),r=require("./ref-iJtiv3o2.cjs"),o=require("./if-defined-Cni-RHLS.cjs"),d=require("./input-element-C4xJoM-X.cjs"),c=require("./pkt-options-controller-CiuBG6Lt.cjs"),v=require("./pkt-slot-controller-BzddBp7z.cjs");require("./input-wrapper-CZ-a00V7.cjs");var f=Object.defineProperty,_=Object.getOwnPropertyDescriptor,a=(p,t,e,s)=>{for(var i=s>1?void 0:s?_(t,e):t,l=p.length-1,n;l>=0;l--)(n=p[l])&&(i=(s?n(t,e,i):n(i))||i);return s&&i&&f(t,e,i),i};exports.PktSelect=class extends d.PktInputElement{constructor(){super(),this.inputRef=r.e(),this.helptextSlot=r.e(),this._optionsProp=[],this.value="",this._options=[],this.selectedIndex=-1,this.selectedOptions=void 0,this.optionsController=new c.PktOptionsSlotController(this),this.slotController=new v.PktSlotController(this,this.helptextSlot),this.slotController.skipOptions=!0}get options(){return this._options.map(t=>({...t,selected:t.value===this.value}))}set options(t){this._optionsProp=t,this.requestUpdate("_optionsProp",this._options)}connectedCallback(){super.connectedCallback();const t=this._optionsProp.length>0,e=this.optionsController.nodes.length&&this.optionsController.nodes.length>0;!t&&e?this.optionsController.nodes.forEach(s=>{const i={value:s.hasAttribute("value")?s.getAttribute("value")??"":s.textContent??"",label:s.textContent||s.getAttribute("value")||"",disabled:s.hasAttribute("disabled"),selected:s.hasAttribute("selected"),hidden:s.hasAttribute("data-hidden")};s.getAttribute("selected")&&!this.value&&(this.value=i.value),this._options.push(i)}):(this._options=this._optionsProp,this._options.forEach(s=>{s.selected&&!this.value&&(this.value=s.value)}))}add(t,e){const s={value:t.value||t.text,label:t.text||t.value,selected:t.selected,disabled:t.disabled};if(e===void 0)this._options.push(s);else if(typeof e=="number")this._options.splice(e,0,s);else{const i=e.value||e.text,l=this._options.findIndex(n=>n.value===i);l>=0?this._options.splice(l,0,s):this._options.push(s)}t.selected&&(this.value=t.value||t.text,this.selectedIndex=this._options.findIndex(i=>i.value===this.value)),this.requestUpdate()}remove(t){var e;typeof t=="number"&&(this.selectedIndex===t&&(this.value=((e=this._options[0])==null?void 0:e.value)||""),this._options.splice(t,1),this.requestUpdate())}item(t){var e;return(e=this.inputRef.value)==null?void 0:e.item(t)}namedItem(t){var e;return(e=this.inputRef.value)==null?void 0:e.namedItem(t)}showPicker(){this.inputRef.value&&"showPicker"in this.inputRef.value&&this.inputRef.value.showPicker()}attributeChangedCallback(t,e,s){var i,l;t==="options"&&(this._options=s?JSON.parse(s):[]),t==="value"&&this.value!==e&&(this.selectedIndex=this.touched?this.returnNumberOrNull((i=this.inputRef.value)==null?void 0:i.selectedIndex):this._options.findIndex(n=>n.value===s),this.selectedOptions=(l=this.inputRef.value)==null?void 0:l.selectedOptions,this.valueChanged(s,e)),super.attributeChangedCallback(t,e,s)}update(t){var e,s;super.update(t),t.has("_optionsProp")&&this._optionsProp.length>0&&(this._options=this._optionsProp,this.requestUpdate("_options"),!this.value&&this._options.length>0&&(this.value=this._options[0].value,this.selectedIndex=0)),t.has("value")&&this.value!==t.get("value")&&(this.selectedIndex=this.touched?this.returnNumberOrNull((e=this.inputRef.value)==null?void 0:e.selectedIndex):this._options.findIndex(i=>i.value===this.value),this.selectedOptions=(s=this.inputRef.value)==null?void 0:s.selectedOptions,this.valueChanged(this.value,t.get("value"))),t.has("id")&&!this.name&&this.id&&(this.name=this.id)}firstUpdated(t){var e;super.firstUpdated(t),this._optionsProp.length&&(this._options=this._optionsProp),!this.value&&this._options.length>0?(this.value=this._options[0].value,this.selectedIndex=0):this.selectedIndex=this._options.findIndex(s=>s.value===this.value),this.selectedOptions=(e=this.inputRef.value)==null?void 0:e.selectedOptions}render(){const t=`pkt-input ${this.fullwidth?"pkt-input--fullwidth":""}`;return h.x`
2
+ <pkt-input-wrapper
3
+ ?counter=${this.counter}
4
+ ?disabled=${this.disabled}
5
+ ?hasError=${this.hasError}
6
+ ?hasFieldset=${this.hasFieldset}
7
+ ?inline=${this.inline}
8
+ ?optionalTag=${this.optionalTag}
9
+ ?requiredTag=${this.requiredTag}
10
+ ?useWrapper=${this.useWrapper}
11
+ ariaDescribedBy=${o.o(this.ariaDescribedBy)}
12
+ class="pkt-select"
13
+ errorMessage=${o.o(this.errorMessage)}
14
+ forId=${this.id+"-input"}
15
+ helptext=${o.o(this.helptext)}
16
+ helptextDropdown=${o.o(this.helptextDropdown)}
17
+ helptextDropdownButton=${o.o(this.helptextDropdownButton)}
18
+ label=${o.o(this.label)}
19
+ optionalText=${o.o(this.optionalText)}
20
+ requiredText=${o.o(this.requiredText)}
21
+ tagText=${o.o(this.tagText)}
22
+ >
23
+ <select
24
+ class=${t}
25
+ aria-invalid=${this.hasError}
26
+ aria-errormessage=${`${this.id}-error`}
27
+ aria-labelledby=${o.o(this.ariaLabelledby)}
28
+ ?disabled=${this.disabled}
29
+ id=${this.id+"-input"}
30
+ name=${(this.name||this.id)+"-input"}
31
+ value=${this.value}
32
+ @change=${e=>{this.touched=!0,this.value=e.target.value,e.stopImmediatePropagation()}}
33
+ @input=${e=>{this.onInput(),e.stopImmediatePropagation()}}
34
+ @focus=${e=>{this.onFocus(),e.stopImmediatePropagation()}}
35
+ @blur=${e=>{this.onBlur(),e.stopImmediatePropagation()}}
36
+ ${r.n(this.inputRef)}
37
+ >
38
+ ${this._options.length>0?this._options.map(e=>h.x`<option
39
+ value=${e.value}
40
+ ?selected=${this.value==e.value||e.selected}
41
+ ?disabled=${e.disabled}
42
+ ?hidden=${e.hidden}
43
+ >
44
+ ${e.label}
45
+ </option>`):""}
46
+ </select>
47
+ <div class="pkt-contents" ${r.n(this.helptextSlot)} name="helptext" slot="helptext"></div>
48
+ </pkt-input-wrapper>
49
+ `}returnNumberOrNull(t){return t==null||isNaN(t)?null:t}};a([h.n({type:Array,attribute:"options"})],exports.PktSelect.prototype,"_optionsProp",2);a([h.n({type:String})],exports.PktSelect.prototype,"value",2);a([u.r()],exports.PktSelect.prototype,"_options",2);exports.PktSelect=a([h.t("pkt-select")],exports.PktSelect);
@@ -0,0 +1,173 @@
1
+ import { x as r, n as c, a as v } from "./element-CgEWt74-.js";
2
+ import { r as f } from "./state-Bo2bck5_.js";
3
+ import { e as u, n as d } from "./ref-BBYSqgeW.js";
4
+ import { o as l } from "./if-defined-CmuO4Vz9.js";
5
+ import { P as _ } from "./input-element-NnrDmp4r.js";
6
+ import { P as x } from "./pkt-options-controller-CZO1nxZ8.js";
7
+ import { P as b } from "./pkt-slot-controller-BPGj-LC5.js";
8
+ import "./input-wrapper-Dr__Sxql.js";
9
+ var $ = Object.defineProperty, m = Object.getOwnPropertyDescriptor, a = (t, e, s, i) => {
10
+ for (var o = i > 1 ? void 0 : i ? m(e, s) : e, n = t.length - 1, p; n >= 0; n--)
11
+ (p = t[n]) && (o = (i ? p(e, s, o) : p(o)) || o);
12
+ return i && o && $(e, s, o), o;
13
+ };
14
+ let h = class extends _ {
15
+ constructor() {
16
+ super(), this.inputRef = u(), this.helptextSlot = u(), this._optionsProp = [], this.value = "", this._options = [], this.selectedIndex = -1, this.selectedOptions = void 0, this.optionsController = new x(this), this.slotController = new b(this, this.helptextSlot), this.slotController.skipOptions = !0;
17
+ }
18
+ // Getter and setter for options to expose the actual parsed options
19
+ get options() {
20
+ return this._options.map((t) => ({
21
+ ...t,
22
+ selected: t.value === this.value
23
+ }));
24
+ }
25
+ set options(t) {
26
+ this._optionsProp = t, this.requestUpdate("_optionsProp", this._options);
27
+ }
28
+ connectedCallback() {
29
+ super.connectedCallback();
30
+ const t = this._optionsProp.length > 0, e = this.optionsController.nodes.length && this.optionsController.nodes.length > 0;
31
+ !t && e ? this.optionsController.nodes.forEach((s) => {
32
+ const i = {
33
+ value: s.hasAttribute("value") ? s.getAttribute("value") ?? "" : s.textContent ?? "",
34
+ label: s.textContent || s.getAttribute("value") || "",
35
+ disabled: s.hasAttribute("disabled"),
36
+ selected: s.hasAttribute("selected"),
37
+ hidden: s.hasAttribute("data-hidden")
38
+ };
39
+ s.getAttribute("selected") && !this.value && (this.value = i.value), this._options.push(i);
40
+ }) : (this._options = this._optionsProp, this._options.forEach((s) => {
41
+ s.selected && !this.value && (this.value = s.value);
42
+ }));
43
+ }
44
+ // Support native Select method `add`
45
+ add(t, e) {
46
+ const s = {
47
+ value: t.value || t.text,
48
+ label: t.text || t.value,
49
+ selected: t.selected,
50
+ disabled: t.disabled
51
+ };
52
+ if (e === void 0)
53
+ this._options.push(s);
54
+ else if (typeof e == "number")
55
+ this._options.splice(e, 0, s);
56
+ else {
57
+ const i = e.value || e.text, o = this._options.findIndex((n) => n.value === i);
58
+ o >= 0 ? this._options.splice(o, 0, s) : this._options.push(s);
59
+ }
60
+ t.selected && (this.value = t.value || t.text, this.selectedIndex = this._options.findIndex((i) => i.value === this.value)), this.requestUpdate();
61
+ }
62
+ // Support native Select method `remove`
63
+ remove(t) {
64
+ var e;
65
+ typeof t == "number" && (this.selectedIndex === t && (this.value = ((e = this._options[0]) == null ? void 0 : e.value) || ""), this._options.splice(t, 1), this.requestUpdate());
66
+ }
67
+ // Support native Select method `item`
68
+ item(t) {
69
+ var e;
70
+ return (e = this.inputRef.value) == null ? void 0 : e.item(t);
71
+ }
72
+ // Support native Select method `namedItem`
73
+ namedItem(t) {
74
+ var e;
75
+ return (e = this.inputRef.value) == null ? void 0 : e.namedItem(t);
76
+ }
77
+ // Support native Select method `showPicker`
78
+ showPicker() {
79
+ this.inputRef.value && "showPicker" in this.inputRef.value && this.inputRef.value.showPicker();
80
+ }
81
+ attributeChangedCallback(t, e, s) {
82
+ var i, o;
83
+ t === "options" && (this._options = s ? JSON.parse(s) : []), t === "value" && this.value !== e && (this.selectedIndex = this.touched ? this.returnNumberOrNull((i = this.inputRef.value) == null ? void 0 : i.selectedIndex) : this._options.findIndex((n) => n.value === s), this.selectedOptions = (o = this.inputRef.value) == null ? void 0 : o.selectedOptions, this.valueChanged(s, e)), super.attributeChangedCallback(t, e, s);
84
+ }
85
+ update(t) {
86
+ var e, s;
87
+ super.update(t), t.has("_optionsProp") && this._optionsProp.length > 0 && (this._options = this._optionsProp, this.requestUpdate("_options"), !this.value && this._options.length > 0 && (this.value = this._options[0].value, this.selectedIndex = 0)), t.has("value") && this.value !== t.get("value") && (this.selectedIndex = this.touched ? this.returnNumberOrNull((e = this.inputRef.value) == null ? void 0 : e.selectedIndex) : this._options.findIndex((i) => i.value === this.value), this.selectedOptions = (s = this.inputRef.value) == null ? void 0 : s.selectedOptions, this.valueChanged(this.value, t.get("value"))), t.has("id") && !this.name && this.id && (this.name = this.id);
88
+ }
89
+ firstUpdated(t) {
90
+ var e;
91
+ super.firstUpdated(t), this._optionsProp.length && (this._options = this._optionsProp), !this.value && this._options.length > 0 ? (this.value = this._options[0].value, this.selectedIndex = 0) : this.selectedIndex = this._options.findIndex((s) => s.value === this.value), this.selectedOptions = (e = this.inputRef.value) == null ? void 0 : e.selectedOptions;
92
+ }
93
+ render() {
94
+ const t = `pkt-input ${this.fullwidth ? "pkt-input--fullwidth" : ""}`;
95
+ return r`
96
+ <pkt-input-wrapper
97
+ ?counter=${this.counter}
98
+ ?disabled=${this.disabled}
99
+ ?hasError=${this.hasError}
100
+ ?hasFieldset=${this.hasFieldset}
101
+ ?inline=${this.inline}
102
+ ?optionalTag=${this.optionalTag}
103
+ ?requiredTag=${this.requiredTag}
104
+ ?useWrapper=${this.useWrapper}
105
+ ariaDescribedBy=${l(this.ariaDescribedBy)}
106
+ class="pkt-select"
107
+ errorMessage=${l(this.errorMessage)}
108
+ forId=${this.id + "-input"}
109
+ helptext=${l(this.helptext)}
110
+ helptextDropdown=${l(this.helptextDropdown)}
111
+ helptextDropdownButton=${l(this.helptextDropdownButton)}
112
+ label=${l(this.label)}
113
+ optionalText=${l(this.optionalText)}
114
+ requiredText=${l(this.requiredText)}
115
+ tagText=${l(this.tagText)}
116
+ >
117
+ <select
118
+ class=${t}
119
+ aria-invalid=${this.hasError}
120
+ aria-errormessage=${`${this.id}-error`}
121
+ aria-labelledby=${l(this.ariaLabelledby)}
122
+ ?disabled=${this.disabled}
123
+ id=${this.id + "-input"}
124
+ name=${(this.name || this.id) + "-input"}
125
+ value=${this.value}
126
+ @change=${(e) => {
127
+ this.touched = !0, this.value = e.target.value, e.stopImmediatePropagation();
128
+ }}
129
+ @input=${(e) => {
130
+ this.onInput(), e.stopImmediatePropagation();
131
+ }}
132
+ @focus=${(e) => {
133
+ this.onFocus(), e.stopImmediatePropagation();
134
+ }}
135
+ @blur=${(e) => {
136
+ this.onBlur(), e.stopImmediatePropagation();
137
+ }}
138
+ ${d(this.inputRef)}
139
+ >
140
+ ${this._options.length > 0 ? this._options.map(
141
+ (e) => r`<option
142
+ value=${e.value}
143
+ ?selected=${this.value == e.value || e.selected}
144
+ ?disabled=${e.disabled}
145
+ ?hidden=${e.hidden}
146
+ >
147
+ ${e.label}
148
+ </option>`
149
+ ) : ""}
150
+ </select>
151
+ <div class="pkt-contents" ${d(this.helptextSlot)} name="helptext" slot="helptext"></div>
152
+ </pkt-input-wrapper>
153
+ `;
154
+ }
155
+ returnNumberOrNull(t) {
156
+ return t == null || isNaN(t) ? null : t;
157
+ }
158
+ };
159
+ a([
160
+ c({ type: Array, attribute: "options" })
161
+ ], h.prototype, "_optionsProp", 2);
162
+ a([
163
+ c({ type: String })
164
+ ], h.prototype, "value", 2);
165
+ a([
166
+ f()
167
+ ], h.prototype, "_options", 2);
168
+ h = a([
169
+ v("pkt-select")
170
+ ], h);
171
+ export {
172
+ h as P
173
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oslokommune/punkt-elements",
3
- "version": "13.5.12",
3
+ "version": "13.6.0",
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",
@@ -73,5 +73,5 @@
73
73
  "url": "https://github.com/oslokommune/punkt/issues"
74
74
  },
75
75
  "license": "MIT",
76
- "gitHead": "0216f07fa821851a3768a219b1906aba297fbf94"
76
+ "gitHead": "02be3699565d6e962bf2a28742428505c2922363"
77
77
  }
@@ -0,0 +1,126 @@
1
+ import '@testing-library/jest-dom'
2
+ import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { vi } from 'vitest'
4
+ import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
+ import './date-tags'
6
+ import { PktDateTags } from './date-tags'
7
+
8
+ expect.extend(toHaveNoViolations)
9
+
10
+ export interface IDateTagsTest extends BaseTestConfig {
11
+ dates?: string[]
12
+ idBase?: string
13
+ className?: string
14
+ dateformat?: string
15
+ }
16
+
17
+ export const createDateTagsTest = async (config: IDateTagsTest = {}) => {
18
+ const { container, element } = await createElementTest('pkt-date-tags' as any, config)
19
+
20
+ return {
21
+ container,
22
+ dateTags: element as PktDateTags,
23
+ }
24
+ }
25
+
26
+ afterEach(() => {
27
+ document.body.innerHTML = ''
28
+ })
29
+
30
+ describe('PktDateTags', () => {
31
+ test('renders nothing when no dates provided', async () => {
32
+ const { dateTags } = await createDateTagsTest()
33
+ await dateTags.updateComplete
34
+
35
+ expect(dateTags.querySelectorAll('time').length).toBe(0)
36
+ })
37
+
38
+ test('renders provided ISO dates and formats them', async () => {
39
+ const iso = '2025-09-17'
40
+ const { dateTags } = await createDateTagsTest()
41
+
42
+ dateTags.dates = [iso]
43
+ dateTags.idBase = 'base-'
44
+ await dateTags.updateComplete
45
+
46
+ const time = dateTags.querySelector('time')
47
+ expect(time).toBeTruthy()
48
+ expect(time?.getAttribute('datetime')).toBe(iso)
49
+
50
+ expect(time?.textContent?.trim()).toBe('17.09.2025')
51
+
52
+ const tag = dateTags.querySelector('pkt-tag')
53
+ expect(tag).toBeTruthy()
54
+ expect(tag?.id).toBe(`base-${iso}-tag`)
55
+ })
56
+
57
+ test('applies custom unicode-style dateformat', async () => {
58
+ const iso = '2025-09-17'
59
+ const { dateTags } = await createDateTagsTest()
60
+
61
+ dateTags.dates = [iso]
62
+ dateTags.dateformat = 'yyyy/MM/dd'
63
+ await dateTags.updateComplete
64
+
65
+ const time = dateTags.querySelector('time')
66
+ expect(time).toBeTruthy()
67
+ expect(time?.textContent?.trim()).toBe('2025/09/17')
68
+ })
69
+
70
+ test('normalizes overflow ISO dates (e.g. 2025-02-30 -> 02.03.2025)', async () => {
71
+ const iso = '2025-02-30'
72
+ const { dateTags } = await createDateTagsTest()
73
+
74
+ dateTags.dates = [iso]
75
+ await dateTags.updateComplete
76
+
77
+ const time = dateTags.querySelector('time')
78
+ expect(time).toBeTruthy()
79
+
80
+ // JS Date normalizes invalid dates; 2025-02-30 becomes 02.03.2025
81
+ expect(time?.textContent?.trim()).toBe('02.03.2025')
82
+ })
83
+
84
+ test('Moment-style tokens (DD.MM.YYYY) do not match date-fns tokens', async () => {
85
+ const iso = '2025-09-17'
86
+ const { dateTags } = await createDateTagsTest()
87
+
88
+ // Moment-style tokens are uppercase; date-fns expects lowercase (yyyy, dd)
89
+ dateTags.dates = [iso]
90
+ dateTags.dateformat = 'DD.MM.YYYY'
91
+
92
+ const spyWarn = vi.spyOn(console, 'warn').mockImplementation(() => {})
93
+ try {
94
+ await expect(dateTags.updateComplete).rejects.toThrow(/Use `dd` instead of `DD`/)
95
+ } finally {
96
+ spyWarn.mockRestore()
97
+ }
98
+ })
99
+
100
+ test('emits date-tag-removed when child pkt-tag dispatches close', async () => {
101
+ const iso = '2025-09-17'
102
+ const { dateTags } = await createDateTagsTest()
103
+ dateTags.dates = [iso]
104
+ await dateTags.updateComplete
105
+
106
+ const handler = vi.fn()
107
+ dateTags.addEventListener('date-tag-removed', (e: any) => handler(e.detail))
108
+
109
+ const tag = dateTags.querySelector('pkt-tag')
110
+ expect(tag).toBeTruthy()
111
+
112
+ // Simulate close event on child tag
113
+ tag?.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))
114
+
115
+ expect(handler).toHaveBeenCalledWith(iso)
116
+ })
117
+
118
+ test('is accessible (WCAG) with dates', async () => {
119
+ const iso = '2025-09-17'
120
+ const { container } = await createDateTagsTest({ dates: [iso] })
121
+
122
+ // Run axe on the rendered container
123
+ const results = await axe(container)
124
+ expect(results).toHaveNoViolations()
125
+ })
126
+ })
@@ -0,0 +1,59 @@
1
+ import { PktElement } from '@/base-elements/element'
2
+ import { html, nothing } from 'lit'
3
+ import { customElement, property } from 'lit/decorators.js'
4
+ import { classMap } from 'lit/directives/class-map.js'
5
+ import { repeat } from 'lit/directives/repeat.js'
6
+
7
+ import '@/components/tag'
8
+ import { fromISOtoLocal } from '@/utils/dateutils'
9
+ import { uuidish } from '@/utils/stringutils'
10
+
11
+ type TYear = `${number}${number}${number}${number}`
12
+ type TMonth = `${number}${number}`
13
+ type TDay = `${number}${number}`
14
+ export type TISODate = `${TYear}-${TMonth}-${TDay}`
15
+
16
+ /**
17
+ * OBS! `dateformat` er standard formatteringsstreng for visning av datoer.
18
+ * Denne brukes for å sette "menneskeleselig" format på datoene i tags.
19
+ *
20
+ * Følger denne unicode-standarden:
21
+ * https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
22
+ */
23
+
24
+ @customElement('pkt-date-tags')
25
+ export class PktDateTags extends PktElement {
26
+ @property({ type: Array }) dates: TISODate[] = []
27
+ @property({ type: String }) dateformat: string = 'dd.MM.yyyy' // se kommentar over
28
+ @property({ type: String, attribute: 'class' }) className: string = 'pkt-datepicker__tags'
29
+ @property({ type: String, attribute: 'id-base' }) idBase: string = uuidish()
30
+
31
+ render() {
32
+ this.classes = {
33
+ 'pkt-date-tags': true,
34
+ [this.className]: true,
35
+ }
36
+
37
+ return html`
38
+ <div class=${classMap(this.classes)} aria-live="polite">
39
+ ${Array.isArray(this.dates) && !!this.dates[0]
40
+ ? repeat(
41
+ (this.dates ?? []).filter(Boolean).sort(),
42
+ (date) => date,
43
+ (date) =>
44
+ html` <pkt-tag
45
+ id=${this.idBase + date + '-tag'}
46
+ closeTag
47
+ @close=${() => {
48
+ this.dispatchEvent(new CustomEvent('date-tag-removed', { detail: date }))
49
+ }}
50
+ .ariaLabel=${`${this.strings?.calendar.deleteDate} ${fromISOtoLocal(date, this.dateformat)}`}
51
+ >
52
+ <time datetime=${date}>${fromISOtoLocal(date, this.dateformat)}</time>
53
+ </pkt-tag>`,
54
+ )
55
+ : nothing}
56
+ </div>
57
+ `
58
+ }
59
+ }
@@ -1,24 +1,17 @@
1
1
  import { classMap } from 'lit/directives/class-map.js'
2
2
  import { ifDefined } from 'lit/directives/if-defined.js'
3
3
  import { customElement, property, state } from 'lit/decorators.js'
4
- import {
5
- formatISODate,
6
- fromISOToDate,
7
- fromISOtoLocal,
8
- newDate,
9
- parseISODateString,
10
- } from '@/utils/dateutils'
4
+ import { formatISODate, fromISOToDate, newDate, parseISODateString } from '@/utils/dateutils'
11
5
  import { html, nothing, PropertyValues } from 'lit'
12
6
  import { PktCalendar } from '@/components/calendar/calendar'
13
7
  import { PktInputElement } from '@/base-elements/input-element'
14
8
  import { Ref, createRef, ref } from 'lit/directives/ref.js'
15
- import { repeat } from 'lit/directives/repeat.js'
16
9
  import converters from '@/helpers/converters'
17
10
  import specs from 'componentSpecs/datepicker.json'
18
11
  import '@/components/calendar'
19
12
  import '@/components/icon'
20
13
  import '@/components/input-wrapper'
21
- import '@/components/tag'
14
+ import './date-tags'
22
15
  import { PktSlotController } from '@/controllers/pkt-slot-controller'
23
16
 
24
17
  const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
@@ -527,31 +520,6 @@ export class PktDatepicker extends PktInputElement {
527
520
  `
528
521
  }
529
522
 
530
- renderTags() {
531
- return html`
532
- <div class="pkt-datepicker__tags" aria-live="polite">
533
- ${!!this._value[0]
534
- ? repeat(
535
- (this._value ?? []).filter(Boolean).sort(),
536
- (date) => date,
537
- (date) => html`
538
- <pkt-tag
539
- .id="${this.id + date + '-tag'}"
540
- closeTag
541
- ariaLabel="${this.strings.calendar.deleteDate} ${fromISOtoLocal(
542
- date,
543
- this.dateformat,
544
- )}"
545
- @close=${() => this.calRef.value?.handleDateSelect(fromISOToDate(date))}
546
- ><time datetime="${date}">${fromISOtoLocal(date, this.dateformat)}</time></pkt-tag
547
- >
548
- `,
549
- )
550
- : nothing}
551
- </div>
552
- `
553
- }
554
-
555
523
  renderCalendar() {
556
524
  return html`<div
557
525
  class="pkt-calendar-popup pkt-${this.calendarOpen ? 'show' : 'hide'}"
@@ -651,7 +619,17 @@ export class PktDatepicker extends PktInputElement {
651
619
  class="pkt-datepicker"
652
620
  >
653
621
  <div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
654
- ${this.multiple ? this.renderTags() : nothing}
622
+ ${this.multiple
623
+ ? html`<pkt-date-tags
624
+ .dates=${this._value}
625
+ dateformat=${this.dateformat}
626
+ strings=${this.strings}
627
+ id-base=${this.id}
628
+ @date-tag-removed=${(e: CustomEvent) => {
629
+ this.calRef.value?.handleDateSelect(fromISOToDate(e.detail))
630
+ }}
631
+ ></pkt-date-tags>`
632
+ : nothing}
655
633
  <div
656
634
  class="pkt-datepicker__inputs ${this.range && this.showRangeLabels
657
635
  ? 'pkt-input__range-inputs'
@@ -9,6 +9,7 @@ export { PktCombobox } from './combobox'
9
9
  export { PktConsent } from './consent'
10
10
  export { PktCheckbox } from '@/components/checkbox'
11
11
  export { PktComponent } from '../base-elements/component-template.js'
12
+ export { PktDateTags } from '@/components/datepicker/date-tags.js'
12
13
  export { PktDatepicker } from '@/components/datepicker/datepicker.js'
13
14
  export { PktHelptext } from '@/components/helptext'
14
15
  export { PktHeading } from '@/components/heading'