@oslokommune/punkt-elements 18.3.1 → 18.5.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 (154) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/{accordion-4eAsO-Sr.js → accordion-D814csFx.js} +6 -6
  3. package/dist/{accordion-DOa5vubf.cjs → accordion-E0-pLzBq.cjs} +6 -6
  4. package/dist/{alert-DKNJTlMQ.js → alert-DNZtr3gd.js} +39 -31
  5. package/dist/alert-DqM9l5as.cjs +40 -0
  6. package/dist/{backlink-CA5R69FX.cjs → backlink-DYO8qA9C.cjs} +1 -1
  7. package/dist/{button-Dqolsuwj.js → button-Drwt7Qe5.js} +29 -26
  8. package/dist/button-jJfzE9C7.cjs +32 -0
  9. package/dist/{card-DgRvtnnk.js → card-BhmJZOGh.js} +90 -70
  10. package/dist/card-D-1JMn_h.cjs +64 -0
  11. package/dist/{combobox-q8kzy-S_.js → combobox-BNstYIC5.js} +20 -20
  12. package/dist/{combobox-D3zyAi_o.cjs → combobox-CRdBlMz1.cjs} +17 -17
  13. package/dist/components/alert/alert.d.ts +2 -0
  14. package/dist/components/button/button.d.ts +4 -21
  15. package/dist/components/button/index.d.ts +1 -1
  16. package/dist/components/card/card.d.ts +12 -3
  17. package/dist/components/index.d.ts +1 -1
  18. package/dist/components/linkcard/linkcard.d.ts +1 -1
  19. package/dist/components/loader/loader.d.ts +2 -2
  20. package/dist/components/messagebox/messagebox.d.ts +1 -1
  21. package/dist/components/progressbar/progressbar.d.ts +2 -6
  22. package/dist/{consent-Cqetmc5Q.cjs → consent-DaOFbopy.cjs} +1 -1
  23. package/dist/{consent-Dkyp-UbI.js → consent-Yvw7gZI_.js} +1 -1
  24. package/dist/{datepicker-8KnaI9Xj.cjs → datepicker-DjvL_Nb8.cjs} +16 -16
  25. package/dist/{datepicker-9ulmApjN.js → datepicker-DzTdWHkX.js} +3 -3
  26. package/dist/docs/components/button.d.ts +0 -1
  27. package/dist/{fileupload-XQAilDRd.js → fileupload-B8Uhfx2d.js} +24 -24
  28. package/dist/{fileupload-EWBE4h3V.cjs → fileupload-BJVYPl8u.cjs} +15 -15
  29. package/dist/{footer-BpuYmm5V.cjs → footer-BGC5PkLa.cjs} +1 -1
  30. package/dist/{footer-BXmN43ol.js → footer-BPxKLaut.js} +2 -2
  31. package/dist/{header-BPQHiw4v.js → header-BPzlBRhY.js} +30 -30
  32. package/dist/{header-BQ32MqUl.cjs → header-CAqegPzW.cjs} +34 -34
  33. package/dist/{header-menu-DpQbRKcm.cjs → header-menu-DBy7Yrd_.cjs} +1 -1
  34. package/dist/{header-menu-Dgem4HO9.js → header-menu-DWiPoQ58.js} +1 -1
  35. package/dist/{helptext-Ds8Q9IGV.cjs → helptext-BwDhf6VB.cjs} +2 -2
  36. package/dist/{helptext-BzLJKMMO.js → helptext-mf-67-fv.js} +2 -2
  37. package/dist/{input-wrapper-DzEgz7nZ.js → input-wrapper-BetB7OLQ.js} +16 -15
  38. package/dist/{input-wrapper-B0eSdZs3.cjs → input-wrapper-CS0qrYcm.cjs} +8 -7
  39. package/dist/{link-CpwR3BLX.cjs → link-DXnoMJIo.cjs} +3 -3
  40. package/dist/{link-C9xAIILf.js → link-DkO7a3Fs.js} +3 -3
  41. package/dist/{linkcard-Bzv3CEw5.cjs → linkcard-2l6z1M2U.cjs} +3 -3
  42. package/dist/{linkcard-C6ljKc0B.js → linkcard-aVKL5JPP.js} +8 -8
  43. package/dist/{loader-D6dau_7w.js → loader-CRVUJ-HU.js} +1 -1
  44. package/dist/{loader-Bv-1vwju.cjs → loader-D23kzlaR.cjs} +1 -1
  45. package/dist/{messagebox-CmhjIh0n.js → messagebox-CqI6_Ah7.js} +2 -2
  46. package/dist/{messagebox-DNUfv2FN.cjs → messagebox-DP06cyqc.cjs} +1 -1
  47. package/dist/pkt-accordion.cjs +1 -1
  48. package/dist/pkt-accordion.js +1 -1
  49. package/dist/pkt-alert.cjs +1 -1
  50. package/dist/pkt-alert.js +1 -1
  51. package/dist/pkt-backlink.cjs +1 -1
  52. package/dist/pkt-backlink.js +1 -1
  53. package/dist/pkt-button.cjs +1 -1
  54. package/dist/pkt-button.js +1 -1
  55. package/dist/pkt-card.cjs +1 -1
  56. package/dist/pkt-card.js +1 -1
  57. package/dist/pkt-combobox.cjs +1 -1
  58. package/dist/pkt-combobox.js +1 -1
  59. package/dist/pkt-consent.cjs +1 -1
  60. package/dist/pkt-consent.js +1 -1
  61. package/dist/pkt-datepicker.cjs +1 -1
  62. package/dist/pkt-datepicker.js +1 -1
  63. package/dist/pkt-fileupload.cjs +1 -1
  64. package/dist/pkt-fileupload.js +1 -1
  65. package/dist/pkt-footer.cjs +1 -1
  66. package/dist/pkt-footer.js +1 -1
  67. package/dist/pkt-header-menu.cjs +1 -1
  68. package/dist/pkt-header-menu.js +1 -1
  69. package/dist/pkt-header.cjs +1 -1
  70. package/dist/pkt-header.js +1 -1
  71. package/dist/pkt-helptext.cjs +1 -1
  72. package/dist/pkt-helptext.js +1 -1
  73. package/dist/pkt-index.cjs +1 -1
  74. package/dist/pkt-index.js +31 -31
  75. package/dist/pkt-input-wrapper.cjs +1 -1
  76. package/dist/pkt-input-wrapper.js +1 -1
  77. package/dist/pkt-link.cjs +1 -1
  78. package/dist/pkt-link.js +1 -1
  79. package/dist/pkt-linkcard.cjs +1 -1
  80. package/dist/pkt-linkcard.js +1 -1
  81. package/dist/pkt-loader.cjs +1 -1
  82. package/dist/pkt-loader.js +1 -1
  83. package/dist/pkt-messagebox.cjs +1 -1
  84. package/dist/pkt-messagebox.js +1 -1
  85. package/dist/pkt-progressbar.cjs +1 -1
  86. package/dist/pkt-progressbar.js +1 -1
  87. package/dist/pkt-radiobutton.cjs +1 -1
  88. package/dist/pkt-radiobutton.js +1 -1
  89. package/dist/pkt-searchinput.cjs +1 -1
  90. package/dist/pkt-searchinput.js +1 -1
  91. package/dist/pkt-select.cjs +1 -1
  92. package/dist/pkt-select.js +1 -1
  93. package/dist/pkt-tabs.cjs +1 -1
  94. package/dist/pkt-tabs.js +1 -1
  95. package/dist/pkt-tag.cjs +1 -1
  96. package/dist/pkt-tag.js +1 -1
  97. package/dist/pkt-textarea.cjs +1 -1
  98. package/dist/pkt-textarea.js +1 -1
  99. package/dist/pkt-textinput.cjs +1 -1
  100. package/dist/pkt-textinput.js +1 -1
  101. package/dist/pkt-timepicker.cjs +1 -1
  102. package/dist/pkt-timepicker.js +1 -1
  103. package/dist/progressbar-BPHLC7ce.js +117 -0
  104. package/dist/progressbar-BpcsDCnG.cjs +31 -0
  105. package/dist/{radiobutton-B_j_nYCC.js → radiobutton-B2e9Vyp8.js} +0 -1
  106. package/dist/{radiobutton-DsL-FNDd.cjs → radiobutton-C3nmL9rA.cjs} +0 -1
  107. package/dist/{searchinput-Dm3T0tGS.cjs → searchinput-CiPB8xvh.cjs} +3 -2
  108. package/dist/{searchinput-D7Dd2W2z.js → searchinput-DrUcPajl.js} +14 -12
  109. package/dist/{select-BqAZsLKy.js → select-B7TvZGIL.js} +15 -16
  110. package/dist/{select-VqzZdE-T.cjs → select-qxjHJ8bu.cjs} +13 -14
  111. package/dist/shared-types/button.d.ts +45 -0
  112. package/dist/shared-types/index.d.ts +2 -0
  113. package/dist/{tabs-DPdDkHSk.js → tabs-C_tCCdBK.js} +18 -18
  114. package/dist/{tabs-nvIpMwHK.cjs → tabs-DBanbSG1.cjs} +15 -15
  115. package/dist/tag-BDlwKjgT.cjs +27 -0
  116. package/dist/{tag-DBCzfbPE.js → tag-CdiDs9zb.js} +10 -10
  117. package/dist/{textarea-D17CiySU.cjs → textarea-DgFwd2LY.cjs} +10 -10
  118. package/dist/{textarea-C0a-K05x.js → textarea-YL6JYsB5.js} +14 -14
  119. package/dist/{textinput-D0QasOZ9.cjs → textinput-CIxMtaIo.cjs} +10 -10
  120. package/dist/{textinput-DKl04Y3e.js → textinput-CrJYDOHb.js} +12 -12
  121. package/dist/{timepicker-DVvI4uEk.js → timepicker-BHWOqlr8.js} +11 -11
  122. package/dist/{timepicker-BcnFL6Bj.cjs → timepicker-avaMu1hN.cjs} +8 -8
  123. package/package.json +2 -2
  124. package/src/components/accordion/accordion.ts +2 -1
  125. package/src/components/alert/alert.test.ts +2 -1
  126. package/src/components/alert/alert.ts +21 -3
  127. package/src/components/button/button.test.ts +0 -3
  128. package/src/components/button/button.ts +57 -62
  129. package/src/components/button/index.ts +0 -2
  130. package/src/components/card/card.test.ts +7 -7
  131. package/src/components/card/card.ts +99 -80
  132. package/src/components/helptext/helptext.ts +2 -2
  133. package/src/components/index.ts +0 -2
  134. package/src/components/input-wrapper/input-wrapper.ts +1 -0
  135. package/src/components/link/link.ts +4 -2
  136. package/src/components/linkcard/linkcard.test.ts +3 -3
  137. package/src/components/linkcard/linkcard.ts +1 -1
  138. package/src/components/loader/loader.test.ts +1 -1
  139. package/src/components/loader/loader.ts +3 -3
  140. package/src/components/messagebox/messagebox.test.ts +1 -1
  141. package/src/components/messagebox/messagebox.ts +2 -2
  142. package/src/components/progressbar/progressbar.test.ts +10 -8
  143. package/src/components/progressbar/progressbar.ts +63 -84
  144. package/src/components/radiobutton/radiobutton.ts +0 -1
  145. package/src/components/searchinput/searchinput.ts +3 -1
  146. package/src/components/select/select.test.ts +2 -1
  147. package/src/components/select/select.ts +0 -1
  148. package/dist/alert-BlHM1zEi.cjs +0 -35
  149. package/dist/button-CVMhQT3X.cjs +0 -30
  150. package/dist/card-DMKvuvNv.cjs +0 -87
  151. package/dist/progressbar-Bk_RsEjW.js +0 -112
  152. package/dist/progressbar-T5_MpZGN.cjs +0 -17
  153. package/dist/tag-Bp9gJnYh.cjs +0 -27
  154. package/dist/{backlink-BYUtL8cO.js → backlink-BHtxOlTw.js} +1 -1
@@ -1,7 +1,16 @@
1
1
  import { PktElementWithSlot } from '@/base-elements/element-with-slot'
2
2
  import { slotContent } from '@/directives/slot-content'
3
3
  import { PktIconName } from '@oslokommune/punkt-assets/dist/icons/icon'
4
- import type { Booleanish, THTMLButtonType } from 'shared-types'
4
+ import type {
5
+ Booleanish,
6
+ IPktButtonBase,
7
+ TPktButtonSize,
8
+ TPktButtonColor,
9
+ TPktButtonSkin,
10
+ TPktButtonVariant,
11
+ TPktButtonState,
12
+ THTMLButtonType,
13
+ } from 'shared-types'
5
14
  import { html, nothing, PropertyValues } from 'lit'
6
15
  import { property, customElement, state } from 'lit/decorators.js'
7
16
  import { classMap } from 'lit/directives/class-map.js'
@@ -15,48 +24,26 @@ const defaultAnimationPath = 'https://punkt-cdn.oslo.kommune.no/latest/animation
15
24
  if (typeof window !== 'undefined') {
16
25
  window.pktAnimationPath = window.pktAnimationPath || defaultAnimationPath
17
26
  }
18
- export type TPktButtonMode = 'light' | 'dark'
19
- export type TPktButtonSize = 'xsmall' | 'small' | 'medium' | 'large'
20
- export type TPktButtonColor =
21
- | 'blue'
22
- | 'blue-outline'
23
- | 'green'
24
- | 'green-outline'
25
- | 'green-dark'
26
- | 'green-dark-outline'
27
- | 'beige-light'
28
- | 'beige-dark-outline'
29
- | 'yellow'
30
- | 'yellow-outline'
31
- | 'red'
32
- | 'red-outline'
33
- export type TPktButtonSkin = 'primary' | 'secondary' | 'tertiary'
34
- export type TPktButtonVariant =
35
- | 'label-only'
36
- | 'icon-left'
37
- | 'icon-right'
38
- | 'icon-only'
39
- | 'icons-right-and-left'
40
- export type TPktButtonState = 'normal' | 'focus' | 'hover' | 'active'
41
- export type TPktButtonType = THTMLButtonType
42
-
43
- export interface IPktButton {
27
+
28
+ export type {
29
+ TPktButtonSize,
30
+ TPktButtonColor,
31
+ TPktButtonSkin,
32
+ TPktButtonVariant,
33
+ TPktButtonState,
34
+ }
35
+
36
+ export interface IPktButton
37
+ extends Omit<
38
+ IPktButtonBase,
39
+ 'iconName' | 'secondIconName' | 'fullWidth' | 'fullWidthOnMobile' | 'isLoading' | 'disabled'
40
+ > {
44
41
  iconName?: PktIconName
45
42
  secondIconName?: PktIconName
46
- iconPath?: string
47
- secondIconPath?: string
48
- mode?: TPktButtonMode
49
- size?: TPktButtonSize
50
43
  fullWidth?: Booleanish
51
44
  fullWidthOnMobile?: Booleanish
52
- color?: TPktButtonColor
53
- skin?: TPktButtonSkin
54
- variant?: TPktButtonVariant
55
- state?: TPktButtonState
56
- type?: TPktButtonType
57
45
  isLoading?: Booleanish
58
46
  disabled?: Booleanish
59
- loadingAnimationPath?: string
60
47
  }
61
48
  export class PktButton extends PktElementWithSlot<IPktButton> implements IPktButton {
62
49
  // Properties
@@ -64,7 +51,6 @@ export class PktButton extends PktElementWithSlot<IPktButton> implements IPktBut
64
51
  @property({ type: String }) secondIconName: string = 'user'
65
52
  @property({ type: String }) iconPath: string | undefined
66
53
  @property({ type: String }) secondIconPath: string | undefined
67
- @property({ type: String }) mode?: TPktButtonMode = 'light'
68
54
  @property({ type: String }) size: TPktButtonSize = 'medium'
69
55
  @property({ type: Boolean, attribute: 'full-width' }) fullWidth: Booleanish = false
70
56
  @property({ type: Boolean, attribute: 'full-width-on-mobile' }) fullWidthOnMobile: Booleanish =
@@ -72,8 +58,8 @@ export class PktButton extends PktElementWithSlot<IPktButton> implements IPktBut
72
58
  @property({ type: String }) color?: TPktButtonColor
73
59
  @property({ type: String }) skin: TPktButtonSkin = 'primary'
74
60
  @property({ type: String }) variant: TPktButtonVariant = 'label-only'
75
- @property({ type: String, reflect: true }) state?: TPktButtonState = 'normal'
76
- @property({ type: String, reflect: true }) type: TPktButtonType = 'button'
61
+ @property({ type: String, reflect: true }) state?: TPktButtonState = undefined
62
+ @property({ type: String, reflect: true }) type: THTMLButtonType = 'button'
77
63
  @property({ type: String }) form: string | undefined = undefined
78
64
  @property({ type: Boolean, reflect: true }) isLoading: Booleanish = false
79
65
  @property({ type: Boolean, reflect: true }) disabled: Booleanish = false
@@ -123,6 +109,8 @@ export class PktButton extends PktElementWithSlot<IPktButton> implements IPktBut
123
109
  'aria-haspopup',
124
110
  'aria-expanded',
125
111
  'aria-controls',
112
+ 'aria-label',
113
+ 'tabindex',
126
114
  ] as const
127
115
 
128
116
  @state() private relocatedAria: Record<string, string> = {}
@@ -167,7 +155,6 @@ export class PktButton extends PktElementWithSlot<IPktButton> implements IPktBut
167
155
  [`pkt-btn--${this.state}`]: !!this.state,
168
156
  'pkt-btn--full': !!this.fullWidth,
169
157
  'pkt-btn--full-small': !!this.fullWidthOnMobile,
170
- 'pkt-btn--disabled': !!this.disabled,
171
158
  'pkt-btn--isLoading': !!this.isLoading,
172
159
  }
173
160
 
@@ -181,30 +168,38 @@ export class PktButton extends PktElementWithSlot<IPktButton> implements IPktBut
181
168
  aria-haspopup=${ifDefined(this.relocatedAria['aria-haspopup'])}
182
169
  aria-expanded=${ifDefined(this.relocatedAria['aria-expanded'])}
183
170
  aria-controls=${ifDefined(this.relocatedAria['aria-controls'])}
171
+ aria-label=${ifDefined(this.relocatedAria['aria-label'])}
172
+ tabindex=${ifDefined(this.relocatedAria['tabindex'])}
184
173
  form=${ifDefined(formId)}
185
174
  >
186
- ${this.isLoading
187
- ? html`<pkt-icon
188
- class="pkt-btn__icon pkt-btn__spinner"
189
- name="spinner-blue"
190
- path=${ifDefined(this.loadingAnimationPath)}
191
- ></pkt-icon>`
192
- : nothing}
193
- ${this.variant !== 'label-only'
194
- ? html`<pkt-icon
195
- class="pkt-btn__icon pkt-icon"
196
- name=${this.iconName}
197
- path=${ifDefined(this.iconPath)}
198
- ></pkt-icon>`
199
- : nothing}
175
+ ${
176
+ this.isLoading
177
+ ? html`<pkt-icon
178
+ class="pkt-btn__icon pkt-btn__spinner"
179
+ name="spinner-blue"
180
+ path=${ifDefined(this.loadingAnimationPath)}
181
+ ></pkt-icon>`
182
+ : nothing
183
+ }
184
+ ${
185
+ this.variant !== 'label-only'
186
+ ? html`<pkt-icon
187
+ class="pkt-btn__icon pkt-icon"
188
+ name=${this.iconName}
189
+ path=${ifDefined(this.iconPath)}
190
+ ></pkt-icon>`
191
+ : nothing
192
+ }
200
193
  <span class="pkt-btn__text">${slotContent(this)}</span>
201
- ${this.variant === 'icons-right-and-left'
202
- ? html`<pkt-icon
203
- class="pkt-btn__icon"
204
- name=${this.secondIconName}
205
- path=${ifDefined(this.secondIconPath)}
206
- ></pkt-icon>`
207
- : nothing}
194
+ ${
195
+ this.variant === 'icons-right-and-left'
196
+ ? html`<pkt-icon
197
+ class="pkt-btn__icon"
198
+ name=${this.secondIconName}
199
+ path=${ifDefined(this.secondIconPath)}
200
+ ></pkt-icon>`
201
+ : nothing
202
+ }
208
203
  </button>
209
204
  `
210
205
  }
@@ -2,13 +2,11 @@ import { PktButton } from './button'
2
2
 
3
3
  export type {
4
4
  IPktButton,
5
- TPktButtonMode,
6
5
  TPktButtonSize,
7
6
  TPktButtonColor,
8
7
  TPktButtonSkin,
9
8
  TPktButtonVariant,
10
9
  TPktButtonState,
11
- TPktButtonType,
12
10
  } from './button'
13
11
 
14
12
  export { PktButton }
@@ -106,7 +106,7 @@ describe('PktCard', () => {
106
106
  expect(card.tagPosition).toBe('top')
107
107
  expect(card.imageShape).toBe('square')
108
108
  expect(card.openLinkInNewTab).toBe(false)
109
- expect(card.headinglevel).toBe(3)
109
+ expect(card.headingLevel).toBe(3)
110
110
 
111
111
  const article = card.querySelector('article')
112
112
  expect(article).toHaveClass('pkt-card--outlined')
@@ -220,9 +220,9 @@ describe('PktCard', () => {
220
220
 
221
221
  expect(card.heading).toBe('Test Card Title')
222
222
 
223
- const heading = card.querySelector('pkt-heading')
223
+ const heading = card.querySelector('.pkt-card__heading')
224
224
  expect(heading).toBeInTheDocument()
225
- expect(heading).toHaveClass('pkt-card__heading')
225
+ expect(heading?.tagName).toBe('H3')
226
226
  expect(heading?.textContent?.trim()).toBe('Test Card Title')
227
227
  })
228
228
 
@@ -241,10 +241,10 @@ describe('PktCard', () => {
241
241
  const { card } = await createCardTest({ heading: 'Test', headingLevel: 2 })
242
242
  await card.updateComplete
243
243
 
244
- expect(card.headinglevel).toBe(2)
244
+ expect(card.headingLevel).toBe(2)
245
245
 
246
- const heading = card.querySelector('pkt-heading')
247
- expect(heading?.getAttribute('level')).toBe('2')
246
+ const heading = card.querySelector('.pkt-card__heading')
247
+ expect(heading?.tagName).toBe('H2')
248
248
  })
249
249
 
250
250
  test('does not render header when no heading or subheading', async () => {
@@ -263,7 +263,7 @@ describe('PktCard', () => {
263
263
 
264
264
  expect(card.clickCardLink).toBe(null)
265
265
 
266
- const heading = card.querySelector('pkt-heading')
266
+ const heading = card.querySelector('.pkt-card__heading')
267
267
  const link = card.querySelector('.pkt-card__link')
268
268
  expect(heading).toBeInTheDocument()
269
269
  expect(link).not.toBeInTheDocument()
@@ -8,14 +8,14 @@ import { slotContent } from '@/directives/slot-content'
8
8
  import { IPktHeading } from '../heading'
9
9
  import specs from 'componentSpecs/card.json'
10
10
  import '@/components/icon'
11
- /* eslint-disable no-duplicate-imports -- There's a different between the import methods */
11
+
12
12
  import '@/components/tag'
13
- import '@/components/heading'
14
13
  import type { IAriaAttributes, TCardSkin, TLayout } from 'shared-types'
15
14
 
16
15
  export type { TCardSkin, TLayout }
17
16
  export type TCardPadding = 'none' | 'default'
18
17
  export type TCardImageShape = 'square' | 'round'
18
+ export type TCardImageAspect = 'auto' | '1-1' | '4-3' | '3-2' | '16-9' | '19-10'
19
19
  export type TCardTagPosition = 'top' | 'bottom'
20
20
 
21
21
  export interface IPktCard {
@@ -27,9 +27,12 @@ export interface IPktCard {
27
27
  headingLevel?: IPktHeading['level']
28
28
  image?: { src: string; alt: string }
29
29
  imageShape?: TCardImageShape
30
+ imageAspect?: TCardImageAspect | null
31
+ restrictImageHeight?: boolean | null
30
32
  clickCardLink?: string | null
31
33
  openLinkInNewTab?: boolean | null
32
34
  borderOnHover?: boolean | null
35
+ zoom?: boolean | null
33
36
  padding?: TCardPadding
34
37
  skin?: TCardSkin
35
38
  subheading?: string
@@ -43,11 +46,16 @@ export class PktCard extends PktElementWithSlot implements IPktCard {
43
46
  @property({ type: String }) ariaLabel: string = ''
44
47
  @property({ type: String }) metaLead: string | null = null
45
48
  @property({ type: Boolean }) borderOnHover: boolean = true
49
+ @property({ type: Boolean }) zoom: boolean = false
50
+ @property({ type: String }) imageAspect: TCardImageAspect | null = null
51
+ @property({ type: Boolean }) restrictImageHeight: boolean = false
46
52
  @property({ type: String, reflect: true }) clickCardLink: IPktCard['clickCardLink'] = null
47
53
  @property({ type: String }) metaTrail: string | null = null
48
54
  @property({ type: String }) layout: TLayout = specs.props.layout.default as TLayout
49
55
  @property({ type: String }) heading: string = ''
50
- @property({ type: Number }) headinglevel: IPktHeading['level'] = 3
56
+ // Attributtet beholder gamle `headinglevel` eksisterende markup ikke brekker.
57
+ @property({ type: Number, attribute: 'headinglevel' })
58
+ headingLevel: IPktHeading['level'] = 3
51
59
  @property({ type: Object }) image: { src: string; alt: string } = {
52
60
  src: '',
53
61
  alt: '',
@@ -97,6 +105,7 @@ export class PktCard extends PktElementWithSlot implements IPktCard {
97
105
  [`pkt-card--${this.layout}`]: this.layout,
98
106
  [`pkt-card--padding-${this.padding}`]: this.padding,
99
107
  [`pkt-card--border-on-hover`]: this.borderOnHover,
108
+ [`pkt-card--zoom`]: this.zoom,
100
109
 
101
110
  }
102
111
 
@@ -127,59 +136,61 @@ export class PktCard extends PktElementWithSlot implements IPktCard {
127
136
  const imageClasses = {
128
137
  'pkt-card__image': true,
129
138
  [`pkt-card__image-${this.imageShape}`]: this.imageShape,
139
+ [`pkt-card__image-aspect-${this.imageAspect}`]: Boolean(this.imageAspect),
140
+ 'pkt-card__image-restricted': this.restrictImageHeight,
130
141
  }
131
142
 
132
143
  return html`
133
- ${this.image.src &&
134
- html`
135
- <div class=${classMap(imageClasses)}>
136
- <img src=${this.image.src} alt=${this.image.alt || ''} />
137
- </div>
138
- `}
144
+ ${
145
+ this.image.src &&
146
+ html`
147
+ <div class=${classMap(imageClasses)}>
148
+ <img src=${this.image.src} alt=${this.image.alt || ''} />
149
+ </div>
150
+ `
151
+ }
139
152
  `
140
153
  }
141
154
 
155
+ private renderHeadingTag(classes: string, content: unknown) {
156
+ const level =
157
+ this.headingLevel && this.headingLevel >= 1 && this.headingLevel <= 6 ? this.headingLevel : 3
158
+ // Bruker pkt-heading sine klasser her, for å unngå forskjeller i markup
159
+ const all = `pkt-heading pkt-heading--medium pkt-heading--fw-regular ${classes}`
160
+ switch (level) {
161
+ case 1:
162
+ return html`<h1 class=${all}>${content}</h1>`
163
+ case 2:
164
+ return html`<h2 class=${all}>${content}</h2>`
165
+ case 4:
166
+ return html`<h4 class=${all}>${content}</h4>`
167
+ case 5:
168
+ return html`<h5 class=${all}>${content}</h5>`
169
+ case 6:
170
+ return html`<h6 class=${all}>${content}</h6>`
171
+ default:
172
+ return html`<h3 class=${all}>${content}</h3>`
173
+ }
174
+ }
175
+
142
176
  // Do not render heading if link is present, render link heading instead
143
- // Combine the rendering for headings into a renderHeader method
144
177
  renderHeading() {
145
- return html`
146
- ${this.heading && !this.clickCardLink
147
- ? html`
148
- <pkt-heading
149
- class="pkt-card__heading"
150
- .level=${this.headinglevel || 3}
151
- size="medium"
152
- nospacing
153
- weight="regular"
154
- >
155
- ${this.heading}
156
- </pkt-heading>
157
- `
158
- : nothing}
159
- `
178
+ if (!this.heading || this.clickCardLink) return nothing
179
+ return this.renderHeadingTag('pkt-card__heading', this.heading)
160
180
  }
161
181
 
162
182
  renderLinkHeading() {
163
- return html`
164
- ${this.clickCardLink
165
- ? html`
166
- <pkt-heading
167
- class="pkt-card__link-heading pkt-card__heading"
168
- .level=${this.headinglevel || 3}
169
- size="medium"
170
- weight="regular"
171
- nospacing
172
- >
173
- <a
174
- class="pkt-card__link"
175
- href=${this.clickCardLink}
176
- target=${this.openLinkInNewTab ? '_blank' : '_self'}
177
- >${this.heading}</a
178
- >
179
- </pkt-heading>
180
- `
181
- : nothing}
182
- `
183
+ if (!this.clickCardLink) return nothing
184
+ return this.renderHeadingTag(
185
+ 'pkt-card__link-heading pkt-card__heading',
186
+ html`<a
187
+ class="pkt-card__link"
188
+ href=${this.clickCardLink}
189
+ target=${this.openLinkInNewTab ? '_blank' : '_self'}
190
+ rel=${ifDefined(this.openLinkInNewTab ? 'noopener noreferrer' : undefined)}
191
+ >${this.heading}</a
192
+ >`,
193
+ )
183
194
  }
184
195
 
185
196
  renderSubheading() {
@@ -212,29 +223,31 @@ export class PktCard extends PktElementWithSlot implements IPktCard {
212
223
  [`pkt-card__tags-${this.tagPosition}`]: this.tagPosition,
213
224
  }
214
225
  return html`
215
- ${this.tags.length > 0
216
- ? html`
217
- <div
218
- class=${classMap(tagClasses)}
219
- role="list"
220
- aria-label=${this.tags.length > 1 ? 'merkelapper' : 'merkelapp'}
221
- >
222
- ${this.tags.map(
223
- (tag) => html`
224
- <pkt-tag
225
- role="listitem"
226
- textStyle="normal-text"
227
- size="medium"
228
- skin=${ifDefined(tag.skin)}
229
- iconName=${ifDefined(tag.iconName)}
230
- >
231
- <span>${tag.text}</span>
232
- </pkt-tag>
233
- `,
234
- )}
235
- </div>
236
- `
237
- : nothing}
226
+ ${
227
+ this.tags.length > 0
228
+ ? html`
229
+ <div
230
+ class=${classMap(tagClasses)}
231
+ role="list"
232
+ aria-label=${this.tags.length > 1 ? 'merkelapper' : 'merkelapp'}
233
+ >
234
+ ${this.tags.map(
235
+ (tag) => html`
236
+ <pkt-tag
237
+ role="listitem"
238
+ textStyle="normal-text"
239
+ size="medium"
240
+ skin=${ifDefined(tag.skin)}
241
+ iconName=${ifDefined(tag.iconName)}
242
+ >
243
+ <span>${tag.text}</span>
244
+ </pkt-tag>
245
+ `,
246
+ )}
247
+ </div>
248
+ `
249
+ : nothing
250
+ }
238
251
  `
239
252
  }
240
253
 
@@ -244,18 +257,24 @@ export class PktCard extends PktElementWithSlot implements IPktCard {
244
257
 
245
258
  renderMetadata() {
246
259
  return html`
247
- ${this.metaLead || this.metaTrail
248
- ? html`
249
- <footer class="pkt-card__metadata">
250
- ${this.metaLead
251
- ? html`<span class="pkt-card__metadata-lead">${this.metaLead}</span>`
252
- : nothing}
253
- ${this.metaTrail
254
- ? html`<span class="pkt-card__metadata-trail">${this.metaTrail}</span>`
255
- : nothing}
256
- </footer>
257
- `
258
- : nothing}
260
+ ${
261
+ this.metaLead || this.metaTrail
262
+ ? html`
263
+ <footer class="pkt-card__metadata">
264
+ ${
265
+ this.metaLead
266
+ ? html`<span class="pkt-card__metadata-lead">${this.metaLead}</span>`
267
+ : nothing
268
+ }
269
+ ${
270
+ this.metaTrail
271
+ ? html`<span class="pkt-card__metadata-trail">${this.metaTrail}</span>`
272
+ : nothing
273
+ }
274
+ </footer>
275
+ `
276
+ : nothing
277
+ }
259
278
  `
260
279
  }
261
280
  }
@@ -77,8 +77,8 @@ export class PktHelptext extends PktElementWithSlot<IPktStringsProps<'forms'>> {
77
77
  const helptextElement = () => {
78
78
  return html`<div class="${helptextClasses}">
79
79
  <div class="pkt-inputwrapper__helptext" id="${this.forId}-helptext">
80
- <div class="pkt-contents" name="helptext">${slotContent(this)}</div>
81
- ${this.helptext && unsafeHTML(this.helptext)}
80
+ <div class="pkt-contents">${slotContent(this)}</div>
81
+ ${this.helptext ? html`<span>${unsafeHTML(this.helptext)}</span>` : nothing}
82
82
  </div>
83
83
  ${helptextDropdown()}
84
84
  </div>`
@@ -46,13 +46,11 @@ export type { IPktAccordion, IPktAccordionItem, TPktAccordionSkin } from '@/comp
46
46
 
47
47
  export type {
48
48
  IPktButton,
49
- TPktButtonMode,
50
49
  TPktButtonSize,
51
50
  TPktButtonColor,
52
51
  TPktButtonSkin,
53
52
  TPktButtonVariant,
54
53
  TPktButtonState,
55
- TPktButtonType,
56
54
  } from '@/components/button'
57
55
 
58
56
  export type {
@@ -193,6 +193,7 @@ export class PktInputWrapper extends PktElementWithSlot<Props> {
193
193
  <pkt-alert
194
194
  skin="error"
195
195
  .size=${errorAlertSize}
196
+ .role=${'alert'}
196
197
  id=${`${this.forId}-error`}
197
198
  aria-live="assertive"
198
199
  aria-atomic="true"
@@ -30,14 +30,16 @@ export class PktLink extends PktElementWithSlot {
30
30
  'pkt-link--icon-right': !!this.iconName && this.iconPosition === 'right',
31
31
  'pkt-link--external': this.external,
32
32
  }
33
+ const target = this.target && this.target !== '_self' ? this.target : nothing
34
+
33
35
  return html`<a
34
36
  class=${classMap(classes)}
35
37
  href=${this.href}
36
- .target=${this.target}
38
+ target=${target}
37
39
  .rel=${this.external ? 'noopener noreferrer' : nothing}
38
40
  >${this.iconName
39
41
  ? html`<pkt-icon name=${this.iconName} class="pkt-link__icon"></pkt-icon>`
40
- : ''} <span>${slotContent(this)}</span></a
42
+ : ''}${slotContent(this)}</a
41
43
  >`
42
44
  }
43
45
  }
@@ -64,7 +64,7 @@ describe('PktLinkCard', () => {
64
64
  expect(linkCard.href).toBe('#')
65
65
  expect(linkCard.iconName).toBe('')
66
66
  expect(linkCard.openInNewTab).toBe(false)
67
- expect(linkCard.skin).toBe('normal')
67
+ expect(linkCard.skin).toBeUndefined()
68
68
  expect(linkCard.external).toBe(false)
69
69
 
70
70
  expect(link.getAttribute('href')).toBe('#')
@@ -209,7 +209,7 @@ describe('PktLinkCard', () => {
209
209
  test('applies default skin class', async () => {
210
210
  const { link } = await createLinkCardTest()
211
211
  expect(link).toHaveClass('pkt-linkcard')
212
- expect(link).toHaveClass('pkt-linkcard--normal')
212
+ expect(link).not.toHaveClass('pkt-linkcard--normal')
213
213
  })
214
214
 
215
215
  test('applies different skin classes correctly', async () => {
@@ -312,7 +312,7 @@ describe('PktLinkCard', () => {
312
312
 
313
313
  expect(linkCard.href).toBe('/minimal')
314
314
  expect(link.getAttribute('href')).toBe('/minimal')
315
- expect(link).toHaveClass('pkt-linkcard--normal')
315
+ expect(link).not.toHaveClass('pkt-linkcard--normal')
316
316
 
317
317
  // Should not have title or icon
318
318
  expect(linkCard.querySelector('.pkt-linkcard__title')).not.toBeInTheDocument()
@@ -16,7 +16,7 @@ export class PktLinkCard extends PktElementWithSlot<IPktLinkCard> implements IPk
16
16
  @property({ type: String, reflect: true }) iconName: string = ''
17
17
  @property({ type: Boolean, reflect: true }) external: boolean = false
18
18
  @property({ type: Boolean, reflect: true }) openInNewTab: boolean = false
19
- @property({ type: String, reflect: true }) skin: TLinkCardSkin = 'normal'
19
+ @property({ type: String, reflect: true }) skin?: TLinkCardSkin = undefined
20
20
 
21
21
  render() {
22
22
  const classes = ['pkt-linkcard', this.skin && `pkt-linkcard--${this.skin}`]
@@ -83,7 +83,7 @@ describe('PktLoader', () => {
83
83
  expect(loader.isLoading).toBe(true)
84
84
  expect(loader.inline).toBe(false)
85
85
  expect(loader.size).toBe('medium')
86
- expect(loader.variant).toBe('shapes')
86
+ expect(loader.variant).toBe('rainbow')
87
87
  expect(loader.delay).toBe(0)
88
88
  })
89
89
 
@@ -40,8 +40,8 @@ export interface IPktLoader {
40
40
  */
41
41
  size?: TPktSize
42
42
  /**
43
- * The variant of the loader. Default is "shapes" which is the OSLO wave loader.
44
- * Other variants are "blue" and "rainbow" which are spinner variants.
43
+ * The variant of the loader. Default is "rainbow".
44
+ * "shapes" is the OSLO wave loader, "blue" a blue spinner.
45
45
  */
46
46
  variant?: TPktLoaderVariant
47
47
  /**
@@ -56,7 +56,7 @@ export class PktLoader extends PktElementWithSlot implements IPktLoader {
56
56
  @property({ type: Boolean }) isLoading: boolean = true
57
57
  @property({ type: String }) message: string | null = null
58
58
  @property({ type: String }) size: TPktSize = 'medium'
59
- @property({ type: String }) variant: TPktLoaderVariant = 'shapes'
59
+ @property({ type: String }) variant: TPktLoaderVariant = 'rainbow'
60
60
  @property({ type: String }) loadingAnimationPath: string | undefined =
61
61
  typeof window !== 'undefined' ? window.pktAnimationPath : defaultAnimationPath
62
62
 
@@ -72,7 +72,7 @@ describe('PktMessagebox', () => {
72
72
  expect(messagebox.closable).toBe(false)
73
73
  expect(messagebox.compact).toBe(false)
74
74
  expect(messagebox.title).toBe('')
75
- expect(messagebox.skin).toBe('beige')
75
+ expect(messagebox.skin).toBeUndefined()
76
76
  })
77
77
 
78
78
  test('sets properties correctly', async () => {
@@ -29,7 +29,7 @@ export class PktMessagebox extends PktElementWithSlot implements IPktMessagebox
29
29
  @property({ type: Boolean, reflect: true }) closable = specs.props.closable.default
30
30
  @property({ type: Boolean, reflect: true }) compact = specs.props.compact.default
31
31
  @property({ type: String, reflect: true }) title = ''
32
- @property({ type: String, reflect: true }) skin = specs.props.skin.default as TMessageboxSkin
32
+ @property({ type: String, reflect: true }) skin?: TMessageboxSkin = undefined
33
33
 
34
34
  @state() _isClosed: boolean = false
35
35
 
@@ -49,7 +49,7 @@ export class PktMessagebox extends PktElementWithSlot implements IPktMessagebox
49
49
  const classes = {
50
50
  'pkt-messagebox': true,
51
51
  'pkt-messagebox--compact': this.compact,
52
- [`pkt-messagebox--${this.skin}`]: this.skin,
52
+ [`pkt-messagebox--${this.skin}`]: !!this.skin,
53
53
  'pkt-messagebox--closable': this.closable,
54
54
  'pkt-hide': this._isClosed,
55
55
  }