@oslokommune/punkt-react 12.33.1 → 12.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/dist/index.d.ts +26 -29
- package/dist/punkt-react.es.js +7888 -7800
- package/dist/punkt-react.umd.js +274 -240
- package/package.json +4 -4
- package/src/components/accordion/Accordion.test.tsx +66 -36
- package/src/components/accordion/Accordion.tsx +26 -21
- package/src/components/accordion/AccordionItem.tsx +30 -75
- package/src/components/checkbox/Checkbox.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oslokommune/punkt-react",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.34.1",
|
|
4
4
|
"description": "React komponentbibliotek til Punkt, et designsystem laget av Oslo Origo",
|
|
5
5
|
"homepage": "https://punkt.oslo.kommune.no",
|
|
6
6
|
"author": "Team Designsystem, Oslo Origo",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@lit-labs/ssr-dom-shim": "^1.2.1",
|
|
40
40
|
"@lit/react": "^1.0.5",
|
|
41
|
-
"@oslokommune/punkt-elements": "^12.
|
|
41
|
+
"@oslokommune/punkt-elements": "^12.34.1",
|
|
42
42
|
"angular-html-parser": "^6.0.2",
|
|
43
43
|
"html-format": "^1.1.7",
|
|
44
44
|
"prettier": "^3.3.3",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@babel/plugin-proposal-private-property-in-object": "^7.18.6",
|
|
51
51
|
"@oslokommune/punkt-assets": "^12.30.1",
|
|
52
|
-
"@oslokommune/punkt-css": "^12.
|
|
52
|
+
"@oslokommune/punkt-css": "^12.34.1",
|
|
53
53
|
"@testing-library/jest-dom": "^6.5.0",
|
|
54
54
|
"@testing-library/react": "^16.0.1",
|
|
55
55
|
"@testing-library/user-event": "^14.5.2",
|
|
@@ -112,5 +112,5 @@
|
|
|
112
112
|
"url": "https://github.com/oslokommune/punkt/issues"
|
|
113
113
|
},
|
|
114
114
|
"license": "MIT",
|
|
115
|
-
"gitHead": "
|
|
115
|
+
"gitHead": "62e323745bcb2f3d3a27ff2f05090680fbeaeef7"
|
|
116
116
|
}
|
|
@@ -2,7 +2,7 @@ import '@testing-library/jest-dom'
|
|
|
2
2
|
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
3
3
|
import { PktAccordion } from './Accordion'
|
|
4
4
|
import { PktAccordionItem } from './AccordionItem'
|
|
5
|
-
import { render, screen } from '@testing-library/react'
|
|
5
|
+
import { render, screen, waitFor } from '@testing-library/react'
|
|
6
6
|
import React, { createRef } from 'react'
|
|
7
7
|
|
|
8
8
|
expect.extend(toHaveNoViolations)
|
|
@@ -20,24 +20,14 @@ describe('PktAccordion', () => {
|
|
|
20
20
|
// Assert that the Accordion component renders without throwing any errors
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
test('ref works correctly', async () => {
|
|
24
|
-
const ref = createRef<HTMLDivElement>()
|
|
25
|
-
const { unmount } = render(<PktAccordion ref={ref}>Alert text</PktAccordion>)
|
|
26
|
-
await window.customElements.whenDefined('pkt-icon')
|
|
27
|
-
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
28
|
-
|
|
29
|
-
unmount()
|
|
30
|
-
expect(ref.current).toBe(null)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
23
|
test('renders children', async () => {
|
|
34
24
|
const mockToggleOpen = jest.fn()
|
|
35
25
|
render(
|
|
36
26
|
<PktAccordion>
|
|
37
|
-
<PktAccordionItem title="Title 1" id="item1"
|
|
27
|
+
<PktAccordionItem title="Title 1" id="item1" onClick={mockToggleOpen}>
|
|
38
28
|
Content 1
|
|
39
29
|
</PktAccordionItem>
|
|
40
|
-
<PktAccordionItem title="Title 2" id="item2"
|
|
30
|
+
<PktAccordionItem title="Title 2" id="item2" onClick={mockToggleOpen}>
|
|
41
31
|
Content 2
|
|
42
32
|
</PktAccordionItem>
|
|
43
33
|
</PktAccordion>,
|
|
@@ -51,38 +41,78 @@ describe('PktAccordion', () => {
|
|
|
51
41
|
expect(screen.getByText('Content 2')).toBeInTheDocument()
|
|
52
42
|
})
|
|
53
43
|
|
|
54
|
-
test('applies compact and skin
|
|
55
|
-
|
|
44
|
+
test('applies compact and skin', async () => {
|
|
45
|
+
const ref = createRef<any>()
|
|
46
|
+
const { container } = render(
|
|
56
47
|
<>
|
|
57
48
|
<h3 id="accordion-heading">Accordion Heading</h3>
|
|
58
|
-
<PktAccordion
|
|
49
|
+
<PktAccordion ref={ref}>
|
|
59
50
|
<PktAccordionItem title="Title" id="item1">
|
|
60
51
|
Content
|
|
61
52
|
</PktAccordionItem>
|
|
62
53
|
</PktAccordion>
|
|
63
54
|
</>,
|
|
64
55
|
)
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
|
|
57
|
+
// Wait for the element to be defined
|
|
58
|
+
await window.customElements.whenDefined('pkt-accordion')
|
|
59
|
+
await window.customElements.whenDefined('pkt-accordion-item')
|
|
60
|
+
|
|
61
|
+
// Now manually set properties on the element
|
|
62
|
+
if (ref.current) {
|
|
63
|
+
ref.current.skin = 'blue'
|
|
64
|
+
ref.current.compact = true
|
|
65
|
+
await ref.current.updateComplete // Wait for Lit to update
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const accordion = container.querySelector('pkt-accordion')!
|
|
69
|
+
expect(accordion).toBeInTheDocument()
|
|
70
|
+
expect(accordion).toHaveAttribute('compact') // compact reflected as boolean attribute
|
|
71
|
+
expect(accordion).toHaveAttribute('skin', 'blue')
|
|
69
72
|
})
|
|
73
|
+
})
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
describe('PktAccordionItem', () => {
|
|
76
|
+
test('applies compact and skin', async () => {
|
|
77
|
+
const ref = createRef<any>()
|
|
78
|
+
const { container } = render(
|
|
79
|
+
<>
|
|
80
|
+
<PktAccordionItem ref={ref} title="Title" id="item1" skin="blue" compact>
|
|
81
|
+
Content
|
|
82
|
+
</PktAccordionItem>
|
|
83
|
+
</>,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
// Wait for the element to be defined
|
|
87
|
+
await window.customElements.whenDefined('pkt-accordion-item')
|
|
88
|
+
|
|
89
|
+
// Now manually set properties on the element
|
|
90
|
+
if (ref.current) {
|
|
91
|
+
ref.current.skin = 'blue'
|
|
92
|
+
ref.current.compact = true
|
|
93
|
+
ref.current.requestUpdate()
|
|
94
|
+
await ref.current.updateComplete
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const details = container.querySelector('details')!
|
|
98
|
+
expect(details.classList.contains('pkt-accordion-item--blue')).toBe(true)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe('accessibility', () => {
|
|
103
|
+
it('renders with no wcag errors with axe', async () => {
|
|
104
|
+
const { container } = render(
|
|
105
|
+
<PktAccordion>
|
|
106
|
+
<PktAccordionItem title="Title 1" id="item1">
|
|
107
|
+
Content 1
|
|
108
|
+
</PktAccordionItem>
|
|
109
|
+
<PktAccordionItem title="Title 2" id="item2">
|
|
110
|
+
Content 2
|
|
111
|
+
</PktAccordionItem>
|
|
112
|
+
</PktAccordion>,
|
|
113
|
+
)
|
|
114
|
+
await window.customElements.whenDefined('pkt-icon')
|
|
115
|
+
const results = await axe(container)
|
|
116
|
+
expect(results).toHaveNoViolations()
|
|
87
117
|
})
|
|
88
118
|
})
|
|
@@ -1,36 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PktElConstructor, PktElType } from '@/interfaces/IPktElements'
|
|
2
|
+
import { createComponent } from '@lit/react'
|
|
3
|
+
import React, { ForwardRefExoticComponent, LegacyRef } from 'react'
|
|
4
|
+
import { FC, ReactNode, Ref, forwardRef } from 'react'
|
|
5
|
+
import { PktAccordion as PktElAccordion } from '@oslokommune/punkt-elements'
|
|
6
|
+
import { TPktAccordionSkin } from '@oslokommune/punkt-elements'
|
|
2
7
|
|
|
3
|
-
export interface IPktAccordion {
|
|
4
|
-
className?: string
|
|
5
|
-
children: ReactNode | ReactNode[]
|
|
6
|
-
/**
|
|
7
|
-
* @default compact: "false"
|
|
8
|
-
*/
|
|
8
|
+
export interface IPktAccordion extends PktElType {
|
|
9
9
|
compact?: boolean
|
|
10
10
|
/**
|
|
11
11
|
* @default skin: "borderless"
|
|
12
12
|
*/
|
|
13
|
-
skin?:
|
|
13
|
+
skin?: TPktAccordionSkin
|
|
14
|
+
/**
|
|
15
|
+
* @description A unique identifier to connect the accordion with a heading
|
|
16
|
+
*/
|
|
17
|
+
ariaLabelledBy?: string
|
|
14
18
|
/**
|
|
15
19
|
* @description A unique identifier to connect the accordion with a heading
|
|
16
20
|
*/
|
|
21
|
+
ref?: LegacyRef<HTMLElement>
|
|
17
22
|
}
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
skin && `pkt-accordion--${skin}`,
|
|
26
|
-
]
|
|
27
|
-
.filter(Boolean)
|
|
28
|
-
.join(' ')
|
|
24
|
+
const LitComponent: FC<IPktAccordion> = createComponent({
|
|
25
|
+
tagName: 'pkt-accordion',
|
|
26
|
+
elementClass: PktElAccordion as PktElConstructor<HTMLElement>,
|
|
27
|
+
react: React,
|
|
28
|
+
displayName: 'PktAccordion',
|
|
29
|
+
}) as ForwardRefExoticComponent<IPktAccordion>
|
|
29
30
|
|
|
31
|
+
export const PktAccordion: FC<IPktAccordion> = forwardRef(
|
|
32
|
+
({ compact = false, skin = 'borderless', ariaLabelledBy, children, ...props }: IPktAccordion, ref) => {
|
|
30
33
|
return (
|
|
31
|
-
<
|
|
32
|
-
{children}
|
|
33
|
-
</
|
|
34
|
+
<LitComponent data-testid="pkt-accordion" {...props} ref={ref} aria-labelledby={ariaLabelledBy}>
|
|
35
|
+
<div className="pkt-contents">{children}</div>
|
|
36
|
+
</LitComponent>
|
|
34
37
|
)
|
|
35
38
|
},
|
|
36
39
|
)
|
|
40
|
+
|
|
41
|
+
PktAccordion.displayName = 'PktAccordion'
|
|
@@ -1,83 +1,38 @@
|
|
|
1
|
-
import React, { LegacyRef,
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export interface IPktAccordionToggleProps {
|
|
13
|
-
isOpen: boolean
|
|
14
|
-
onToggleClick: (e: React.MouseEvent, id: string) => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface IPktAccordionItem {
|
|
18
|
-
children?: React.ReactNode | React.ReactNode[]
|
|
19
|
-
className?: string
|
|
1
|
+
import React, { FC, ForwardRefExoticComponent, LegacyRef, ReactElement, forwardRef } from 'react'
|
|
2
|
+
import { PktElConstructor, PktElType, PktEventWithTarget } from '@/interfaces/IPktElements'
|
|
3
|
+
import { createComponent, EventName } from '@lit/react'
|
|
4
|
+
import { PktAccordionItem as PktElAccordionItem } from '@oslokommune/punkt-elements'
|
|
5
|
+
import { TPktAccordionSkin } from '@oslokommune/punkt-elements'
|
|
6
|
+
|
|
7
|
+
export interface IPktAccordionItem extends Omit<PktElType, 'onClick'> {
|
|
8
|
+
compact?: boolean
|
|
9
|
+
skin?: TPktAccordionSkin
|
|
10
|
+
title?: string
|
|
20
11
|
defaultOpen?: boolean
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
isOpen?: boolean
|
|
13
|
+
id?: string
|
|
14
|
+
onClick?: (e: PktEventWithTarget) => void
|
|
15
|
+
ref?: LegacyRef<HTMLElement>
|
|
24
16
|
}
|
|
25
17
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* To use the "open" attribute of <details> element correctly,
|
|
37
|
-
* we need to return either "open=true" or "open=undefined" as setting "open=false"
|
|
38
|
-
* will set the "open" attribute to true as "false" is still a boolean
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
const returnTrueIfOpen = (isOpen: boolean): boolean | undefined => {
|
|
42
|
-
return isOpen ?? undefined
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const handleToggleClick = (e: React.MouseEvent, id: string) => {
|
|
46
|
-
/**
|
|
47
|
-
* e.preventDefault() is important to prevent native default onToggle behavior
|
|
48
|
-
* (that the event receives from being a <details> element) as it creates
|
|
49
|
-
* inconsistent behaviour toggling the "open" attribute both locally
|
|
50
|
-
* and through the React state.
|
|
51
|
-
* Read more here: https://github.com/facebook/react/issues/15486#issuecomment-873516817
|
|
52
|
-
* */
|
|
53
|
-
e.preventDefault()
|
|
54
|
-
|
|
55
|
-
if (toggleProps !== undefined) {
|
|
56
|
-
toggleProps.onToggleClick(e, id)
|
|
57
|
-
}
|
|
58
|
-
setIsOpen(!openToggleProp) // use open if it exists, if not use isOpen
|
|
59
|
-
}
|
|
60
|
-
const accordionItemClass = classNames(className, 'pkt-accordion-item')
|
|
18
|
+
const LitComponent: FC<IPktAccordionItem> = createComponent({
|
|
19
|
+
tagName: 'pkt-accordion-item',
|
|
20
|
+
elementClass: PktElAccordionItem as PktElConstructor<HTMLElement>,
|
|
21
|
+
react: React,
|
|
22
|
+
displayName: 'PktAccordionItem',
|
|
23
|
+
events: {
|
|
24
|
+
onClick: 'click' as EventName<PktEventWithTarget>,
|
|
25
|
+
},
|
|
26
|
+
}) as ForwardRefExoticComponent<IPktAccordionItem>
|
|
61
27
|
|
|
28
|
+
export const PktAccordionItem: FC<IPktAccordionItem> = forwardRef(
|
|
29
|
+
({ children, ...props }: Omit<IPktAccordionItem, 'ref'>, ref): ReactElement => {
|
|
62
30
|
return (
|
|
63
|
-
<
|
|
64
|
-
className={
|
|
65
|
-
|
|
66
|
-
id={id}
|
|
67
|
-
open={toggleProps ? returnTrueIfOpen(toggleProps.isOpen) : returnTrueIfOpen(isOpen)}
|
|
68
|
-
>
|
|
69
|
-
<summary
|
|
70
|
-
className="pkt-accordion-item__title"
|
|
71
|
-
id={`pkt-accordion-item-summary-${id}`}
|
|
72
|
-
onClick={(e) => handleToggleClick(e, id)}
|
|
73
|
-
>
|
|
74
|
-
{title}
|
|
75
|
-
<PktIcon name="chevron-thin-down" className="pkt-accordion-item__icon" aria-hidden="true" />
|
|
76
|
-
</summary>
|
|
77
|
-
<div id={`pkt-accordion-item-content-${id}`} role="region" className="pkt-accordion-item__content">
|
|
78
|
-
{children}
|
|
79
|
-
</div>
|
|
80
|
-
</details>
|
|
31
|
+
<LitComponent ref={ref} {...props}>
|
|
32
|
+
<div className="pkt-contents">{children}</div>
|
|
33
|
+
</LitComponent>
|
|
81
34
|
)
|
|
82
35
|
},
|
|
83
36
|
)
|
|
37
|
+
|
|
38
|
+
PktAccordionItem.displayName = 'PktAccordionItem'
|
|
@@ -19,7 +19,7 @@ export interface IPktCheckbox extends InputHTMLAttributes<HTMLInputElement> {
|
|
|
19
19
|
defaultChecked?: boolean
|
|
20
20
|
disabled?: boolean
|
|
21
21
|
value?: string
|
|
22
|
-
checkHelptext?: string |
|
|
22
|
+
checkHelptext?: string | ReactNode | ReactNode[]
|
|
23
23
|
isSwitch?: boolean
|
|
24
24
|
hideLabel?: boolean
|
|
25
25
|
labelPosition?: 'right' | 'left'
|