@oslokommune/punkt-elements 16.0.5 → 16.1.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.
Files changed (151) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{accordionitem-CHXGzgLv.js → accordionitem-Cj74XruR.js} +31 -31
  3. package/dist/accordionitem-D7sWqDM_.cjs +34 -0
  4. package/dist/alert-C95U_RZ0.cjs +33 -0
  5. package/dist/{alert-BHSd2Vpj.js → alert-ca_hFi-u.js} +19 -20
  6. package/dist/async-directive-B158h3ba.cjs +5 -0
  7. package/dist/async-directive-CKx6pubI.js +65 -0
  8. package/dist/{button-CHUuxLQV.js → button-BRovt5nm.js} +10 -11
  9. package/dist/button-BXN_JPaH.cjs +27 -0
  10. package/dist/{card-Db9QSEqh.cjs → card-DfHo45CG.cjs} +11 -13
  11. package/dist/{card-CmfUyl_s.js → card-DvgCTN4B.js} +47 -51
  12. package/dist/{checkbox-D6nltMuc.js → checkbox-CbIUMIYt.js} +2 -2
  13. package/dist/{checkbox-Cpyay9_l.cjs → checkbox-mmn3v9ry.cjs} +1 -1
  14. package/dist/{combobox-TKTemUxN.js → combobox-CwW0md6G.js} +31 -31
  15. package/dist/combobox-TKL44xnV.cjs +135 -0
  16. package/dist/{consent-BQLkfN3d.cjs → consent-CIhFwuFO.cjs} +1 -1
  17. package/dist/{consent-knPF4PS_.js → consent-CgS1L1xF.js} +1 -1
  18. package/dist/{datepicker-CPNcXd-o.cjs → datepicker-oN9L0Wnm.cjs} +14 -14
  19. package/dist/{datepicker-MuQYeXhL.js → datepicker-qRWWzmbo.js} +51 -51
  20. package/dist/element-with-slot-1djk8KXi.js +240 -0
  21. package/dist/element-with-slot-yT8k1Z37.cjs +1 -0
  22. package/dist/helptext-B366oeR9.cjs +24 -0
  23. package/dist/{helptext-TFpeGJ1P.js → helptext-DepcDYFV.js} +32 -39
  24. package/dist/index.d.ts +39 -90
  25. package/dist/input-element-Xe9FTi2a.cjs +1 -0
  26. package/dist/{input-element-BGNbdzy2.js → input-element-n5U38pZ1.js} +8 -7
  27. package/dist/{input-wrapper-CaUY90qz.js → input-wrapper-B__6jW4U.js} +25 -28
  28. package/dist/{input-wrapper-JU4D2TGu.cjs → input-wrapper-BdFdJU-k.cjs} +7 -9
  29. package/dist/link-DLjXMpvi.cjs +7 -0
  30. package/dist/link-oGYvBLYL.js +53 -0
  31. package/dist/linkcard-BhVIc18n.js +54 -0
  32. package/dist/linkcard-C20WC6Nw.cjs +13 -0
  33. package/dist/{loader-BF9K1VCZ.js → loader-BHt9i5Xp.js} +12 -13
  34. package/dist/{loader-C1LI8Q4z.cjs → loader-DxAGCcNF.cjs} +2 -2
  35. package/dist/messagebox-B8LW0PSQ.cjs +13 -0
  36. package/dist/messagebox-DkspcMQg.js +69 -0
  37. package/dist/modal-Bfk_ncLQ.cjs +36 -0
  38. package/dist/{modal-CGHWsjk8.js → modal-p1rvuP8e.js} +26 -27
  39. package/dist/pkt-accordion.cjs +1 -1
  40. package/dist/pkt-accordion.js +2 -2
  41. package/dist/pkt-alert.cjs +1 -1
  42. package/dist/pkt-alert.js +1 -1
  43. package/dist/pkt-button.cjs +1 -1
  44. package/dist/pkt-button.js +1 -1
  45. package/dist/pkt-card.cjs +1 -1
  46. package/dist/pkt-card.js +1 -1
  47. package/dist/pkt-checkbox.cjs +1 -1
  48. package/dist/pkt-checkbox.js +1 -1
  49. package/dist/pkt-combobox.cjs +1 -1
  50. package/dist/pkt-combobox.js +1 -1
  51. package/dist/pkt-consent.cjs +1 -1
  52. package/dist/pkt-consent.js +1 -1
  53. package/dist/pkt-datepicker.cjs +1 -1
  54. package/dist/pkt-datepicker.js +2 -2
  55. package/dist/pkt-header.cjs +16 -17
  56. package/dist/pkt-header.js +62 -69
  57. package/dist/pkt-helptext.cjs +1 -1
  58. package/dist/pkt-helptext.js +1 -1
  59. package/dist/pkt-index.cjs +1 -1
  60. package/dist/pkt-index.js +22 -22
  61. package/dist/pkt-input-wrapper.cjs +1 -1
  62. package/dist/pkt-input-wrapper.js +1 -1
  63. package/dist/pkt-link.cjs +1 -1
  64. package/dist/pkt-link.js +1 -1
  65. package/dist/pkt-linkcard.cjs +1 -1
  66. package/dist/pkt-linkcard.js +1 -1
  67. package/dist/pkt-loader.cjs +1 -1
  68. package/dist/pkt-loader.js +1 -1
  69. package/dist/pkt-messagebox.cjs +1 -1
  70. package/dist/pkt-messagebox.js +1 -1
  71. package/dist/pkt-modal.cjs +1 -1
  72. package/dist/pkt-modal.js +1 -1
  73. package/dist/pkt-options-controller-DIeKSpWv.cjs +1 -0
  74. package/dist/{pkt-options-controller-Z-bPox7n.js → pkt-options-controller-W4ITGQy9.js} +1 -1
  75. package/dist/pkt-progressbar.cjs +1 -1
  76. package/dist/pkt-progressbar.js +2 -2
  77. package/dist/pkt-radiobutton.cjs +1 -1
  78. package/dist/pkt-radiobutton.js +1 -1
  79. package/dist/pkt-select.cjs +1 -1
  80. package/dist/pkt-select.js +1 -1
  81. package/dist/pkt-tabs.cjs +1 -1
  82. package/dist/pkt-tabs.js +2 -2
  83. package/dist/pkt-tag.cjs +1 -1
  84. package/dist/pkt-tag.js +1 -1
  85. package/dist/pkt-textarea.cjs +1 -1
  86. package/dist/pkt-textarea.js +1 -1
  87. package/dist/pkt-textinput.cjs +1 -1
  88. package/dist/pkt-textinput.js +1 -1
  89. package/dist/{progressbar-Bxh335uT.cjs → progressbar-CC9Qr82_.cjs} +1 -1
  90. package/dist/{progressbar-GSA4Md1u.js → progressbar-CcX-xiPI.js} +1 -1
  91. package/dist/{radiobutton-CNHCpKn0.cjs → radiobutton-BUDQYAH-.cjs} +1 -1
  92. package/dist/{radiobutton-DgC27mb0.js → radiobutton-RW3h0tJj.js} +2 -2
  93. package/dist/ref-DBGHvw2G.js +42 -0
  94. package/dist/ref-DahIePMT.cjs +5 -0
  95. package/dist/select-PuEeK4jQ.cjs +49 -0
  96. package/dist/{select-7VuYtPZv.js → select-iXKeM3yz.js} +37 -37
  97. package/dist/{tabitem-DQRzgAT4.js → tabitem-DZSzwag2.js} +30 -30
  98. package/dist/{tabitem-BKv4eN0a.cjs → tabitem-Jenus4Qd.cjs} +13 -13
  99. package/dist/{tag-DZPqFiem.js → tag-CIWBLpjv.js} +17 -18
  100. package/dist/tag-DeE1OpmF.cjs +27 -0
  101. package/dist/{textarea-VpCEjVFx.js → textarea-DR9lVDN-.js} +13 -13
  102. package/dist/{textarea-CO7Ikug5.cjs → textarea-DtiYQWjy.cjs} +7 -7
  103. package/dist/{textinput-C2AZ9ss2.js → textinput-0Bttvt9V.js} +22 -22
  104. package/dist/{textinput-DRFZU3dA.cjs → textinput-cKrjvbJW.cjs} +9 -9
  105. package/package.json +2 -2
  106. package/src/components/accordion/accordionitem.ts +4 -6
  107. package/src/components/alert/alert.ts +4 -8
  108. package/src/components/button/button.ts +4 -12
  109. package/src/components/card/card.ts +4 -19
  110. package/src/components/combobox/combobox-base.ts +0 -5
  111. package/src/components/combobox/combobox-utils.ts +1 -1
  112. package/src/components/combobox/combobox.ts +2 -1
  113. package/src/components/datepicker/datepicker.ts +2 -8
  114. package/src/components/header/header-service.ts +5 -19
  115. package/src/components/header/header.ts +4 -13
  116. package/src/components/helptext/helptext.test.ts +2 -12
  117. package/src/components/helptext/helptext.ts +5 -19
  118. package/src/components/input-wrapper/input-wrapper.test.ts +3 -3
  119. package/src/components/input-wrapper/input-wrapper.ts +5 -16
  120. package/src/components/link/link.ts +4 -12
  121. package/src/components/linkcard/linkcard.test.ts +2 -2
  122. package/src/components/linkcard/linkcard.ts +4 -13
  123. package/src/components/loader/loader.ts +4 -12
  124. package/src/components/messagebox/messagebox.ts +4 -9
  125. package/src/components/modal/modal.ts +4 -7
  126. package/src/components/select/select.ts +2 -5
  127. package/src/components/tabs/tabitem.ts +4 -7
  128. package/src/components/tabs/tabs.ts +4 -13
  129. package/src/components/tag/tag.ts +6 -12
  130. package/src/components/textarea/textarea.ts +2 -8
  131. package/src/components/textinput/textinput.ts +2 -8
  132. package/dist/accordionitem-To95GT6b.cjs +0 -34
  133. package/dist/alert-BDXWFRcf.cjs +0 -33
  134. package/dist/button-VWxZW89G.cjs +0 -27
  135. package/dist/combobox-DX2BLzIm.cjs +0 -135
  136. package/dist/helptext-BjW1WdOn.cjs +0 -24
  137. package/dist/input-element-CSDVA3Y6.cjs +0 -1
  138. package/dist/link-Bscfb6s9.js +0 -54
  139. package/dist/link-CDuv1jxx.cjs +0 -7
  140. package/dist/linkcard-3WUL0CpY.cjs +0 -13
  141. package/dist/linkcard-wNgRxJ-S.js +0 -55
  142. package/dist/messagebox-Dmot5szX.cjs +0 -13
  143. package/dist/messagebox-LBEzcr6B.js +0 -70
  144. package/dist/modal-S9MOKOaz.cjs +0 -37
  145. package/dist/pkt-options-controller-BogGk-6J.cjs +0 -1
  146. package/dist/pkt-slot-controller-D4nKlom5.cjs +0 -1
  147. package/dist/pkt-slot-controller-D7CrjM52.js +0 -95
  148. package/dist/ref-CxLwrCxt.cjs +0 -9
  149. package/dist/ref-Dma3n3i8.js +0 -102
  150. package/dist/select-PWPy5gTB.cjs +0 -49
  151. package/dist/tag-DmbgBCKu.cjs +0 -27
@@ -3,9 +3,8 @@ import { ifDefined } from 'lit/directives/if-defined.js'
3
3
  import { customElement, property } from 'lit/decorators.js'
4
4
  import { html, nothing } from 'lit'
5
5
  import { IPktTag } from '@/components/tag'
6
- import { PktElement } from '@/base-elements/element'
7
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
8
- import { ref, createRef, Ref } from 'lit/directives/ref.js'
6
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
7
+ import { slotContent } from '@/directives/slot-content'
9
8
  import { IPktHeading } from '../heading'
10
9
  import specs from 'componentSpecs/card.json'
11
10
  import '@/components/icon'
@@ -38,18 +37,7 @@ export interface IPktCard {
38
37
  }
39
38
 
40
39
  @customElement('pkt-card')
41
- export class PktCard extends PktElement implements IPktCard {
42
- // Refs
43
-
44
- defaultSlot: Ref<HTMLElement> = createRef()
45
-
46
- //Constructor
47
-
48
- constructor() {
49
- super()
50
- this.slotController = new PktSlotController(this, this.defaultSlot)
51
- }
52
-
40
+ export class PktCard extends PktElementWithSlot implements IPktCard {
53
41
  // Properties
54
42
 
55
43
  @property({ type: String }) ariaLabel: string = ''
@@ -252,10 +240,7 @@ export class PktCard extends PktElement implements IPktCard {
252
240
  }
253
241
 
254
242
  renderSlot() {
255
- return html`
256
- ${this.defaultSlot &&
257
- html`<section class="pkt-card__content" ${ref(this.defaultSlot)}></section>`}
258
- `
243
+ return html`<section class="pkt-card__content">${slotContent(this)}</section>`
259
244
  }
260
245
 
261
246
  renderMetadata() {
@@ -2,7 +2,6 @@ import { property, state } from 'lit/decorators.js'
2
2
  import { Ref, createRef } from 'lit/directives/ref.js'
3
3
  import { PktInputElement } from '@/base-elements/input-element'
4
4
  import { PktOptionsSlotController } from '@/controllers/pkt-options-controller'
5
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
6
5
  import { isMaxSelectionReached } from 'shared-utils/combobox/option-utils'
7
6
  import specs from 'componentSpecs/combobox.json'
8
7
 
@@ -14,13 +13,9 @@ import PktListbox from '../listbox'
14
13
  * Declares all reactive properties, state, refs, and simple helpers.
15
14
  */
16
15
  export class ComboboxBase extends PktInputElement {
17
- protected readonly helptextSlot: Ref<HTMLElement> = createRef()
18
-
19
16
  constructor() {
20
17
  super()
21
18
  this.optionsController = new PktOptionsSlotController(this)
22
- this.slotController = new PktSlotController(this, this.helptextSlot)
23
- this.slotController.skipOptions = true
24
19
  }
25
20
 
26
21
  // Props / Attributes
@@ -6,7 +6,7 @@ import { buildFulltext } from 'shared-utils/combobox/option-utils'
6
6
  * Lit-specific utility functions for PktCombobox component.
7
7
  *
8
8
  * Framework-agnostic functions live in shared-utils/combobox/.
9
- * Only Lit-specific functions (using Ref, in-place mutation, PktSlotController) stay here.
9
+ * Only Lit-specific functions (using Ref, in-place mutation) stay here.
10
10
  */
11
11
 
12
12
  // Selection state helpers (mutating, Lit-specific)
@@ -13,6 +13,7 @@ import type {
13
13
  import { findOptionByValue, findOptionIndex } from 'shared-utils/combobox/option-utils'
14
14
  import { getSingleValueForInput } from 'shared-utils/combobox/input-utils'
15
15
  import { slotUtils, optionStateUtils } from './combobox-utils'
16
+ import { slotContent } from '@/directives/slot-content'
16
17
  import { ComboboxHandlers } from './combobox-handlers'
17
18
 
18
19
  import '../input-wrapper'
@@ -295,7 +296,7 @@ export class PktCombobox extends ComboboxHandlers implements IPktCombobox {
295
296
  class="pkt-combobox__wrapper"
296
297
  @labelClick=${this.handleInputClick}
297
298
  >
298
- <div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
299
+ <div class="pkt-contents" slot="helptext">${slotContent(this, 'helptext')}</div>
299
300
  <div class="pkt-combobox" @focusout=${this.handleFocusOut}>
300
301
  <div
301
302
  class=${classMap({
@@ -14,7 +14,7 @@ import './datepicker-popup'
14
14
  import './datepicker-single'
15
15
  import './datepicker-range'
16
16
  import './datepicker-multiple'
17
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
17
+ import { slotContent } from '@/directives/slot-content'
18
18
  import {
19
19
  valueUtils,
20
20
  inputTypeUtils,
@@ -135,11 +135,6 @@ export class PktDatepicker extends PktInputElement<Props> {
135
135
  * Housekeeping / lifecycle methods
136
136
  */
137
137
 
138
- constructor() {
139
- super()
140
- this.slotController = new PktSlotController(this, this.helptextSlot)
141
- }
142
-
143
138
  connectedCallback() {
144
139
  super.connectedCallback()
145
140
  if (this.timezone && this.timezone !== window.pktTz) {
@@ -256,7 +251,6 @@ export class PktDatepicker extends PktInputElement<Props> {
256
251
 
257
252
  calRef: Ref<PktCalendar> = createRef()
258
253
  popupRef: Ref<HTMLDivElement> = createRef()
259
- helptextSlot: Ref<HTMLElement> = createRef()
260
254
 
261
255
  // Child component refs
262
256
  singleInputRef: Ref<PktDatepickerSingle> = createRef()
@@ -521,7 +515,7 @@ export class PktDatepicker extends PktInputElement<Props> {
521
515
  .ariaDescribedBy=${this.ariaDescribedBy}
522
516
  class="pkt-datepicker"
523
517
  >
524
- <div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
518
+ <div class="pkt-contents" slot="helptext">${slotContent(this, 'helptext')}</div>
525
519
  ${this.multiple
526
520
  ? html`<pkt-date-tags
527
521
  .dates=${this._value}
@@ -1,9 +1,9 @@
1
- import { PktElement } from '@/base-elements/element'
2
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
3
2
  import { html, nothing, PropertyValues } from 'lit'
4
3
  import { customElement, property, state } from 'lit/decorators.js'
5
4
  import { classMap } from 'lit/directives/class-map.js'
6
5
  import { createRef, Ref, ref } from 'lit/directives/ref.js'
6
+ import { slotContent } from '@/directives/slot-content'
7
7
  import {
8
8
  User,
9
9
  Representing,
@@ -28,7 +28,7 @@ import './header-user-menu'
28
28
  const CDN_LOGO_PATH = 'https://punkt-cdn.oslo.kommune.no/latest/logos/'
29
29
 
30
30
  @customElement('pkt-header-service')
31
- export class PktHeaderService extends PktElement<IPktHeader> implements IPktHeader {
31
+ export class PktHeaderService extends PktElementWithSlot<IPktHeader> implements IPktHeader {
32
32
  @property({ type: String, attribute: 'service-name' }) serviceName?: string
33
33
  @property({ type: String, attribute: 'service-link' }) serviceLink?: string
34
34
  @property({ type: String, attribute: 'logo-link' }) logoLink?: string
@@ -69,13 +69,9 @@ export class PktHeaderService extends PktElement<IPktHeader> implements IPktHead
69
69
  @state() private openMenu: THeaderMenu = 'none'
70
70
  @state() private isHidden = false
71
71
  @state() private componentWidth = typeof window !== 'undefined' ? window.innerWidth : 0
72
- @state() private hasSlotContent = false
73
72
  @state() private alignSlotRight = false
74
73
  @state() private alignSearchRight = false
75
74
 
76
- defaultSlot: Ref<HTMLElement> = createRef()
77
- slotController!: PktSlotController
78
-
79
75
  private headerRef: Ref<HTMLElement> = createRef()
80
76
  private userContainerRef: Ref<HTMLElement> = createRef()
81
77
  private slotContainerRef: Ref<HTMLElement> = createRef()
@@ -89,15 +85,6 @@ export class PktHeaderService extends PktElement<IPktHeader> implements IPktHead
89
85
  private lastFocusedElement: HTMLElement | null = null
90
86
  private shouldRestoreFocus = false
91
87
 
92
- constructor() {
93
- super()
94
- this.slotController = new PktSlotController(this, this.defaultSlot)
95
- }
96
-
97
- updateSlots(filledSlots: Set<string | null | undefined>) {
98
- this.hasSlotContent = filledSlots.has(null) || filledSlots.has(undefined)
99
- }
100
-
101
88
  connectedCallback() {
102
89
  super.connectedCallback()
103
90
  this.setupScrollListener()
@@ -520,7 +507,7 @@ export class PktHeaderService extends PktElement<IPktHeader> implements IPktHead
520
507
  @focusout=${(e: FocusEvent) => this.handleFocusOut(e, 'slot')}
521
508
  ${ref(this.slotContainerRef)}
522
509
  >
523
- ${this.isTablet && this.hasSlotContent
510
+ ${this.isTablet && this.hasSlotContent()
524
511
  ? html`
525
512
  <pkt-button
526
513
  skin="secondary"
@@ -543,8 +530,7 @@ export class PktHeaderService extends PktElement<IPktHeader> implements IPktHead
543
530
  role=${this.isTablet ? 'menu' : nothing}
544
531
  aria-label=${this.isTablet ? 'Meny' : nothing}
545
532
  ${ref(this.slotContentRef)}
546
- ${ref(this.defaultSlot)}
547
- ></div>
533
+ >${slotContent(this)}</div>
548
534
  </div>
549
535
  `
550
536
  }
@@ -1,9 +1,8 @@
1
- import { PktElement } from '@/base-elements/element'
2
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
+ import { slotContent } from '@/directives/slot-content'
3
3
  import { html, PropertyValues } from 'lit'
4
4
  import { customElement, property } from 'lit/decorators.js'
5
5
  import { ifDefined } from 'lit/directives/if-defined.js'
6
- import { createRef, Ref, ref } from 'lit/directives/ref.js'
7
6
  import {
8
7
  User,
9
8
  Representing,
@@ -33,10 +32,7 @@ import './header-service'
33
32
  * TODO: Add `type` prop to switch between `service` and `global` header types
34
33
  */
35
34
  @customElement('pkt-header')
36
- export class PktHeader extends PktElement<IPktHeader> implements IPktHeader {
37
- defaultSlot: Ref<HTMLElement> = createRef()
38
- slotController!: PktSlotController
39
-
35
+ export class PktHeader extends PktElementWithSlot<IPktHeader> implements IPktHeader {
40
36
  @property({ type: String, attribute: 'service-name' }) serviceName?: string
41
37
  @property({ type: String, attribute: 'service-link' }) serviceLink?: string
42
38
  @property({ type: String, attribute: 'logo-link' }) logoLink?: string
@@ -76,11 +72,6 @@ export class PktHeader extends PktElement<IPktHeader> implements IPktHeader {
76
72
  @property({ type: Array, attribute: 'user-menu-footer' }) userMenuFooter?: UserMenuItem[]
77
73
  @property({ type: Array, attribute: 'user-options' }) userOptions?: UserMenuItem[]
78
74
 
79
- constructor() {
80
- super()
81
- this.slotController = new PktSlotController(this, this.defaultSlot)
82
- }
83
-
84
75
  firstUpdated(changedProperties: PropertyValues) {
85
76
  super.firstUpdated(changedProperties)
86
77
  this.emitDeprecationWarnings()
@@ -136,7 +127,7 @@ export class PktHeader extends PktElement<IPktHeader> implements IPktHeader {
136
127
  .userMenu=${this.effectiveUserMenu}
137
128
  .representing=${this.representing}
138
129
  >
139
- <div class="pkt-contents" ${ref(this.defaultSlot)}></div>
130
+ <div class="pkt-contents">${slotContent(this)}</div>
140
131
  </pkt-header-service>
141
132
  `
142
133
  }
@@ -362,29 +362,19 @@ describe('PktHelptext', () => {
362
362
  })
363
363
 
364
364
  describe('Slot management', () => {
365
- test('updates slot state when slots are filled', async () => {
365
+ test('detects slot content via hasSlotContent()', async () => {
366
366
  const container = await createHelptext('', '<span>Slotted content</span>')
367
367
 
368
368
  const helptext = container.querySelector('pkt-helptext') as PktHelptext
369
369
  await helptext.updateComplete
370
370
 
371
- // Simulate slot controller updating filled slots
372
- const filledSlots = new Set(['default'])
373
- helptext.updateSlots(filledSlots)
374
- await helptext.updateComplete
375
-
376
- expect(helptext.filledSlots.size).toBe(1)
377
- expect(helptext.filledSlots.has('default')).toBe(true)
371
+ expect(helptext.hasSlotContent()).toBe(true)
378
372
  })
379
373
 
380
374
  test('applies has-helptext class when slots are filled', async () => {
381
375
  const container = await createHelptext('', '<span>Slotted content</span>')
382
376
 
383
377
  const helptext = container.querySelector('pkt-helptext') as PktHelptext
384
-
385
- // Simulate slot controller updating filled slots
386
- const filledSlots = new Set(['default'])
387
- helptext.updateSlots(filledSlots)
388
378
  await helptext.updateComplete
389
379
 
390
380
  const helptextContainer = helptext.querySelector('.pkt-inputwrapper__helptext-container')
@@ -1,23 +1,15 @@
1
- import { PktElement } from '@/base-elements/element'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
2
  import { html, nothing } from 'lit'
3
- import { createRef, ref, Ref } from 'lit/directives/ref.js'
4
3
  import { unsafeHTML } from 'lit/directives/unsafe-html.js'
5
4
  import { classMap } from 'lit/directives/class-map.js'
6
5
  import { customElement, property, state } from 'lit/decorators.js'
7
6
  import { uuidish } from 'shared-utils/utils'
8
7
  import specs from 'componentSpecs/input-wrapper.json'
9
8
  import '@/components/icon'
10
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
9
+ import { slotContent } from '@/directives/slot-content'
11
10
 
12
11
  @customElement('pkt-helptext')
13
- export class PktHelptext extends PktElement {
14
- defaultSlot: Ref<HTMLElement> = createRef()
15
-
16
- constructor() {
17
- super()
18
- this.slotController = new PktSlotController(this, this.defaultSlot)
19
- }
20
-
12
+ export class PktHelptext extends PktElementWithSlot {
21
13
  @property({ type: String, reflect: true })
22
14
  forId: string = uuidish()
23
15
 
@@ -32,12 +24,6 @@ export class PktHelptext extends PktElement {
32
24
 
33
25
  @state() isHelpTextOpen: boolean = false
34
26
 
35
- @state() filledSlots: Set<string | null | undefined> = new Set()
36
-
37
- updateSlots(filledSlots: Set<string | null | undefined>) {
38
- this.filledSlots = new Set(filledSlots)
39
- }
40
-
41
27
  render() {
42
28
  const toggleDropdown = () => {
43
29
  const isOpen = !this.isHelpTextOpen
@@ -53,7 +39,7 @@ export class PktHelptext extends PktElement {
53
39
  const helptextClasses = classMap({
54
40
  'pkt-inputwrapper__helptext-container': true,
55
41
  'pkt-inputwrapper__has-helptext':
56
- this.helptext || this.helptextDropdown || this.filledSlots.size > 0,
42
+ this.helptext || this.helptextDropdown || this.hasSlotContent(),
57
43
  })
58
44
 
59
45
  const helptextDropdown = () => {
@@ -88,7 +74,7 @@ export class PktHelptext extends PktElement {
88
74
  const helptextElement = () => {
89
75
  return html`<div class="${helptextClasses}">
90
76
  <div class="pkt-inputwrapper__helptext" id="${this.forId}-helptext">
91
- <div class="pkt-contents" ${ref(this.defaultSlot)} name="helptext"></div>
77
+ <div class="pkt-contents" name="helptext">${slotContent(this)}</div>
92
78
  ${this.helptext && unsafeHTML(this.helptext)}
93
79
  </div>
94
80
  ${helptextDropdown()}
@@ -259,9 +259,9 @@ describe('PktInputWrapper', () => {
259
259
  })
260
260
  await wrapper.updateComplete
261
261
 
262
- const slottedContent = wrapper.querySelector('[name="helptext"]')
263
- expect(slottedContent).toBeInTheDocument()
264
- expect(slottedContent?.textContent).toContain('Slotted help content')
262
+ const helptextEl = wrapper.querySelector('pkt-helptext')
263
+ expect(helptextEl).toBeInTheDocument()
264
+ expect(helptextEl?.textContent).toContain('Slotted help content')
265
265
  })
266
266
  })
267
267
 
@@ -1,6 +1,5 @@
1
- import { PktElement } from '@/base-elements/element'
2
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
3
- import { ref, Ref, createRef } from 'lit/directives/ref.js'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
+ import { slotContent } from '@/directives/slot-content'
4
3
  import { ifDefined } from 'lit/directives/if-defined.js'
5
4
  import { html, nothing, PropertyValues } from 'lit'
6
5
  import { unsafeHTML } from 'lit/directives/unsafe-html.js'
@@ -42,15 +41,7 @@ type Props = ElementProps<
42
41
  >
43
42
 
44
43
  @customElement('pkt-input-wrapper')
45
- export class PktInputWrapper extends PktElement<Props> {
46
- defaultSlot: Ref<HTMLElement> = createRef()
47
- helptextSlot: Ref<HTMLElement> = createRef()
48
-
49
- constructor() {
50
- super()
51
- this.slotController = new PktSlotController(this, this.defaultSlot, this.helptextSlot)
52
- }
53
-
44
+ export class PktInputWrapper extends PktElementWithSlot<Props> {
54
45
  /**
55
46
  * Element attributes
56
47
  */
@@ -158,9 +149,7 @@ export class PktInputWrapper extends PktElement<Props> {
158
149
  @toggleHelpText=${(e: CustomEvent) => {
159
150
  this.toggleDropdown(e)
160
151
  }}
161
- ${ref(this.helptextSlot)}
162
- name="helptext"
163
- ></pkt-helptext>
152
+ >${slotContent(this, 'helptext')}</pkt-helptext>
164
153
  `
165
154
  }
166
155
 
@@ -197,7 +186,7 @@ export class PktInputWrapper extends PktElement<Props> {
197
186
  ${labelElement()}
198
187
  ${helptextElement()}
199
188
  ${this.counterPosition === 'top' ? counterElement() : nothing}
200
- <div class="pkt-contents" ${ref(this.defaultSlot)}></div>
189
+ <div class="pkt-contents">${slotContent(this)}</div>
201
190
  ${this.counterPosition === 'bottom' ? counterElement() : nothing}
202
191
  ${errorElement()}
203
192
  `
@@ -1,6 +1,5 @@
1
- import { PktElement } from '@/base-elements/element'
2
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
3
- import { ref, Ref, createRef } from 'lit/directives/ref.js'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
+ import { slotContent } from '@/directives/slot-content'
4
3
  import { html, nothing } from 'lit'
5
4
  import { classMap } from 'lit/directives/class-map.js'
6
5
  import { customElement, property } from 'lit/decorators.js'
@@ -8,14 +7,7 @@ import specs from 'componentSpecs/link.json'
8
7
  import '@/components/icon'
9
8
 
10
9
  @customElement('pkt-link')
11
- export class PktLink extends PktElement {
12
- defaultSlot: Ref<HTMLElement> = createRef()
13
-
14
- constructor() {
15
- super()
16
- this.slotController = new PktSlotController(this, this.defaultSlot)
17
- }
18
-
10
+ export class PktLink extends PktElementWithSlot {
19
11
  /**
20
12
  * Element attributes
21
13
  */
@@ -41,7 +33,7 @@ export class PktLink extends PktElement {
41
33
  .rel=${this.external ? 'noopener noreferrer' : nothing}
42
34
  >${this.iconName
43
35
  ? html`<pkt-icon name=${this.iconName} class="pkt-link__icon"></pkt-icon>`
44
- : ''} <span ${ref(this.defaultSlot)}>Link</span></a
36
+ : ''} <span>${slotContent(this)}</span></a
45
37
  >`
46
38
  }
47
39
  }
@@ -78,7 +78,7 @@ describe('PktLinkCard', () => {
78
78
 
79
79
  const textSlot = linkCard.querySelector('.pkt-linkcard__text')
80
80
  expect(textSlot).toBeInTheDocument()
81
- expect(textSlot?.innerHTML).toBe(content)
81
+ expect(textSlot?.innerHTML).toContain(content)
82
82
  })
83
83
  })
84
84
 
@@ -266,7 +266,7 @@ describe('PktLinkCard', () => {
266
266
  expect(icon?.getAttribute('name')).toBe(config.iconName)
267
267
 
268
268
  const textSlot = linkCard.querySelector('.pkt-linkcard__text')
269
- expect(textSlot?.innerHTML).toBe(config.content)
269
+ expect(textSlot?.innerHTML).toContain(config.content)
270
270
  })
271
271
 
272
272
  test('renders minimal configuration', async () => {
@@ -1,9 +1,7 @@
1
1
  import { html } from 'lit'
2
2
  import { customElement, property } from 'lit/decorators.js'
3
- import { ref } from 'lit/directives/ref.js'
4
- import { Ref, createRef } from 'lit/directives/ref.js'
5
- import { PktElement } from '@/base-elements/element'
6
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
3
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
4
+ import { slotContent } from '@/directives/slot-content'
7
5
  import '@/components/icon'
8
6
  import { ifDefined } from 'lit/directives/if-defined.js'
9
7
 
@@ -27,9 +25,7 @@ export interface IPktLinkCard {
27
25
  }
28
26
 
29
27
  @customElement('pkt-linkcard')
30
- export class PktLinkCard extends PktElement implements IPktLinkCard {
31
- defaultSlot: Ref<HTMLElement> = createRef()
32
-
28
+ export class PktLinkCard extends PktElementWithSlot implements IPktLinkCard {
33
29
  @property({ type: String, reflect: true }) title: string = ''
34
30
  @property({ type: String, reflect: true }) href: string = '#'
35
31
  @property({ type: String, reflect: true }) iconName: string = ''
@@ -37,11 +33,6 @@ export class PktLinkCard extends PktElement implements IPktLinkCard {
37
33
  @property({ type: Boolean, reflect: true }) openInNewTab: boolean = false
38
34
  @property({ type: String, reflect: true }) skin: TLinkCardSkin = 'normal'
39
35
 
40
- constructor() {
41
- super()
42
- this.slotController = new PktSlotController(this, this.defaultSlot)
43
- }
44
-
45
36
  render() {
46
37
  const classes = ['pkt-linkcard', this.skin && `pkt-linkcard--${this.skin}`]
47
38
  .filter(Boolean)
@@ -61,7 +52,7 @@ export class PktLinkCard extends PktElement implements IPktLinkCard {
61
52
  ${this.iconName && html`<pkt-icon class="pkt-link__icon" name="${this.iconName}" />`}
62
53
  ${this.title && html`<div class=${titleClasses}>${this.title}</div>`}
63
54
 
64
- <div class="pkt-linkcard__text" ${ref(this.defaultSlot)}></div>
55
+ <div class="pkt-linkcard__text">${slotContent(this)}</div>
65
56
  </a>
66
57
  `
67
58
  }
@@ -1,9 +1,8 @@
1
- import { PktElement } from '@/base-elements/element'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
2
  import { classMap } from 'lit/directives/class-map.js'
3
3
  import { customElement, property, state } from 'lit/decorators.js'
4
- import { createRef, ref, Ref } from 'lit/directives/ref.js'
5
4
  import { html, nothing } from 'lit'
6
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
5
+ import { slotContent } from '@/directives/slot-content'
7
6
  import { TPktSize } from '@/types/size'
8
7
  import '@/components/icon'
9
8
 
@@ -49,14 +48,7 @@ export interface IPktLoader {
49
48
  }
50
49
 
51
50
  @customElement('pkt-loader')
52
- export class PktLoader extends PktElement implements IPktLoader {
53
- defaultSlot: Ref<HTMLElement> = createRef()
54
-
55
- constructor() {
56
- super()
57
- this.slotController = new PktSlotController(this, this.defaultSlot)
58
- }
59
-
51
+ export class PktLoader extends PktElementWithSlot implements IPktLoader {
60
52
  @property({ type: Number }) delay: number = 0
61
53
  @property({ type: Boolean }) inline: boolean = false
62
54
  @property({ type: Boolean }) isLoading: boolean = true
@@ -110,7 +102,7 @@ export class PktLoader extends PktElement implements IPktLoader {
110
102
  ${this.message && html`<p>${this.message}</p>`}
111
103
  </div>`
112
104
  : nothing}
113
- <div class=${slotClasses} ${ref(this.defaultSlot)}></div>
105
+ <div class=${slotClasses}>${slotContent(this)}</div>
114
106
  </div>`
115
107
  }
116
108
 
@@ -1,7 +1,5 @@
1
- import { PktElement } from '@/base-elements/element'
2
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
3
- import { ref } from 'lit/directives/ref.js'
4
- import { Ref, createRef } from 'lit/directives/ref.js'
1
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
+ import { slotContent } from '@/directives/slot-content'
5
3
  import { html, nothing, PropertyValues } from 'lit'
6
4
  import { classMap } from 'lit/directives/class-map.js'
7
5
  import { customElement, property, state } from 'lit/decorators.js'
@@ -21,12 +19,9 @@ export interface IPktMessagebox {
21
19
  }
22
20
 
23
21
  @customElement('pkt-messagebox')
24
- export class PktMessagebox extends PktElement implements IPktMessagebox {
25
- defaultSlot: Ref<HTMLElement> = createRef()
26
-
22
+ export class PktMessagebox extends PktElementWithSlot implements IPktMessagebox {
27
23
  constructor() {
28
24
  super()
29
- this.slotController = new PktSlotController(this, this.defaultSlot)
30
25
  this._isClosed = false
31
26
  }
32
27
 
@@ -73,7 +68,7 @@ export class PktMessagebox extends PktElement implements IPktMessagebox {
73
68
  </div>`
74
69
  : nothing}
75
70
  ${this.title ? html`<div class="pkt-messagebox__title">${this.title}</div>` : nothing}
76
- <div class="pkt-messagebox__text" ${ref(this.defaultSlot)}></div>
71
+ <div class="pkt-messagebox__text">${slotContent(this)}</div>
77
72
  </div>`
78
73
  }
79
74
 
@@ -1,8 +1,8 @@
1
1
  import { classMap } from 'lit/directives/class-map.js'
2
2
  import { customElement, property, state } from 'lit/decorators.js'
3
3
  import { html, nothing, PropertyValues } from 'lit'
4
- import { PktElement } from '@/base-elements/element'
5
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
4
+ import { PktElementWithSlot } from '@/base-elements/element-with-slot'
5
+ import { slotContent } from '@/directives/slot-content'
6
6
  import { ref } from 'lit/directives/ref.js'
7
7
  import { Ref, createRef } from 'lit/directives/ref.js'
8
8
  import { TPktSize } from '@/types/size'
@@ -22,7 +22,7 @@ export interface IPktModal {
22
22
  }
23
23
 
24
24
  @customElement('pkt-modal')
25
- export class PktModal extends PktElement implements IPktModal {
25
+ export class PktModal extends PktElementWithSlot implements IPktModal {
26
26
  // Public properties"
27
27
  @property({ type: String }) headingText?: string = ''
28
28
  @property({ type: Boolean }) removePadding?: boolean = false
@@ -35,14 +35,12 @@ export class PktModal extends PktElement implements IPktModal {
35
35
  @property({ type: String }) drawerPosition?: 'left' | 'right' = 'right'
36
36
  @property({ type: Boolean }) transparentBackdrop?: boolean = false
37
37
 
38
- defaultSlot: Ref<HTMLElement> = createRef()
39
38
  dialogRef: Ref<HTMLDialogElement> = createRef()
40
39
 
41
40
  @state() _isOpen: boolean = false
42
41
 
43
42
  constructor() {
44
43
  super()
45
- this.slotController = new PktSlotController(this, this.defaultSlot)
46
44
  this._isOpen = false
47
45
  }
48
46
 
@@ -201,8 +199,7 @@ export class PktModal extends PktElement implements IPktModal {
201
199
  <div
202
200
  id="pkt-modal__content"
203
201
  class=${classMap(contentClasses)}
204
- ${ref(this.defaultSlot)}
205
- ></div>
202
+ >${slotContent(this)}</div>
206
203
  </div>
207
204
  </div>
208
205
  </dialog>
@@ -4,7 +4,7 @@ import { Ref, createRef, ref } from 'lit/directives/ref.js'
4
4
  import { ifDefined } from 'lit/directives/if-defined.js'
5
5
  import { PktOptionsInputElement } from '@/base-elements/options-input-element'
6
6
  import { PktOptionsSlotController } from '@/controllers/pkt-options-controller'
7
- import { PktSlotController } from '@/controllers/pkt-slot-controller'
7
+ import { slotContent } from '@/directives/slot-content'
8
8
  import '@/components/input-wrapper'
9
9
 
10
10
  export type TSelectOption = {
@@ -41,7 +41,6 @@ declare global {
41
41
  @customElement('pkt-select')
42
42
  export class PktSelect extends PktOptionsInputElement<{}, TSelectOption> implements IPktSelect {
43
43
  inputRef: Ref<HTMLSelectElement> = createRef()
44
- private helptextSlot: Ref<HTMLElement> = createRef()
45
44
 
46
45
  @property({ type: String }) value: string = ''
47
46
 
@@ -51,8 +50,6 @@ export class PktSelect extends PktOptionsInputElement<{}, TSelectOption> impleme
51
50
  constructor() {
52
51
  super()
53
52
  this.optionsController = new PktOptionsSlotController(this)
54
- this.slotController = new PktSlotController(this, this.helptextSlot)
55
- this.slotController.skipOptions = true
56
53
  }
57
54
 
58
55
  connectedCallback(): void {
@@ -251,7 +248,7 @@ export class PktSelect extends PktOptionsInputElement<{}, TSelectOption> impleme
251
248
  )
252
249
  : ''}
253
250
  </select>
254
- <div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
251
+ <div class="pkt-contents" slot="helptext">${slotContent(this, 'helptext')}</div>
255
252
  </pkt-input-wrapper>
256
253
  `
257
254
  }