@oslokommune/punkt-elements 19.8.0 → 19.10.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/CHANGELOG.md +35 -0
- package/dist/accordion-CMCCpxtz.cjs +47 -0
- package/dist/{accordion-BJh6X1Ek.js → accordion-Cp2o6wTY.js} +10 -9
- package/dist/{alert-WME3geaX.js → alert-CAPiwi4F.js} +5 -5
- package/dist/{alert-CKqtC9AM.cjs → alert-QfloIr-o.cjs} +1 -1
- package/dist/{async-directive-BGoo_npW.cjs → async-directive-DpyKp6qv.cjs} +1 -1
- package/dist/{async-directive-DsdqP_X7.js → async-directive-yh8hG41Q.js} +2 -2
- package/dist/{backlink-BRqhwUr2.cjs → backlink-CsFeerTH.cjs} +1 -1
- package/dist/{backlink-BslFewn-.js → backlink-ogvv493Y.js} +3 -3
- package/dist/base-elements/input-element.d.ts +17 -0
- package/dist/base-elements/option-group-element.d.ts +61 -0
- package/dist/base-elements/polyfill-form-value.test.d.ts +0 -0
- package/dist/{breadcrumbs-Cr3GugPv.js → breadcrumbs-53QVnTFP.js} +2 -2
- package/dist/{breadcrumbs-DG4i5UCh.cjs → breadcrumbs-D03id_ha.cjs} +1 -1
- package/dist/{button-B78im4wB.js → button-CeRr7oIn.js} +5 -5
- package/dist/{button-BNVTj7nB.cjs → button-Dh97H-58.cjs} +1 -1
- package/dist/{calendar-TcxvS-1_.cjs → calendar-C5QwPrbk.cjs} +1 -1
- package/dist/{calendar-BLaRXUBl.js → calendar-D9w8M99G.js} +3 -3
- package/dist/{card-CaLEuumN.cjs → card--NuWdTbG.cjs} +1 -1
- package/dist/{card-CYKhPUNI.js → card-_PlgXmgZ.js} +6 -6
- package/dist/{checkbox-Tq8ESzwH.js → checkbox-G8k3vg85.js} +39 -35
- package/dist/checkbox-QIcdn09A.cjs +40 -0
- package/dist/checkbox-group-DoueGGi5.js +50 -0
- package/dist/checkbox-group-nLazAkcg.cjs +1 -0
- package/dist/checkbox-group.d.ts +1 -0
- package/dist/{class-map-C4hdfSfY.js → class-map-Bf-QzUpN.js} +1 -1
- package/dist/{class-map-Drv0_anQ.cjs → class-map-Bh6toDeV.cjs} +1 -1
- package/dist/{combobox-89Ohd1Oe.cjs → combobox-ClXhKwR9.cjs} +1 -1
- package/dist/{combobox-Cpb67TV0.js → combobox-Cz_rq7Mm.js} +13 -13
- package/dist/components/checkbox/checkbox.d.ts +1 -0
- package/dist/components/checkbox-group/checkbox-group-context.d.ts +5 -0
- package/dist/components/checkbox-group/checkbox-group.d.ts +15 -0
- package/dist/components/checkbox-group/checkbox-group.test.d.ts +0 -0
- package/dist/components/checkbox-group/index.d.ts +3 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/radio-group/index.d.ts +3 -0
- package/dist/components/radio-group/radio-group-context.d.ts +7 -0
- package/dist/components/radio-group/radio-group.d.ts +14 -0
- package/dist/components/radio-group/radio-group.test.d.ts +0 -0
- package/dist/components/radiobutton/index.d.ts +1 -0
- package/dist/components/radiobutton/radiobutton.d.ts +8 -2
- package/dist/{consent-CleJMbVH.js → consent-CZMxUavj.js} +2 -2
- package/dist/{consent-Dl-R0iC3.cjs → consent-DimzcQxt.cjs} +1 -1
- package/dist/consume-Bp12si68.js +61 -0
- package/dist/consume-kEjgTrAp.cjs +1 -0
- package/dist/{datepicker-DBEKa1aJ.js → datepicker-C7ABsx7H.js} +12 -12
- package/dist/{datepicker-B9NCJX4o.cjs → datepicker-usIF9WY7.cjs} +2 -2
- package/dist/{directive-helpers-BRrz3Bcj.cjs → directive-helpers-Bv70GjQh.cjs} +1 -1
- package/dist/{directive-helpers-D96YEsht.js → directive-helpers-CwxFepWh.js} +1 -1
- package/dist/directives/slot-content.d.ts +4 -3
- package/dist/docs/components/checkbox-group.d.ts +13 -0
- package/dist/docs/components/radio-group.d.ts +13 -0
- package/dist/{element-BOmr9YLv.cjs → element-C6WTyJFE.cjs} +1 -1
- package/dist/{element-mwwC2Rra.js → element-DBugHPKM.js} +1 -0
- package/dist/{element-with-slot-DQv0cbbD.js → element-with-slot-DDLS-aLw.js} +6 -3
- package/dist/element-with-slot-DhiAuSjM.cjs +1 -0
- package/dist/{fileupload-2YAbjYuU.cjs → fileupload-2uTFjd81.cjs} +1 -1
- package/dist/{fileupload-DqWCXMPz.js → fileupload-BR9H6fET.js} +8 -8
- package/dist/{footer-DdLls3F-.js → footer-B3DMvo8-.js} +4 -4
- package/dist/{footer-vy9NqT65.cjs → footer-CyxRYvT-.cjs} +1 -1
- package/dist/{header-Dp0Lq7wS.js → header-BKeSkfB7.js} +11 -11
- package/dist/{header-9Y6Q6Cfq.cjs → header-Drj3lTrv.cjs} +1 -1
- package/dist/{header-menu-BfkCp8jw.cjs → header-menu-B_5hCNUl.cjs} +1 -1
- package/dist/{header-menu-ANj5nL2M.js → header-menu-buYE90FU.js} +4 -4
- package/dist/{heading-zoz-QZJ9.cjs → heading-DUYOvlxs.cjs} +1 -1
- package/dist/{heading-CUrZvkrM.js → heading-WBB5MO9i.js} +2 -2
- package/dist/{helptext-BCkwSz1m.cjs → helptext-C7cyihnu.cjs} +1 -1
- package/dist/{helptext-DCT_9dw1.js → helptext-DadLkcoO.js} +4 -4
- package/dist/{icon-JigbxxF7.js → icon-Bao96Zb8.js} +1 -1
- package/dist/{icon-Dnv6LtPC.cjs → icon-jPhyZD1z.cjs} +1 -1
- package/dist/if-defined-CiML3MTM.cjs +1 -0
- package/dist/{if-defined-Bebu3LXY.js → if-defined-O59_I-e-.js} +1 -1
- package/dist/{input-element-lLzfwdim.js → input-element-BBygBEei.js} +54 -17
- package/dist/input-element-C4SelHLD.cjs +1 -0
- package/dist/{input-wrapper-CTMf4kCK.cjs → input-wrapper-BT6B3Kco.cjs} +6 -2
- package/dist/{input-wrapper-C9K-_7g-.js → input-wrapper-DrSCuw6U.js} +12 -8
- package/dist/{link-LO_5_La8.cjs → link-CEP7w1et.cjs} +1 -1
- package/dist/{link-CmZwAw5u.js → link-CVnIn74-.js} +4 -4
- package/dist/{linkcard-UKsxADrP.cjs → linkcard-D8vitdrQ.cjs} +1 -1
- package/dist/{linkcard-CQluSyJJ.js → linkcard-IWiVvRKy.js} +4 -4
- package/dist/{listbox-Ct9jIV_5.js → listbox-BDesthOp.js} +4 -4
- package/dist/{listbox-g-vHHLkD.cjs → listbox-CvduK_YU.cjs} +1 -1
- package/dist/{loader-C_PH05aw.cjs → loader-B0hFoBtF.cjs} +1 -1
- package/dist/{loader-DzctJ9jW.js → loader-CAsUPHjl.js} +4 -4
- package/dist/{messagebox-D17GYxb9.js → messagebox-6_iNN5F3.js} +4 -4
- package/dist/{messagebox-X01V2l_N.cjs → messagebox-C19L2Duq.cjs} +1 -1
- package/dist/{modal-BymjMIJi.cjs → modal-CoEPzt4p.cjs} +1 -1
- package/dist/{modal-CELmA0-8.js → modal-D7MolBXb.js} +5 -5
- package/dist/option-group-element-BIuotbRu.js +135 -0
- package/dist/option-group-element-BYS7s-is.cjs +23 -0
- package/dist/pkt-accordion.cjs +1 -1
- package/dist/pkt-accordion.js +1 -1
- package/dist/pkt-alert.cjs +1 -1
- package/dist/pkt-alert.js +1 -1
- package/dist/pkt-backlink.cjs +1 -1
- package/dist/pkt-backlink.js +1 -1
- package/dist/pkt-breadcrumbs.cjs +1 -1
- package/dist/pkt-breadcrumbs.js +1 -1
- package/dist/pkt-button.cjs +1 -1
- package/dist/pkt-button.js +1 -1
- package/dist/pkt-calendar.cjs +1 -1
- package/dist/pkt-calendar.js +1 -1
- package/dist/pkt-card.cjs +1 -1
- package/dist/pkt-card.js +1 -1
- package/dist/pkt-checkbox-group.cjs +1 -0
- package/dist/pkt-checkbox-group.js +2 -0
- package/dist/pkt-checkbox.cjs +1 -1
- package/dist/pkt-checkbox.js +1 -1
- package/dist/pkt-combobox.cjs +1 -1
- package/dist/pkt-combobox.js +1 -1
- package/dist/pkt-consent.cjs +1 -1
- package/dist/pkt-consent.js +1 -1
- package/dist/pkt-datepicker.cjs +1 -1
- package/dist/pkt-datepicker.js +1 -1
- package/dist/pkt-fileupload.cjs +1 -1
- package/dist/pkt-fileupload.js +1 -1
- package/dist/pkt-footer.cjs +1 -1
- package/dist/pkt-footer.js +1 -1
- package/dist/pkt-header-menu.cjs +1 -1
- package/dist/pkt-header-menu.js +1 -1
- package/dist/pkt-header.cjs +1 -1
- package/dist/pkt-header.js +1 -1
- package/dist/pkt-heading.cjs +1 -1
- package/dist/pkt-heading.js +1 -1
- package/dist/pkt-helptext.cjs +1 -1
- package/dist/pkt-helptext.js +1 -1
- package/dist/pkt-icon.cjs +1 -1
- package/dist/pkt-icon.js +1 -1
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +37 -35
- package/dist/pkt-input-wrapper.cjs +1 -1
- package/dist/pkt-input-wrapper.js +1 -1
- package/dist/pkt-link.cjs +1 -1
- package/dist/pkt-link.js +1 -1
- package/dist/pkt-linkcard.cjs +1 -1
- package/dist/pkt-linkcard.js +1 -1
- package/dist/pkt-listbox.cjs +1 -1
- package/dist/pkt-listbox.js +1 -1
- package/dist/pkt-loader.cjs +1 -1
- package/dist/pkt-loader.js +1 -1
- package/dist/pkt-messagebox.cjs +1 -1
- package/dist/pkt-messagebox.js +1 -1
- package/dist/pkt-modal.cjs +1 -1
- package/dist/pkt-modal.js +1 -1
- package/dist/{pkt-options-controller-CpEZcomb.cjs → pkt-options-controller-B3vVKnAG.cjs} +1 -1
- package/dist/{pkt-options-controller-D7l18Iw0.js → pkt-options-controller-ClFrUWZK.js} +1 -1
- package/dist/pkt-progressbar.cjs +1 -1
- package/dist/pkt-progressbar.js +1 -1
- package/dist/pkt-radio-group.cjs +1 -0
- package/dist/pkt-radio-group.js +2 -0
- package/dist/pkt-radiobutton.cjs +1 -1
- package/dist/pkt-radiobutton.js +1 -1
- package/dist/pkt-searchinput.cjs +1 -1
- package/dist/pkt-searchinput.js +1 -1
- package/dist/pkt-select.cjs +1 -1
- package/dist/pkt-select.js +1 -1
- package/dist/pkt-tabs.cjs +1 -1
- package/dist/pkt-tabs.js +1 -1
- package/dist/pkt-tag.cjs +1 -1
- package/dist/pkt-tag.js +1 -1
- package/dist/pkt-textarea.cjs +1 -1
- package/dist/pkt-textarea.js +1 -1
- package/dist/pkt-textinput.cjs +1 -1
- package/dist/pkt-textinput.js +1 -1
- package/dist/pkt-timepicker.cjs +1 -1
- package/dist/pkt-timepicker.js +1 -1
- package/dist/{progressbar-CIXNSwTy.cjs → progressbar-CnX4fFfR.cjs} +1 -1
- package/dist/{progressbar-DH5lIBpx.js → progressbar-DZHiq7B0.js} +5 -5
- package/dist/provide-Cz18sYug.cjs +1 -0
- package/dist/provide-_MnlMGnw.js +111 -0
- package/dist/radio-group-BzV_JhgJ.js +52 -0
- package/dist/radio-group-C-8C0-Py.cjs +1 -0
- package/dist/radio-group.d.ts +1 -0
- package/dist/radiobutton-_089zFBB.cjs +38 -0
- package/dist/radiobutton-bkTAD5PV.js +108 -0
- package/dist/{ref-Emu5PNxk.cjs → ref-CB7e9nMY.cjs} +1 -1
- package/dist/{ref-CCSGk4MP.js → ref-y_5qv9vU.js} +2 -2
- package/dist/{repeat-CdxGS-_3.js → repeat-CV9S4zya.js} +2 -2
- package/dist/{repeat-Dh9YKoeV.cjs → repeat-CnnigVcj.cjs} +1 -1
- package/dist/{searchinput-Co8tcq-l.js → searchinput-Bkcr3Fby.js} +4 -4
- package/dist/{searchinput-CbClDE-d.cjs → searchinput-Mdc9Ihld.cjs} +1 -1
- package/dist/{select-Cz80KV3g.js → select-B6CN2Ymq.js} +7 -7
- package/dist/{select-CZk57p1_.cjs → select-BowvpCNa.cjs} +1 -1
- package/dist/shared-strings/nb.d.ts +1 -0
- package/dist/shared-types/index.d.ts +6 -2
- package/dist/shared-types/option-group.d.ts +50 -0
- package/dist/shared-types/radiobutton.d.ts +46 -0
- package/dist/{tabs-B8blHQrL.js → tabs-DZvtVA0y.js} +9 -8
- package/dist/tabs-Dm8xcPRs.cjs +40 -0
- package/dist/{tag-Bns7Xj1O.js → tag-C33BPIOm.js} +5 -5
- package/dist/{tag-B5dUg7AD.cjs → tag-DyVZrqOQ.cjs} +1 -1
- package/dist/tests/component-registry.d.ts +4 -0
- package/dist/tests/option-contexts.d.ts +7 -0
- package/dist/{textarea-Dwjx-Crl.cjs → textarea-DoH3Il8v.cjs} +1 -1
- package/dist/{textarea-Dfvx1I60.js → textarea-hW0kV5gj.js} +9 -9
- package/dist/{textinput-7zTPlXVj.js → textinput-B6G4dVuL.js} +8 -8
- package/dist/{textinput-BeraGRzb.cjs → textinput-CQknclmV.cjs} +1 -1
- package/dist/{timepicker-C0dSH4Ij.js → timepicker-Cd2QI6ua.js} +8 -8
- package/dist/{timepicker-DarB9eA6.cjs → timepicker-DB3gor6g.cjs} +1 -1
- package/package.json +2 -2
- package/src/components/checkbox/checkbox.test.ts +99 -0
- package/src/components/checkbox/checkbox.ts +14 -5
- package/src/components/checkbox-group/checkbox-group-context.ts +8 -0
- package/src/components/checkbox-group/checkbox-group.test.ts +406 -0
- package/src/components/checkbox-group/checkbox-group.ts +69 -0
- package/src/components/checkbox-group/index.ts +4 -0
- package/src/components/combobox/combobox.ts +1 -1
- package/src/components/datepicker/datepicker.ts +1 -1
- package/src/components/index.ts +3 -0
- package/src/components/input-wrapper/input-wrapper.ts +5 -1
- package/src/components/input-wrapper/wrapper-parity.test.ts +27 -2
- package/src/components/radio-group/index.ts +4 -0
- package/src/components/radio-group/radio-group-context.ts +8 -0
- package/src/components/radio-group/radio-group.test.ts +530 -0
- package/src/components/radio-group/radio-group.ts +65 -0
- package/src/components/radiobutton/index.ts +1 -0
- package/src/components/radiobutton/radiobutton.test.ts +95 -0
- package/src/components/radiobutton/radiobutton.ts +26 -11
- package/dist/accordion-5lSFQToJ.cjs +0 -47
- package/dist/checkbox-D69leWDh.cjs +0 -40
- package/dist/consume-BDnMAp2g.js +0 -167
- package/dist/consume-Le4HztPo.cjs +0 -1
- package/dist/element-with-slot-D7sTqOr3.cjs +0 -1
- package/dist/if-defined-2mkIDgOm.cjs +0 -1
- package/dist/input-element-CSfDGslx.cjs +0 -1
- package/dist/radiobutton-BPr22VmL.cjs +0 -38
- package/dist/radiobutton-l_3oGDbb.js +0 -97
- package/dist/tabs-CjX-GWvM.cjs +0 -40
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
3
|
+
import { fireEvent } from '@testing-library/dom'
|
|
4
|
+
import { vi } from 'vitest'
|
|
5
|
+
import type { LitElement } from 'lit'
|
|
6
|
+
import { CustomElementFor } from '../../tests/component-registry'
|
|
7
|
+
import '@/components/textinput'
|
|
8
|
+
import './radio-group'
|
|
9
|
+
|
|
10
|
+
expect.extend(toHaveNoViolations)
|
|
11
|
+
|
|
12
|
+
type TRadioGroup = CustomElementFor<'pkt-radio-group'>
|
|
13
|
+
type TRadio = CustomElementFor<'pkt-radiobutton'> & {
|
|
14
|
+
internals: { validity: ValidityState; ariaRequired: string | null }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const settle = async () => {
|
|
18
|
+
for (let i = 0; i < 2; i++) {
|
|
19
|
+
const elements = Array.from(
|
|
20
|
+
document.querySelectorAll<LitElement>('pkt-radio-group, pkt-input-wrapper, pkt-radiobutton'),
|
|
21
|
+
)
|
|
22
|
+
await Promise.all(elements.map((el) => el.updateComplete))
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mount = async (markup: string) => {
|
|
28
|
+
document.body.innerHTML = markup
|
|
29
|
+
await settle()
|
|
30
|
+
return document.querySelector('pkt-radio-group') as TRadioGroup
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const radio = (id: string) => document.getElementById(id) as TRadio
|
|
34
|
+
const inner = (id: string) => radio(id).querySelector('input') as HTMLInputElement
|
|
35
|
+
|
|
36
|
+
const select = async (id: string) => {
|
|
37
|
+
fireEvent.click(inner(id))
|
|
38
|
+
await settle()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const options = `
|
|
42
|
+
<pkt-radiobutton id="buss" value="buss" label="Buss"></pkt-radiobutton>
|
|
43
|
+
<pkt-radiobutton id="tog" value="tog" label="Tog"></pkt-radiobutton>
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
describe('pkt-radio-group', () => {
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
document.body.innerHTML = ''
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe('rendering', () => {
|
|
52
|
+
test('renders the radios inside the fieldset options of an input wrapper', async () => {
|
|
53
|
+
const group = await mount(
|
|
54
|
+
`<pkt-radio-group id="reise" label="Reisemåte">${options}</pkt-radio-group>`,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const fieldset = group.querySelector('fieldset.pkt-inputwrapper__fieldset')
|
|
58
|
+
expect(fieldset).toBeInTheDocument()
|
|
59
|
+
expect(fieldset?.querySelector('legend')).toHaveTextContent('Reisemåte')
|
|
60
|
+
const container = fieldset?.querySelector('.pkt-inputwrapper__options')
|
|
61
|
+
expect(radio('buss').parentElement).toBe(container)
|
|
62
|
+
expect(radio('tog').parentElement).toBe(container)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('uses the group id for the wrapper ids', async () => {
|
|
66
|
+
const group = await mount(
|
|
67
|
+
`<pkt-radio-group id="reise" label="Reisemåte" helptext="Velg én">${options}</pkt-radio-group>`,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
expect(group.querySelector('legend')).toHaveAttribute('id', 'reise-label')
|
|
71
|
+
expect(group.querySelector('fieldset')).toHaveAttribute('aria-describedby', 'reise-helptext')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('passes layout and size to the input wrapper', async () => {
|
|
75
|
+
const group = await mount(
|
|
76
|
+
`<pkt-radio-group label="Reisemåte" layout="horizontal" input-size="small">${options}</pkt-radio-group>`,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const wrapper = group.querySelector('pkt-input-wrapper')
|
|
80
|
+
expect(wrapper).toHaveClass('pkt-inputwrapper--small')
|
|
81
|
+
expect(group.querySelector('.pkt-inputwrapper__options')).toHaveClass(
|
|
82
|
+
'pkt-inputwrapper__options--horizontal',
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('forwards slotted helptext to the input wrapper', async () => {
|
|
87
|
+
const group = await mount(
|
|
88
|
+
`<pkt-radio-group id="reise" label="Reisemåte">
|
|
89
|
+
<div slot="helptext">Fra slot</div>
|
|
90
|
+
${options}
|
|
91
|
+
</pkt-radio-group>`,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
expect(group.querySelector('.pkt-inputwrapper__helptext')).toHaveTextContent('Fra slot')
|
|
95
|
+
expect(group.querySelector('fieldset')).toHaveAttribute('aria-describedby', 'reise-helptext')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('renders the error message and links it to the fieldset', async () => {
|
|
99
|
+
const group = await mount(
|
|
100
|
+
`<pkt-radio-group id="reise" label="Reisemåte" hasError errorMessage="Velg en reisemåte">${options}</pkt-radio-group>`,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
expect(group.querySelector('#reise-error')).toHaveTextContent('Velg en reisemåte')
|
|
104
|
+
expect(group.querySelector('fieldset')?.getAttribute('aria-describedby')).toContain(
|
|
105
|
+
'reise-error',
|
|
106
|
+
)
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
describe('name', () => {
|
|
111
|
+
test('gives radios without a name the group name', async () => {
|
|
112
|
+
await mount(`<pkt-radio-group name="reise" label="Reisemåte">${options}</pkt-radio-group>`)
|
|
113
|
+
|
|
114
|
+
expect(radio('buss')).toHaveAttribute('name', 'reise')
|
|
115
|
+
expect(radio('tog')).toHaveAttribute('name', 'reise')
|
|
116
|
+
expect(inner('buss').name).toBe(inner('tog').name)
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
test('falls back to the group id when the group has no name', async () => {
|
|
120
|
+
await mount(`<pkt-radio-group id="reise" label="Reisemåte">${options}</pkt-radio-group>`)
|
|
121
|
+
|
|
122
|
+
expect(radio('buss')).toHaveAttribute('name', 'reise')
|
|
123
|
+
expect(radio('tog')).toHaveAttribute('name', 'reise')
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
test('generates a shared name when the group has neither name nor id', async () => {
|
|
127
|
+
await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
128
|
+
|
|
129
|
+
const name = radio('buss').getAttribute('name')
|
|
130
|
+
expect(name).toBeTruthy()
|
|
131
|
+
expect(name).not.toBe('buss')
|
|
132
|
+
expect(radio('tog')).toHaveAttribute('name', name!)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('keeps a name set on the radio', async () => {
|
|
136
|
+
await mount(
|
|
137
|
+
`<pkt-radio-group name="reise" label="Reisemåte">
|
|
138
|
+
<pkt-radiobutton id="buss" name="eget" value="buss" label="Buss"></pkt-radiobutton>
|
|
139
|
+
</pkt-radio-group>`,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
expect(radio('buss')).toHaveAttribute('name', 'eget')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
test('replaces the id fallback when a rendered radio joins the group', async () => {
|
|
146
|
+
const group = await mount(
|
|
147
|
+
`<pkt-radio-group name="reise" label="Reisemåte"></pkt-radio-group>`,
|
|
148
|
+
)
|
|
149
|
+
const standalone = document.createElement('pkt-radiobutton') as TRadio
|
|
150
|
+
standalone.id = 'fly'
|
|
151
|
+
standalone.setAttribute('label', 'Fly')
|
|
152
|
+
document.body.appendChild(standalone)
|
|
153
|
+
await settle()
|
|
154
|
+
expect(standalone).toHaveAttribute('name', 'fly')
|
|
155
|
+
|
|
156
|
+
group.appendChild(standalone)
|
|
157
|
+
await settle()
|
|
158
|
+
|
|
159
|
+
expect(standalone).toHaveAttribute('name', 'reise')
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
test('follows a new group name', async () => {
|
|
163
|
+
const group = await mount(
|
|
164
|
+
`<pkt-radio-group name="reise" label="Reisemåte">${options}</pkt-radio-group>`,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
group.name = 'transport'
|
|
168
|
+
await settle()
|
|
169
|
+
|
|
170
|
+
expect(radio('buss')).toHaveAttribute('name', 'transport')
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('keeps the id fallback for a radio outside a group', async () => {
|
|
174
|
+
document.body.innerHTML = '<pkt-radiobutton id="alene" label="Alene"></pkt-radiobutton>'
|
|
175
|
+
await settle()
|
|
176
|
+
|
|
177
|
+
expect(radio('alene')).toHaveAttribute('name', 'alene')
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
describe('defaults for the radios', () => {
|
|
182
|
+
test('turns on tile and error state for every radio', async () => {
|
|
183
|
+
await mount(
|
|
184
|
+
`<pkt-radio-group label="Reisemåte" hasTile hasError>${options}</pkt-radio-group>`,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
for (const id of ['buss', 'tog']) {
|
|
188
|
+
expect(radio(id).querySelector('.pkt-input-check__input')).toHaveClass(
|
|
189
|
+
'pkt-input-check__input--tile',
|
|
190
|
+
)
|
|
191
|
+
expect(inner(id)).toHaveClass('pkt-input-check__input-checkbox--error')
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
test('lets a radio turn on tile when the group does not', async () => {
|
|
196
|
+
await mount(
|
|
197
|
+
`<pkt-radio-group label="Reisemåte">
|
|
198
|
+
<pkt-radiobutton id="buss" value="buss" label="Buss" hasTile></pkt-radiobutton>
|
|
199
|
+
<pkt-radiobutton id="tog" value="tog" label="Tog"></pkt-radiobutton>
|
|
200
|
+
</pkt-radio-group>`,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
expect(radio('buss').querySelector('.pkt-input-check__input')).toHaveClass(
|
|
204
|
+
'pkt-input-check__input--tile',
|
|
205
|
+
)
|
|
206
|
+
expect(radio('tog').querySelector('.pkt-input-check__input')).not.toHaveClass(
|
|
207
|
+
'pkt-input-check__input--tile',
|
|
208
|
+
)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
test('updates the radios when the group changes', async () => {
|
|
212
|
+
const group = await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
213
|
+
|
|
214
|
+
group.hasTile = true
|
|
215
|
+
await settle()
|
|
216
|
+
|
|
217
|
+
expect(radio('buss').querySelector('.pkt-input-check__input')).toHaveClass(
|
|
218
|
+
'pkt-input-check__input--tile',
|
|
219
|
+
)
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
describe('value', () => {
|
|
224
|
+
test('is the value of the checked radio', async () => {
|
|
225
|
+
const group = await mount(
|
|
226
|
+
`<pkt-radio-group label="Reisemåte">
|
|
227
|
+
<pkt-radiobutton id="buss" value="buss" label="Buss"></pkt-radiobutton>
|
|
228
|
+
<pkt-radiobutton id="tog" value="tog" label="Tog" checked></pkt-radiobutton>
|
|
229
|
+
</pkt-radio-group>`,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
expect(group.value).toBe('tog')
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('is an empty string when no radio is checked', async () => {
|
|
236
|
+
const group = await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
237
|
+
|
|
238
|
+
expect(group.value).toBe('')
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
test('is on for a checked radio without a value', async () => {
|
|
242
|
+
const group = await mount(
|
|
243
|
+
`<pkt-radio-group label="Reisemåte">
|
|
244
|
+
<pkt-radiobutton id="ja" label="Ja" checked></pkt-radiobutton>
|
|
245
|
+
</pkt-radio-group>`,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
expect(group.value).toBe('on')
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
test('checks the matching radio from the value attribute', async () => {
|
|
252
|
+
const group = await mount(
|
|
253
|
+
`<pkt-radio-group label="Reisemåte" value="tog">${options}</pkt-radio-group>`,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
expect(radio('tog').checked).toBe(true)
|
|
257
|
+
expect(radio('buss').checked).toBeFalsy()
|
|
258
|
+
expect(group.value).toBe('tog')
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test('checks the matching radio when set from code, without firing events', async () => {
|
|
262
|
+
const group = await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
263
|
+
const changed = vi.fn()
|
|
264
|
+
group.addEventListener('change', changed)
|
|
265
|
+
group.addEventListener('value-change', changed)
|
|
266
|
+
|
|
267
|
+
group.value = 'buss'
|
|
268
|
+
await settle()
|
|
269
|
+
expect(radio('buss').checked).toBe(true)
|
|
270
|
+
expect(inner('buss').checked).toBe(true)
|
|
271
|
+
|
|
272
|
+
group.value = 'tog'
|
|
273
|
+
await settle()
|
|
274
|
+
expect(radio('buss').checked).toBe(false)
|
|
275
|
+
expect(radio('tog').checked).toBe(true)
|
|
276
|
+
|
|
277
|
+
expect(changed).not.toHaveBeenCalled()
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
test('unchecks every radio when set to an empty string', async () => {
|
|
281
|
+
const group = await mount(
|
|
282
|
+
`<pkt-radio-group label="Reisemåte" value="tog">${options}</pkt-radio-group>`,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
group.value = ''
|
|
286
|
+
await settle()
|
|
287
|
+
|
|
288
|
+
expect(radio('tog').checked).toBe(false)
|
|
289
|
+
expect(group.value).toBe('')
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
test('applies the value to radios added later', async () => {
|
|
293
|
+
const group = await mount(
|
|
294
|
+
`<pkt-radio-group label="Reisemåte" value="fly">${options}</pkt-radio-group>`,
|
|
295
|
+
)
|
|
296
|
+
const fly = document.createElement('pkt-radiobutton') as TRadio
|
|
297
|
+
fly.id = 'fly'
|
|
298
|
+
fly.value = 'fly'
|
|
299
|
+
group.appendChild(fly)
|
|
300
|
+
await settle()
|
|
301
|
+
|
|
302
|
+
expect(fly.checked).toBe(true)
|
|
303
|
+
expect(group.value).toBe('fly')
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
describe('events', () => {
|
|
308
|
+
test('fires value-change on the group with the new value when the user selects', async () => {
|
|
309
|
+
const group = await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
310
|
+
const fromGroup: unknown[] = []
|
|
311
|
+
group.addEventListener('value-change', (event) => {
|
|
312
|
+
if (event.target === group) fromGroup.push((event as CustomEvent).detail)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
await select('tog')
|
|
316
|
+
await select('buss')
|
|
317
|
+
|
|
318
|
+
expect(fromGroup).toEqual(['tog', 'buss'])
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
test('fires change, input and value-change from the group instead of the radio', async () => {
|
|
322
|
+
const group = await mount(
|
|
323
|
+
`<form><pkt-radio-group name="reise" label="Reisemåte">${options}</pkt-radio-group></form>`,
|
|
324
|
+
)
|
|
325
|
+
const seen: string[] = []
|
|
326
|
+
for (const type of ['change', 'input', 'value-change']) {
|
|
327
|
+
group.addEventListener(type, (event) => {
|
|
328
|
+
const target = event.target as HTMLElement & { name: string; value: string }
|
|
329
|
+
seen.push(`${type}:${target.tagName.toLowerCase()}:${target.name}=${target.value}`)
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
const formChanges = vi.fn()
|
|
333
|
+
group.closest('form')!.addEventListener('change', formChanges)
|
|
334
|
+
|
|
335
|
+
await select('tog')
|
|
336
|
+
|
|
337
|
+
expect(seen).toEqual([
|
|
338
|
+
'input:pkt-radio-group:reise=tog',
|
|
339
|
+
'change:pkt-radio-group:reise=tog',
|
|
340
|
+
'value-change:pkt-radio-group:reise=tog',
|
|
341
|
+
])
|
|
342
|
+
expect(formChanges).toHaveBeenCalledTimes(1)
|
|
343
|
+
expect(formChanges.mock.calls[0][0].target).toBe(group)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
test('still fires the events on the radio itself', async () => {
|
|
347
|
+
await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
348
|
+
const changed = vi.fn()
|
|
349
|
+
radio('tog').addEventListener('change', changed)
|
|
350
|
+
|
|
351
|
+
await select('tog')
|
|
352
|
+
|
|
353
|
+
expect(changed).toHaveBeenCalledTimes(1)
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
test('fires focus when focus enters and blur when it leaves the group, not between radios', async () => {
|
|
357
|
+
document.body.innerHTML = `<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group><button>Utenfor</button>`
|
|
358
|
+
await settle()
|
|
359
|
+
const group = document.querySelector('pkt-radio-group') as TRadioGroup
|
|
360
|
+
const seen: string[] = []
|
|
361
|
+
for (const type of ['focus', 'blur']) {
|
|
362
|
+
group.addEventListener(type, (event) =>
|
|
363
|
+
seen.push(`${type}:${(event.target as Element).tagName.toLowerCase()}`),
|
|
364
|
+
)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
inner('buss').focus()
|
|
368
|
+
inner('tog').focus()
|
|
369
|
+
document.querySelector('button')!.focus()
|
|
370
|
+
|
|
371
|
+
expect(seen).toEqual(['focus:pkt-radio-group', 'blur:pkt-radio-group'])
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
test('focus() moves focus to the checked radio, or the first one', async () => {
|
|
375
|
+
const group = await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
376
|
+
|
|
377
|
+
group.focus()
|
|
378
|
+
expect(document.activeElement).toBe(inner('buss'))
|
|
379
|
+
|
|
380
|
+
group.value = 'tog'
|
|
381
|
+
await settle()
|
|
382
|
+
group.focus()
|
|
383
|
+
expect(document.activeElement).toBe(inner('tog'))
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
test('fires change only on the radio that becomes checked', async () => {
|
|
387
|
+
await mount(`<pkt-radio-group label="Reisemåte" value="buss">${options}</pkt-radio-group>`)
|
|
388
|
+
const bussChanged = vi.fn()
|
|
389
|
+
radio('buss').addEventListener('change', bussChanged)
|
|
390
|
+
|
|
391
|
+
await select('tog')
|
|
392
|
+
|
|
393
|
+
expect(bussChanged).not.toHaveBeenCalled()
|
|
394
|
+
expect(radio('buss').checked).toBe(false)
|
|
395
|
+
})
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
describe('validation', () => {
|
|
399
|
+
test('makes every radio invalid until one is checked when the group is required', async () => {
|
|
400
|
+
await mount(`<pkt-radio-group label="Reisemåte" required>${options}</pkt-radio-group>`)
|
|
401
|
+
|
|
402
|
+
expect(radio('buss').internals.validity.valueMissing).toBe(true)
|
|
403
|
+
expect(radio('tog').internals.validity.valueMissing).toBe(true)
|
|
404
|
+
|
|
405
|
+
await select('tog')
|
|
406
|
+
|
|
407
|
+
expect(radio('buss').internals.validity.valid).toBe(true)
|
|
408
|
+
expect(radio('tog').internals.validity.valid).toBe(true)
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
test('marks the radios as required for assistive technology', async () => {
|
|
412
|
+
await mount(`<pkt-radio-group label="Reisemåte" required>${options}</pkt-radio-group>`)
|
|
413
|
+
|
|
414
|
+
expect(radio('buss').internals.ariaRequired).toBe('true')
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
test('leaves the radios valid when the group is not required', async () => {
|
|
418
|
+
await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
419
|
+
|
|
420
|
+
expect(radio('buss').internals.validity.valid).toBe(true)
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
describe('disabled', () => {
|
|
425
|
+
test('disables the fieldset and marks the wrapper as disabled', async () => {
|
|
426
|
+
const group = await mount(
|
|
427
|
+
`<pkt-radio-group label="Reisemåte" disabled>${options}</pkt-radio-group>`,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
expect(group.querySelector('fieldset')).toHaveAttribute('disabled', '')
|
|
431
|
+
expect(group.querySelector('pkt-input-wrapper')).toHaveClass('pkt-inputwrapper--disabled')
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
test('does not set disabled on the fieldset otherwise', async () => {
|
|
435
|
+
const group = await mount(`<pkt-radio-group label="Reisemåte">${options}</pkt-radio-group>`)
|
|
436
|
+
|
|
437
|
+
expect(group.querySelector('fieldset')).not.toHaveAttribute('disabled')
|
|
438
|
+
})
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
describe('a text field for an other option', () => {
|
|
442
|
+
const settleAll = async () => {
|
|
443
|
+
for (let i = 0; i < 3; i++) {
|
|
444
|
+
const elements = Array.from(document.querySelectorAll<LitElement>('*')).filter(
|
|
445
|
+
(el) => 'updateComplete' in el,
|
|
446
|
+
)
|
|
447
|
+
await Promise.all(elements.map((el) => el.updateComplete))
|
|
448
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const mountOther = async () => {
|
|
453
|
+
document.body.innerHTML = `
|
|
454
|
+
<form id="skjema">
|
|
455
|
+
<pkt-radio-group id="gruppe" name="reise" label="Spørsmål">
|
|
456
|
+
<pkt-radiobutton id="buss" value="buss" label="Buss"></pkt-radiobutton>
|
|
457
|
+
<pkt-radiobutton id="annet" value="annet" label="Annet"></pkt-radiobutton>
|
|
458
|
+
<pkt-textinput id="annet-tekst" name="reise-annet" label="Hva annet?" hidden></pkt-textinput>
|
|
459
|
+
</pkt-radio-group>
|
|
460
|
+
<button>Utenfor</button>
|
|
461
|
+
</form>`
|
|
462
|
+
await settleAll()
|
|
463
|
+
const group = document.getElementById('gruppe') as HTMLElement & { value: unknown }
|
|
464
|
+
const field = document.getElementById('annet-tekst') as HTMLElement
|
|
465
|
+
group.addEventListener('change', (event) => {
|
|
466
|
+
if (event.target === group) field.hidden = !String(group.value).includes('annet')
|
|
467
|
+
})
|
|
468
|
+
return { group, field, input: () => field.querySelector('input') as HTMLInputElement }
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
test('shows the text field inside the group when the other option is chosen', async () => {
|
|
472
|
+
const { field } = await mountOther()
|
|
473
|
+
|
|
474
|
+
fireEvent.click(document.getElementById('annet')!.querySelector('input')!)
|
|
475
|
+
await settleAll()
|
|
476
|
+
|
|
477
|
+
expect(field.hidden).toBe(false)
|
|
478
|
+
expect(field.closest('.pkt-inputwrapper__options')).toBeInTheDocument()
|
|
479
|
+
})
|
|
480
|
+
|
|
481
|
+
test('keeps the text field out of the group value, and lets its events through', async () => {
|
|
482
|
+
const { group, input } = await mountOther()
|
|
483
|
+
fireEvent.click(document.getElementById('annet')!.querySelector('input')!)
|
|
484
|
+
await settleAll()
|
|
485
|
+
const targets: string[] = []
|
|
486
|
+
group.addEventListener('change', (event) => targets.push((event.target as Element).id))
|
|
487
|
+
|
|
488
|
+
input().value = 'Ferge'
|
|
489
|
+
fireEvent.input(input())
|
|
490
|
+
fireEvent.change(input())
|
|
491
|
+
await settleAll()
|
|
492
|
+
|
|
493
|
+
expect(group.value).toEqual('annet')
|
|
494
|
+
expect(targets).toEqual(['annet-tekst'])
|
|
495
|
+
expect(
|
|
496
|
+
Array.from(new FormData(document.getElementById('skjema') as HTMLFormElement).entries()),
|
|
497
|
+
).toEqual([
|
|
498
|
+
['reise', 'annet'],
|
|
499
|
+
['reise-annet', 'Ferge'],
|
|
500
|
+
])
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
test('fires blur only when focus leaves the group, also from the text field', async () => {
|
|
504
|
+
const { group, input } = await mountOther()
|
|
505
|
+
fireEvent.click(document.getElementById('annet')!.querySelector('input')!)
|
|
506
|
+
await settleAll()
|
|
507
|
+
const blurs: Element[] = []
|
|
508
|
+
group.addEventListener('blur', (event) => {
|
|
509
|
+
if (event.target === group) blurs.push(event.target as Element)
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
document.getElementById('annet')!.querySelector('input')!.focus()
|
|
513
|
+
input().focus()
|
|
514
|
+
expect(blurs).toEqual([])
|
|
515
|
+
|
|
516
|
+
document.querySelector('button')!.focus()
|
|
517
|
+
expect(blurs).toEqual([group])
|
|
518
|
+
})
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
describe('accessibility', () => {
|
|
522
|
+
test('has no axe violations', async () => {
|
|
523
|
+
const group = await mount(
|
|
524
|
+
`<pkt-radio-group id="reise" label="Reisemåte" helptext="Velg én" required>${options}</pkt-radio-group>`,
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
expect(await axe(group)).toHaveNoViolations()
|
|
528
|
+
})
|
|
529
|
+
})
|
|
530
|
+
})
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { provide } from '@lit/context'
|
|
2
|
+
import { customElement, property, state } from 'lit/decorators.js'
|
|
3
|
+
import {
|
|
4
|
+
optionChecked,
|
|
5
|
+
optionValue,
|
|
6
|
+
PktOptionGroupElement,
|
|
7
|
+
type TOption,
|
|
8
|
+
} from '@/base-elements/option-group-element'
|
|
9
|
+
import { radioGroupContext, type RadioGroupContext } from './radio-group-context'
|
|
10
|
+
import '@/components/radiobutton'
|
|
11
|
+
|
|
12
|
+
export class PktRadioGroup extends PktOptionGroupElement {
|
|
13
|
+
protected readonly optionSelector = 'pkt-radiobutton'
|
|
14
|
+
|
|
15
|
+
@provide({ context: radioGroupContext })
|
|
16
|
+
@state()
|
|
17
|
+
protected groupContext: RadioGroupContext = {
|
|
18
|
+
name: '',
|
|
19
|
+
hasTile: false,
|
|
20
|
+
hasError: false,
|
|
21
|
+
required: false,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private storedValue: string | null = null
|
|
25
|
+
|
|
26
|
+
@property({ type: String })
|
|
27
|
+
get value(): string {
|
|
28
|
+
const checked = this.options().find(optionChecked)
|
|
29
|
+
return checked ? optionValue(checked) : ''
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
set value(newValue: string | null | undefined) {
|
|
33
|
+
const oldValue = this.value
|
|
34
|
+
this.storedValue = newValue ?? ''
|
|
35
|
+
this.applyStoredValue(this.options())
|
|
36
|
+
this.requestUpdate('value', oldValue)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected get hasStoredValue(): boolean {
|
|
40
|
+
return this.storedValue !== null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
protected storeCurrentValue(): void {
|
|
44
|
+
this.storedValue = this.value
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected applyStoredValue(options: TOption[]): void {
|
|
48
|
+
options.forEach((option) => {
|
|
49
|
+
const checked = this.storedValue !== '' && optionValue(option) === this.storedValue
|
|
50
|
+
if (optionChecked(option) !== checked) option.checked = checked
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected createGroupContext(): RadioGroupContext {
|
|
55
|
+
return { ...super.createGroupContext(), required: this.required }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
customElement('pkt-radio-group')(PktRadioGroup)
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.warn('Forsøker å definere <pkt-radio-group>, men den er allerede definert')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default PktRadioGroup
|