@oslokommune/punkt-react 12.17.2 → 12.18.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 +38 -0
- package/dist/index.d.ts +5 -16
- package/dist/punkt-react.es.js +10825 -10763
- package/dist/punkt-react.umd.js +301 -266
- package/package.json +3 -3
- package/src/components/header/Header.tsx +15 -5
- package/src/components/progressbar/Progressbar.test.tsx +108 -62
- package/src/components/progressbar/Progressbar.tsx +19 -115
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oslokommune/punkt-react",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.18.0",
|
|
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.18.0",
|
|
42
42
|
"angular-html-parser": "^6.0.2",
|
|
43
43
|
"html-format": "^1.1.7",
|
|
44
44
|
"prettier": "^3.3.3",
|
|
@@ -111,5 +111,5 @@
|
|
|
111
111
|
"url": "https://github.com/oslokommune/punkt/issues"
|
|
112
112
|
},
|
|
113
113
|
"license": "MIT",
|
|
114
|
-
"gitHead": "
|
|
114
|
+
"gitHead": "ceaac8e8aac119c09de9e77927150022aa6e316d"
|
|
115
115
|
}
|
|
@@ -163,7 +163,9 @@ export const PktHeader = forwardRef(
|
|
|
163
163
|
></PktIcon>
|
|
164
164
|
</button>
|
|
165
165
|
)}
|
|
166
|
-
<span className="pkt-header__logo-service">
|
|
166
|
+
<span className="pkt-header__logo-service" translate="no">
|
|
167
|
+
{serviceName}
|
|
168
|
+
</span>
|
|
167
169
|
</div>
|
|
168
170
|
<nav className="pkt-header__actions">
|
|
169
171
|
<ul className="pkt-header__actions-row">
|
|
@@ -195,8 +197,12 @@ export const PktHeader = forwardRef(
|
|
|
195
197
|
onClick={openUserMenu}
|
|
196
198
|
>
|
|
197
199
|
<PktIcon name="user" className="pkt-btn__icon" />
|
|
198
|
-
<span className="pkt-header__user-fullname"
|
|
199
|
-
|
|
200
|
+
<span className="pkt-header__user-fullname" translate="no">
|
|
201
|
+
{representing?.name || user?.name}
|
|
202
|
+
</span>
|
|
203
|
+
<span className="pkt-header__user-shortname" translate="no">
|
|
204
|
+
{representing?.shortname || user?.shortname}
|
|
205
|
+
</span>
|
|
200
206
|
<PktIcon name="chevron-thin-down" className="pkt-btn--closed" />
|
|
201
207
|
<PktIcon name="chevron-thin-up" className="pkt-btn--open" />
|
|
202
208
|
</button>
|
|
@@ -204,7 +210,9 @@ export const PktHeader = forwardRef(
|
|
|
204
210
|
{user && (
|
|
205
211
|
<li>
|
|
206
212
|
<div className="pkt-user-menu__label">Pålogget som</div>
|
|
207
|
-
<div className="pkt-user-menu__name">
|
|
213
|
+
<div className="pkt-user-menu__name" translate="no">
|
|
214
|
+
{user.name}
|
|
215
|
+
</div>
|
|
208
216
|
{user.lastLoggedIn && (
|
|
209
217
|
<div className="pkt-user-menu__last-logged-in">
|
|
210
218
|
Sist pålogget: <time>{lastLoggedIn}</time>
|
|
@@ -238,7 +246,9 @@ export const PktHeader = forwardRef(
|
|
|
238
246
|
{representing && (
|
|
239
247
|
<>
|
|
240
248
|
<div className="pkt-user-menu__label">Representerer</div>
|
|
241
|
-
<div className="pkt-user-menu__name">
|
|
249
|
+
<div className="pkt-user-menu__name" translate="no">
|
|
250
|
+
{representing.name}
|
|
251
|
+
</div>
|
|
242
252
|
{representing.orgNumber && (
|
|
243
253
|
<div className="pkt-user-menu__org-number">Org.nr. {representing.orgNumber}</div>
|
|
244
254
|
)}
|
|
@@ -3,109 +3,155 @@ import { render, screen } from '@testing-library/react'
|
|
|
3
3
|
import '@testing-library/jest-dom'
|
|
4
4
|
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
5
5
|
import { PktProgressbar } from './Progressbar'
|
|
6
|
+
import exp from 'constants'
|
|
6
7
|
|
|
7
8
|
expect.extend(toHaveNoViolations)
|
|
8
9
|
|
|
9
10
|
describe('PktProgressbar', () => {
|
|
10
11
|
describe('rendering', () => {
|
|
11
|
-
|
|
12
|
-
render(<PktProgressbar id="progress1" valueCurrent={50} />)
|
|
13
|
-
|
|
12
|
+
test('renders with default props', async () => {
|
|
13
|
+
const { container } = render(<PktProgressbar id="progress1" valueCurrent={50} />)
|
|
14
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
15
|
+
|
|
16
|
+
const progressbar = container.querySelector('pkt-progressbar')
|
|
17
|
+
|
|
14
18
|
expect(progressbar).toBeInTheDocument()
|
|
15
|
-
expect(progressbar).toHaveAttribute('
|
|
16
|
-
expect(progressbar).toHaveAttribute('
|
|
17
|
-
expect(progressbar).toHaveAttribute('
|
|
18
|
-
|
|
19
|
+
expect(progressbar).toHaveAttribute('id', 'progress1')
|
|
20
|
+
expect(progressbar).toHaveAttribute('valuemin', '0')
|
|
21
|
+
expect(progressbar).toHaveAttribute('valuemax', '100')
|
|
22
|
+
expect(progressbar).toHaveAttribute('valuecurrent', '50')
|
|
23
|
+
|
|
24
|
+
const bar = progressbar?.querySelector('.pkt-progressbar__bar--dark-blue')
|
|
19
25
|
expect(bar).toBeInTheDocument()
|
|
20
26
|
})
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
render(<PktProgressbar id="progress2" valueCurrent={50} skin="red" />)
|
|
24
|
-
|
|
28
|
+
test('renders with custom skin', async () => {
|
|
29
|
+
const { container } = render(<PktProgressbar id="progress2" valueCurrent={50} skin="red" />)
|
|
30
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
31
|
+
|
|
32
|
+
const progressbar = container.querySelector('pkt-progressbar')
|
|
33
|
+
const bar = progressbar?.querySelector('.pkt-progressbar__bar--red')
|
|
25
34
|
expect(bar).toBeInTheDocument()
|
|
26
35
|
})
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
render(<PktProgressbar id="progress3" valueCurrent={50} title="Progress" />)
|
|
30
|
-
|
|
37
|
+
test('renders title correctly', async () => {
|
|
38
|
+
const { container, getByText } = render(<PktProgressbar id="progress3" valueCurrent={50} title="Progress" />)
|
|
39
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
40
|
+
|
|
41
|
+
const progressbar = container.querySelector('pkt-progressbar')
|
|
42
|
+
|
|
43
|
+
// Select by class
|
|
44
|
+
const title = progressbar?.querySelector('.pkt-progressbar__title')
|
|
31
45
|
expect(title).toBeInTheDocument()
|
|
32
|
-
|
|
46
|
+
|
|
47
|
+
// Select by text
|
|
48
|
+
const titleText = getByText('Progress')
|
|
49
|
+
expect(titleText).toBeInTheDocument()
|
|
33
50
|
})
|
|
34
51
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
test('renders title with center position', async () => {
|
|
53
|
+
const { container } = render(
|
|
54
|
+
<PktProgressbar id="progress4" valueCurrent={50} title="Progress" titlePosition="center" />,
|
|
55
|
+
)
|
|
56
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
57
|
+
const title = container.querySelector('.pkt-progressbar__title-center')
|
|
58
|
+
expect(title).toBeInTheDocument()
|
|
39
59
|
})
|
|
40
60
|
|
|
41
|
-
|
|
42
|
-
render(<PktProgressbar id="progress5" valueCurrent={50} statusType="percentage" />)
|
|
43
|
-
|
|
61
|
+
test('renders status as percentage', async () => {
|
|
62
|
+
const { container } = render(<PktProgressbar id="progress5" valueCurrent={50} statusType="percentage" />)
|
|
63
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
64
|
+
const status = container.querySelector('.pkt-progressbar__status')
|
|
65
|
+
console.log(status)
|
|
44
66
|
expect(status).toBeInTheDocument()
|
|
45
|
-
expect(status).
|
|
67
|
+
expect(status).toHaveTextContent('50%')
|
|
46
68
|
})
|
|
47
69
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
test('renders status as fraction', async () => {
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<PktProgressbar id="progress6" valueCurrent={50} valueMax={200} statusType="fraction" />,
|
|
73
|
+
)
|
|
74
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
75
|
+
const status = container.querySelector('.pkt-progressbar__status')
|
|
51
76
|
expect(status).toBeInTheDocument()
|
|
52
|
-
expect(status).
|
|
77
|
+
expect(status).toHaveTextContent('50 av 200')
|
|
53
78
|
})
|
|
54
79
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
80
|
+
test('renders status with center placement', async () => {
|
|
81
|
+
const { container } = render(
|
|
82
|
+
<PktProgressbar id="progress7" valueCurrent={50} statusType="percentage" statusPlacement="center" />,
|
|
83
|
+
)
|
|
84
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
85
|
+
const status = container.querySelector('.pkt-progressbar__status--center')
|
|
86
|
+
expect(status).toBeInTheDocument()
|
|
59
87
|
})
|
|
60
88
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
89
|
+
test('renders status with following placement', async () => {
|
|
90
|
+
const { container } = render(
|
|
91
|
+
<PktProgressbar id="progress8" valueCurrent={50} statusType="percentage" statusPlacement="following" />,
|
|
92
|
+
)
|
|
93
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
94
|
+
const status = container.querySelector('.pkt-progressbar__status-placement--following')
|
|
95
|
+
expect(status).toBeInTheDocument()
|
|
65
96
|
})
|
|
66
97
|
|
|
67
|
-
|
|
68
|
-
render(<PktProgressbar id="progress9" valueCurrent={50} ariaLabel="Progress bar" />)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
expect(progressbar).
|
|
98
|
+
test('handles aria-label correctly', async () => {
|
|
99
|
+
const { container } = render(<PktProgressbar id="progress9" valueCurrent={50} ariaLabel="Progress bar" />)
|
|
100
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
101
|
+
const progressbar = container.querySelector('pkt-progressbar')
|
|
102
|
+
expect(progressbar).toHaveAttribute('arialabel', 'Progress bar')
|
|
103
|
+
expect(progressbar).toHaveAttribute('arialabelledby', '')
|
|
72
104
|
})
|
|
73
105
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
test('handles role meter correctly', async () => {
|
|
107
|
+
const { container } = render(
|
|
108
|
+
<PktProgressbar id="progress10" role="meter" valueCurrent={50} ariaLabel="Meter bar" />,
|
|
109
|
+
)
|
|
110
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
111
|
+
const progressbar = container.querySelector('pkt-progressbar')
|
|
112
|
+
expect(progressbar).toHaveAttribute('role', 'meter')
|
|
78
113
|
})
|
|
79
114
|
|
|
80
|
-
|
|
81
|
-
render(<PktProgressbar valueCurrent={50} title="Progress" id="
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
115
|
+
test('handles id for title and aria-labelledby correctly', async () => {
|
|
116
|
+
const { container } = render(<PktProgressbar valueCurrent={50} title="Progress" id="progressId" />)
|
|
117
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
118
|
+
const title = container.querySelector('.pkt-progressbar__title')
|
|
119
|
+
expect(title).toHaveAttribute('id', 'progressId-title')
|
|
120
|
+
|
|
121
|
+
const progressbarDiv = container.querySelector('.pkt-progressbar__bar-wrapper')
|
|
122
|
+
expect(progressbarDiv).toBeInTheDocument()
|
|
123
|
+
expect(progressbarDiv).toHaveAttribute('aria-labelledby', 'progressId-title')
|
|
86
124
|
})
|
|
87
125
|
|
|
88
|
-
|
|
89
|
-
render(<PktProgressbar valueCurrent={51} />)
|
|
126
|
+
test('generates id if none is provided', async () => {
|
|
90
127
|
const { container } = render(<PktProgressbar valueCurrent={50} />)
|
|
91
|
-
|
|
92
|
-
|
|
128
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
129
|
+
|
|
130
|
+
const outerDiv = container.querySelector('.pkt-progressbar__container')
|
|
131
|
+
const id = outerDiv?.getAttribute('id')
|
|
93
132
|
expect(id).toHaveLength(36)
|
|
94
133
|
})
|
|
95
134
|
|
|
96
|
-
|
|
97
|
-
const ref =
|
|
98
|
-
const {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
expect(
|
|
135
|
+
test('sets ref correctly', async () => {
|
|
136
|
+
const ref = createRef<HTMLElement>()
|
|
137
|
+
const { unmount } = render(<PktProgressbar ref={ref} id="progress-ref" valueCurrent={50} title="Ref bar" />)
|
|
138
|
+
|
|
139
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
140
|
+
|
|
141
|
+
expect(ref.current).toBeInstanceOf(HTMLElement)
|
|
142
|
+
unmount()
|
|
143
|
+
expect(ref.current).toBeNull()
|
|
103
144
|
})
|
|
104
145
|
})
|
|
105
146
|
|
|
147
|
+
// ACCESSIBILITY TESTS
|
|
148
|
+
|
|
106
149
|
describe('accessibility', () => {
|
|
107
|
-
|
|
108
|
-
const { container } = render(
|
|
150
|
+
test('renders with no wcag errors with axe', async () => {
|
|
151
|
+
const { container } = render(
|
|
152
|
+
<PktProgressbar id="progress-axe" valueCurrent={50} title="Axe test" role="progressbar" />,
|
|
153
|
+
)
|
|
154
|
+
await window.customElements.whenDefined('pkt-progressbar')
|
|
109
155
|
const results = await axe(container)
|
|
110
156
|
expect(results).toHaveNoViolations()
|
|
111
157
|
})
|
|
@@ -1,123 +1,27 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import React, { forwardRef, ForwardedRef, ReactElement } from 'react'
|
|
2
|
+
import { createComponent } from '@lit/react'
|
|
3
|
+
import { PktProgressbar as PktElProgressbar } from '@oslokommune/punkt-elements'
|
|
4
|
+
import type { PktElType, PktElConstructor } from '@/interfaces/IPktElements'
|
|
5
|
+
import type { IPktProgressbar as IPktElProgressbar } from '@oslokommune/punkt-elements'
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
valueCurrent: number
|
|
7
|
-
valueMax?: number
|
|
8
|
-
valueMin?: number
|
|
9
|
-
ariaValueText?: string
|
|
10
|
-
skin?: 'dark-blue' | 'light-blue' | 'green' | 'red'
|
|
11
|
-
title?: string
|
|
12
|
-
titlePosition?: 'left' | 'center'
|
|
13
|
-
statusType?: 'none' | 'percentage' | 'fraction'
|
|
14
|
-
statusPlacement?: 'center' | 'left' | 'following'
|
|
15
|
-
ariaLabel?: string
|
|
16
|
-
ariaLabelledby?: string
|
|
17
|
-
role?: 'progressbar' | 'meter'
|
|
18
|
-
className?: string
|
|
19
|
-
id?: string
|
|
20
|
-
}
|
|
7
|
+
type ExtendedProgressbar = IPktElProgressbar & PktElType
|
|
21
8
|
|
|
22
|
-
export
|
|
23
|
-
(
|
|
24
|
-
{
|
|
25
|
-
valueCurrent,
|
|
26
|
-
valueMin = 0,
|
|
27
|
-
valueMax = 100,
|
|
28
|
-
skin = 'dark-blue',
|
|
29
|
-
title,
|
|
30
|
-
titlePosition = 'left',
|
|
31
|
-
statusType = 'none',
|
|
32
|
-
statusPlacement = 'following',
|
|
33
|
-
id,
|
|
34
|
-
ariaLabel,
|
|
35
|
-
ariaLabelledby,
|
|
36
|
-
role = 'progressbar',
|
|
37
|
-
className,
|
|
38
|
-
ariaValueText,
|
|
39
|
-
...props
|
|
40
|
-
}: IPktProgressbar,
|
|
41
|
-
ref: ForwardedRef<HTMLDivElement>,
|
|
42
|
-
) => {
|
|
43
|
-
const labelRef = useRef(null)
|
|
44
|
-
const [labelWidth, setLabelWidth] = useState(0)
|
|
45
|
-
const [progressId, setProgressId] = useState(id)
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (!id) {
|
|
49
|
-
setProgressId(uuidv4())
|
|
50
|
-
}
|
|
51
|
-
}, [id])
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (labelRef.current) {
|
|
55
|
-
const label: HTMLSpanElement = labelRef.current
|
|
56
|
-
setLabelWidth(label.getBoundingClientRect().width)
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
const totalSteps = valueMax - valueMin
|
|
60
|
-
const percentageOfSteps = (valueCurrent / totalSteps) * 100
|
|
61
|
-
const currentPercentage = valueMax !== 100 || valueMin !== 0 ? Math.round(percentageOfSteps) : valueCurrent
|
|
62
|
-
const formattedTitle = `${valueCurrent} av ${valueMax}`
|
|
63
|
-
const hasStatus = statusType !== 'none'
|
|
64
|
-
|
|
65
|
-
const barClasses = classNames('pkt-progressbar__bar', { [`pkt-progressbar__bar--${skin}`]: skin })
|
|
66
|
-
|
|
67
|
-
const titleClasses = classNames('pkt-progressbar__title', {
|
|
68
|
-
['pkt-progressbar__title-center']: titlePosition === 'center',
|
|
69
|
-
})
|
|
9
|
+
export interface IPktProgressbar extends ExtendedProgressbar {}
|
|
70
10
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
['pkt-progressbar__status-placement--left']: statusPlacement === 'left',
|
|
79
|
-
})
|
|
11
|
+
const LitComponent = createComponent({
|
|
12
|
+
tagName: 'pkt-progressbar',
|
|
13
|
+
elementClass: PktElProgressbar as PktElConstructor<HTMLElement>,
|
|
14
|
+
react: React,
|
|
15
|
+
displayName: 'PktProgressbar',
|
|
16
|
+
events: {},
|
|
17
|
+
})
|
|
80
18
|
|
|
19
|
+
export const PktProgressbar = forwardRef(
|
|
20
|
+
({ children, ...props }: IPktProgressbar, ref: ForwardedRef<HTMLElement>): ReactElement => {
|
|
81
21
|
return (
|
|
82
|
-
<
|
|
83
|
-
{
|
|
84
|
-
|
|
85
|
-
className={classNames('pkt-progressbar__container', className)}
|
|
86
|
-
id={progressId}
|
|
87
|
-
style={
|
|
88
|
-
{
|
|
89
|
-
'--pkt-progress-label-width': `${labelWidth}px`,
|
|
90
|
-
'--pkt-progress-width': `${currentPercentage}%`,
|
|
91
|
-
} as CSSProperties
|
|
92
|
-
}
|
|
93
|
-
>
|
|
94
|
-
{title && (
|
|
95
|
-
<p id={`${progressId}-title`} className={titleClasses}>
|
|
96
|
-
{title}
|
|
97
|
-
</p>
|
|
98
|
-
)}
|
|
99
|
-
|
|
100
|
-
<div
|
|
101
|
-
role={role}
|
|
102
|
-
className="pkt-progressbar__bar-wrapper"
|
|
103
|
-
aria-valuemin={valueMin}
|
|
104
|
-
aria-valuemax={valueMax}
|
|
105
|
-
aria-valuenow={valueCurrent}
|
|
106
|
-
aria-labelledby={ariaLabelledby || (title && `${progressId}-title`)}
|
|
107
|
-
aria-label={ariaLabel}
|
|
108
|
-
aria-valuetext={ariaValueText}
|
|
109
|
-
>
|
|
110
|
-
<div className={barClasses}></div>
|
|
111
|
-
</div>
|
|
112
|
-
|
|
113
|
-
{hasStatus && (
|
|
114
|
-
<div className={statusClasses}>
|
|
115
|
-
<span className={placementClasses} ref={labelRef}>
|
|
116
|
-
{statusType === 'percentage' ? `${currentPercentage}%` : formattedTitle}
|
|
117
|
-
</span>
|
|
118
|
-
</div>
|
|
119
|
-
)}
|
|
120
|
-
</div>
|
|
22
|
+
<LitComponent ref={ref} {...props}>
|
|
23
|
+
<div className="pkt-contents">{children}</div>
|
|
24
|
+
</LitComponent>
|
|
121
25
|
)
|
|
122
26
|
},
|
|
123
27
|
)
|