@oslokommune/punkt-react 13.6.16 → 13.8.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 (69) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/index.d.ts +58 -76
  3. package/dist/punkt-react.es.js +5331 -35936
  4. package/dist/punkt-react.umd.js +422 -552
  5. package/package.json +11 -15
  6. package/src/components/accordion/Accordion.test.tsx +1 -1
  7. package/src/components/accordion/Accordion.tsx +1 -1
  8. package/src/components/accordion/AccordionItem.tsx +6 -5
  9. package/src/components/alert/Alert.tsx +2 -1
  10. package/src/components/breadcrumbs/Breadcrumbs.test.tsx +16 -4
  11. package/src/components/breadcrumbs/Breadcrumbs.tsx +3 -2
  12. package/src/components/button/Button.tsx +3 -2
  13. package/src/components/checkbox/Checkbox.tsx +4 -3
  14. package/src/components/footer/Footer.tsx +6 -5
  15. package/src/components/footerSimple/FooterSimple.tsx +4 -3
  16. package/src/components/icon/Icon.test.tsx +6 -19
  17. package/src/components/index.ts +1 -2
  18. package/src/components/input/Input.tsx +4 -3
  19. package/src/components/radio/RadioButton.tsx +3 -2
  20. package/src/components/searchinput/SearchInput.tsx +3 -3
  21. package/src/components/stepper/Stepper.tsx +6 -6
  22. package/src/components/table/Table.tsx +2 -1
  23. package/src/components/table/TableBody.tsx +2 -1
  24. package/src/components/table/TableData.tsx +2 -1
  25. package/src/components/table/TableDataCell.tsx +2 -1
  26. package/src/components/table/TableHeader.tsx +2 -1
  27. package/src/components/table/TableHeaderCell.tsx +2 -1
  28. package/src/components/table/TableRow.tsx +2 -1
  29. package/src/components/tabs/TabItem.tsx +77 -0
  30. package/src/components/tabs/Tabs.test.tsx +393 -1
  31. package/src/components/tabs/Tabs.tsx +86 -65
  32. package/src/components/tag/Tag.tsx +2 -1
  33. package/src/components/preview/Preview.tsx +0 -274
  34. package/src/components/preview/PreviewCode.tsx +0 -118
  35. package/src/components/preview/PreviewPropEditor.tsx +0 -266
  36. package/src/components/preview/PreviewSpecs.tsx +0 -125
  37. package/src/components/preview/PreviewWithJson.tsx +0 -519
  38. package/src/components/preview/preview-types.ts +0 -42
  39. package/src/components/preview/preview-utils.ts +0 -226
  40. package/src/components/preview/previewJson/accordion.json +0 -84
  41. package/src/components/preview/previewJson/alert.json +0 -27
  42. package/src/components/preview/previewJson/backlink.json +0 -14
  43. package/src/components/preview/previewJson/breadcrumbs.json +0 -17
  44. package/src/components/preview/previewJson/button.json +0 -28
  45. package/src/components/preview/previewJson/card.json +0 -41
  46. package/src/components/preview/previewJson/checkbox.json +0 -21
  47. package/src/components/preview/previewJson/combobox.json +0 -24
  48. package/src/components/preview/previewJson/consent.json +0 -14
  49. package/src/components/preview/previewJson/datepicker.json +0 -14
  50. package/src/components/preview/previewJson/footer-simple.json +0 -17
  51. package/src/components/preview/previewJson/footer.json +0 -29
  52. package/src/components/preview/previewJson/header.json +0 -34
  53. package/src/components/preview/previewJson/icon.json +0 -13
  54. package/src/components/preview/previewJson/input-wrapper.json +0 -39
  55. package/src/components/preview/previewJson/link.json +0 -28
  56. package/src/components/preview/previewJson/linkcard.json +0 -30
  57. package/src/components/preview/previewJson/loader.json +0 -28
  58. package/src/components/preview/previewJson/messagebox.json +0 -28
  59. package/src/components/preview/previewJson/modal.json +0 -65
  60. package/src/components/preview/previewJson/progressbar.json +0 -16
  61. package/src/components/preview/previewJson/radiobutton.json +0 -21
  62. package/src/components/preview/previewJson/searchinput.json +0 -20
  63. package/src/components/preview/previewJson/select.json +0 -73
  64. package/src/components/preview/previewJson/steps.json +0 -72
  65. package/src/components/preview/previewJson/table.json +0 -130
  66. package/src/components/preview/previewJson/tabs.json +0 -33
  67. package/src/components/preview/previewJson/tag.json +0 -26
  68. package/src/components/preview/previewJson/textarea.json +0 -18
  69. package/src/components/preview/previewJson/textinput.json +0 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oslokommune/punkt-react",
3
- "version": "13.6.16",
3
+ "version": "13.8.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",
@@ -33,12 +33,13 @@
33
33
  "lint:fix": "eslint --fix 'src/**/*.{jsx,ts,tsx}'",
34
34
  "format": "prettier --write src//**/*.{ts,tsx,css} --config ./.prettierrc",
35
35
  "preview": "vite preview --outDir dist-app",
36
- "test": "react-scripts test --env=jsdom"
36
+ "test": "vitest run",
37
+ "test:watch": "vitest"
37
38
  },
38
39
  "dependencies": {
39
40
  "@lit-labs/ssr-dom-shim": "^1.2.1",
40
41
  "@lit/react": "^1.0.7",
41
- "@oslokommune/punkt-elements": "^13.6.15",
42
+ "@oslokommune/punkt-elements": "^13.8.0",
42
43
  "prettier": "^3.3.3",
43
44
  "react-element-to-jsx-string": "^15.0.0",
44
45
  "react-hook-form": "^7.53.0",
@@ -51,7 +52,7 @@
51
52
  "@testing-library/jest-dom": "^6.5.0",
52
53
  "@testing-library/react": "^16.0.1",
53
54
  "@testing-library/user-event": "^14.5.2",
54
- "@types/jest": "^29.5.12",
55
+ "@types/jest": "^29.5.14",
55
56
  "@types/jest-axe": "^3.5.9",
56
57
  "@types/node": "^20.12.10",
57
58
  "@types/react": "^18.3.5",
@@ -59,7 +60,7 @@
59
60
  "@types/react-syntax-highlighter": "^15.5.13",
60
61
  "@vitejs/plugin-react": "^4.3.1",
61
62
  "classnames": "^2.5.1",
62
- "eslint": "^9.10.0",
63
+ "eslint": "^9.37.0",
63
64
  "eslint-config-prettier": "^9.1.0",
64
65
  "eslint-plugin-prettier": "^5.2.1",
65
66
  "eslint-plugin-simple-import-sort": "^12.1.1",
@@ -67,11 +68,11 @@
67
68
  "jest-axe": "^9.0.0",
68
69
  "jest-environment-jsdom": "^29.7.0",
69
70
  "react-hooks": "^1.0.1",
70
- "react-scripts": "^5.0.1",
71
71
  "sass": "^1.78.0",
72
- "typescript": "^5.6.2",
73
- "vite": "^5.4.18",
74
- "vite-plugin-dts": "^4.2.1"
72
+ "typescript": "^5.9.3",
73
+ "vite": "^6.3.6",
74
+ "vite-plugin-dts": "^4.5.4",
75
+ "vitest": "^3.2.4"
75
76
  },
76
77
  "peerDependencies": {
77
78
  "@oslokommune/punkt-assets": "*",
@@ -97,11 +98,6 @@
97
98
  "ux",
98
99
  "ui"
99
100
  ],
100
- "jest": {
101
- "transformIgnorePatterns": [
102
- "<rootDir>/node_modules/(?!@lit/react)"
103
- ]
104
- },
105
101
  "repository": {
106
102
  "type": "git",
107
103
  "url": "git+https://github.com/oslokommune/punkt.git"
@@ -110,5 +106,5 @@
110
106
  "url": "https://github.com/oslokommune/punkt/issues"
111
107
  },
112
108
  "license": "MIT",
113
- "gitHead": "82d543a41c3ad5f580586874c4e0547c7fa8f10d"
109
+ "gitHead": "291eaf91a93ce286149605e36547068da3bf90e9"
114
110
  }
@@ -3,7 +3,7 @@ import { axe, toHaveNoViolations } from 'jest-axe'
3
3
  import { PktAccordion } from './Accordion'
4
4
  import { PktAccordionItem } from './AccordionItem'
5
5
  import { render, screen, fireEvent } from '@testing-library/react'
6
- import React, { createRef } from 'react'
6
+ import { createRef } from 'react'
7
7
 
8
8
  expect.extend(toHaveNoViolations)
9
9
 
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import React, { ReactNode, forwardRef, createContext, useContext } from 'react'
3
+ import { ReactNode, forwardRef, createContext, useContext } from 'react'
4
4
 
5
5
  export type TPktAccordionSkin = 'borderless' | 'outlined' | 'beige' | 'blue'
6
6
 
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
- import React, { ReactNode, useState, useEffect, forwardRef } from 'react'
3
+ import { ReactNode, useState, useEffect, forwardRef } from 'react'
4
+ import type { MouseEvent, SyntheticEvent } from 'react'
4
5
  import { PktIcon } from '../icon/Icon'
5
6
  import { useAccordionContext } from './Accordion'
6
7
 
@@ -16,8 +17,8 @@ export interface IPktAccordionItem {
16
17
  children?: ReactNode
17
18
  name?: string
18
19
  className?: string
19
- onClick?: (e: React.MouseEvent<HTMLDetailsElement>) => void
20
- onToggle?: (e: React.SyntheticEvent<HTMLDetailsElement>) => void
20
+ onClick?: (e: MouseEvent<HTMLDetailsElement>) => void
21
+ onToggle?: (e: SyntheticEvent<HTMLDetailsElement>) => void
21
22
  }
22
23
 
23
24
  export const PktAccordionItem = forwardRef<HTMLDetailsElement, IPktAccordionItem>(
@@ -52,7 +53,7 @@ export const PktAccordionItem = forwardRef<HTMLDetailsElement, IPktAccordionItem
52
53
  }
53
54
  }, [defaultOpen, controlledIsOpen])
54
55
 
55
- const handleToggle = (e: React.SyntheticEvent<HTMLDetailsElement>) => {
56
+ const handleToggle = (e: SyntheticEvent<HTMLDetailsElement>) => {
56
57
  const detailsElement = e.currentTarget
57
58
  const newOpenState = detailsElement.open
58
59
 
@@ -63,7 +64,7 @@ export const PktAccordionItem = forwardRef<HTMLDetailsElement, IPktAccordionItem
63
64
  onToggle?.(e)
64
65
  }
65
66
 
66
- const handleClick = (e: React.MouseEvent<HTMLDetailsElement>) => {
67
+ const handleClick = (e: MouseEvent<HTMLDetailsElement>) => {
67
68
  // La native toggle skje først, så trigge onClick
68
69
  setTimeout(() => {
69
70
  onClick?.(e)
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
- import React, { FC, ForwardedRef, forwardRef, ReactElement } from 'react'
3
+ import { FC, ForwardedRef, forwardRef, ReactElement } from 'react'
4
+ import * as React from 'react'
4
5
  import { createComponent, EventName } from '@lit/react'
5
6
  import { PktAlert as PktElAlert } from '@oslokommune/punkt-elements'
6
7
  import type { PktElType, PktElConstructor } from '@/interfaces/IPktElements'
@@ -6,6 +6,18 @@ import { PktBreadcrumbs } from './Breadcrumbs'
6
6
 
7
7
  expect.extend(toHaveNoViolations)
8
8
 
9
+ // Create a Router with future flags to suppress warnings
10
+ const TestRouter = ({ children }: { children: React.ReactNode }) => (
11
+ <Router
12
+ future={{
13
+ v7_startTransition: true,
14
+ v7_relativeSplatPath: true,
15
+ }}
16
+ >
17
+ {children}
18
+ </Router>
19
+ )
20
+
9
21
  describe('PktBreadcrumbs Component', () => {
10
22
  const breadcrumbs = [
11
23
  { text: 'Home', href: '/' },
@@ -15,9 +27,9 @@ describe('PktBreadcrumbs Component', () => {
15
27
 
16
28
  it('renders breadcrumbs correctly with react-router navigation', async () => {
17
29
  const { getAllByText } = render(
18
- <Router>
30
+ <TestRouter>
19
31
  <PktBreadcrumbs breadcrumbs={breadcrumbs} navigationType="router" />
20
- </Router>,
32
+ </TestRouter>,
21
33
  )
22
34
  await window.customElements.whenDefined('pkt-icon')
23
35
 
@@ -37,9 +49,9 @@ describe('PktBreadcrumbs Component', () => {
37
49
 
38
50
  it('renders back link correctly on mobile with router navigation', async () => {
39
51
  const { getAllByText } = render(
40
- <Router>
52
+ <TestRouter>
41
53
  <PktBreadcrumbs breadcrumbs={breadcrumbs} navigationType="router" />
42
- </Router>,
54
+ </TestRouter>,
43
55
  )
44
56
  await window.customElements.whenDefined('pkt-icon')
45
57
 
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
- import React, { ForwardedRef, forwardRef } from 'react'
3
+ import { ForwardedRef, forwardRef } from 'react'
4
+ import type { AnchorHTMLAttributes } from 'react'
4
5
  import { Link } from 'react-router-dom'
5
6
 
6
7
  import PktIcon from '../icon/Icon'
@@ -10,7 +11,7 @@ export interface IBreadcrumbs {
10
11
  href: string
11
12
  }
12
13
 
13
- export interface IPktBreadcrumbs extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
14
+ export interface IPktBreadcrumbs extends AnchorHTMLAttributes<HTMLAnchorElement> {
14
15
  breadcrumbs: IBreadcrumbs[]
15
16
  navigationType?: 'router' | 'anchor'
16
17
  }
@@ -1,5 +1,6 @@
1
1
  'use client'
2
- import React, { ForwardedRef, forwardRef } from 'react'
2
+ import { ForwardedRef, forwardRef } from 'react'
3
+ import type { ButtonHTMLAttributes } from 'react'
3
4
 
4
5
  import { PktIcon } from '../icon/Icon'
5
6
  declare global {
@@ -10,7 +11,7 @@ declare global {
10
11
 
11
12
  window.pktAnimationPath = window.pktAnimationPath || 'https://punkt-cdn.oslo.kommune.no/latest/animations/'
12
13
 
13
- export interface IPktButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {
14
+ export interface IPktButton extends ButtonHTMLAttributes<HTMLButtonElement> {
14
15
  iconName?: string
15
16
  secondIconName?: string
16
17
  mode?: 'light' | 'dark'
@@ -1,6 +1,7 @@
1
- import React, { ChangeEventHandler, ForwardedRef, forwardRef, ReactNode } from 'react'
1
+ import { ChangeEventHandler, ForwardedRef, forwardRef, ReactNode, ReactElement } from 'react'
2
+ import type { InputHTMLAttributes } from 'react'
2
3
 
3
- export interface IPktCheckbox extends React.InputHTMLAttributes<HTMLInputElement> {
4
+ export interface IPktCheckbox extends InputHTMLAttributes<HTMLInputElement> {
4
5
  id: string
5
6
  hasTile?: boolean
6
7
  disabled?: boolean
@@ -44,7 +45,7 @@ export const PktCheckbox = forwardRef(
44
45
  ...props
45
46
  }: IPktCheckbox,
46
47
  ref: ForwardedRef<HTMLInputElement>,
47
- ): React.ReactElement => {
48
+ ): ReactElement => {
48
49
  const classes = [className, 'pkt-input-check'].filter(Boolean).join(' ')
49
50
 
50
51
  const labelClasses = [
@@ -1,6 +1,7 @@
1
1
  'use client'
2
2
 
3
- import React from 'react'
3
+ import { FC, Fragment } from 'react'
4
+ import type { HTMLAttributes } from 'react'
4
5
 
5
6
  import { PktIcon } from '../icon/Icon'
6
7
  import { PktConsent } from '../consent/Consent'
@@ -25,7 +26,7 @@ interface SocialLink {
25
26
  openInNewTab?: boolean
26
27
  }
27
28
 
28
- export interface IPktFooter extends React.HTMLAttributes<HTMLDivElement> {
29
+ export interface IPktFooter extends HTMLAttributes<HTMLDivElement> {
29
30
  columnOne: Column
30
31
  columnTwo: Column
31
32
  socialLinks?: SocialLink[]
@@ -42,7 +43,7 @@ export interface IPktFooter extends React.HTMLAttributes<HTMLDivElement> {
42
43
  onToggleConsent?: (e: CustomEvent) => void
43
44
  }
44
45
 
45
- export const PktFooter: React.FC<IPktFooter> = ({
46
+ export const PktFooter: FC<IPktFooter> = ({
46
47
  columnOne,
47
48
  columnTwo,
48
49
  socialLinks,
@@ -169,7 +170,7 @@ export const PktFooter: React.FC<IPktFooter> = ({
169
170
  {socialLinks
170
171
  .filter((link) => link.iconName)
171
172
  .map((link, index) => (
172
- <React.Fragment key={`sociallinks-${index}`}>
173
+ <Fragment key={`sociallinks-${index}`}>
173
174
  <a
174
175
  href={link.href}
175
176
  aria-label={`til ${link.iconName}`}
@@ -179,7 +180,7 @@ export const PktFooter: React.FC<IPktFooter> = ({
179
180
  >
180
181
  <PktIcon className="pkt-footer__social-icon" name={link.iconName} />
181
182
  </a>
182
- </React.Fragment>
183
+ </Fragment>
183
184
  ))}
184
185
  </div>
185
186
  </div>
@@ -1,11 +1,12 @@
1
1
  'use client'
2
2
 
3
- import React from 'react'
3
+ import { FC } from 'react'
4
+ import type { HTMLAttributes } from 'react'
4
5
 
5
6
  import { PktIcon } from '../icon/Icon'
6
7
  import { PktConsent } from '../consent/Consent'
7
8
 
8
- export interface IPktFooterSimple extends React.HTMLAttributes<HTMLDivElement> {
9
+ export interface IPktFooterSimple extends HTMLAttributes<HTMLDivElement> {
9
10
  links?: Array<{
10
11
  href: string
11
12
  text: string
@@ -25,7 +26,7 @@ export interface IPktFooterSimple extends React.HTMLAttributes<HTMLDivElement> {
25
26
  onToggleConsent?: (e: CustomEvent) => void
26
27
  }
27
28
 
28
- export const PktFooterSimple: React.FC<IPktFooterSimple> = ({
29
+ export const PktFooterSimple: FC<IPktFooterSimple> = ({
29
30
  links = [],
30
31
  openLinksInNewTab = false,
31
32
  personvernOgInfoLink = 'https://www.oslo.kommune.no/personvern-og-informasjonskapsler/',
@@ -1,7 +1,6 @@
1
1
  import '@testing-library/jest-dom'
2
2
 
3
3
  import { render, screen, waitFor } from '../../utils/test-utils'
4
- import React from 'react'
5
4
 
6
5
  import { PktIcon } from './Icon'
7
6
 
@@ -11,26 +10,14 @@ declare global {
11
10
  pktIconPath: string
12
11
  }
13
12
  }
14
- window.pktFetch = (file = 'filnavn.svg') =>
15
- Promise.resolve({
16
- ok: true,
17
- text: () => Promise.resolve(`<svg role="img" data-testid="icon" data-filename=${file}>Her er SVGen</svg>`),
18
- })
19
- window.pktIconPath = 'sti'
20
13
 
21
14
  describe('PktIcon', () => {
22
- const localStorageMock = (() => {
23
- const store: { [key: string]: string } = {}
24
- return {
25
- getItem: function (key: string) {
26
- return store[key] || null
27
- },
28
- setItem: function (key: string, value: string) {
29
- store[key] = value.toString()
30
- },
31
- }
32
- })()
33
- Object.defineProperty(global, 'localStorage', { value: localStorageMock })
15
+ window.pktFetch = (file = 'filnavn.svg') =>
16
+ Promise.resolve({
17
+ ok: true,
18
+ text: () => Promise.resolve(`<svg role="img" data-testid="icon" data-filename=${file}>Her er SVGen</svg>`),
19
+ })
20
+ window.pktIconPath = 'sti'
34
21
 
35
22
  describe('with default fetcher', () => {
36
23
  test('fetches SVG with default fetcher', async () => {
@@ -22,8 +22,6 @@ export { PktLinkCard } from './linkcard/LinkCard'
22
22
  export { PktLoader } from './loader/Loader'
23
23
  export { PktMessagebox } from './messagebox/Messagebox'
24
24
  export { PktModal } from './modal/Modal'
25
- export { PktPreview } from './preview/Preview'
26
- export { PktPreviewWithJson } from './preview/PreviewWithJson'
27
25
  export { PktProgressbar } from './progressbar/Progressbar'
28
26
  export { PktRadioButton } from './radio/RadioButton'
29
27
  export { PktSearchInput } from './searchinput/SearchInput'
@@ -37,6 +35,7 @@ export { PktTableHeader } from './table/TableHeader'
37
35
  export { PktTableHeaderCell } from './table/TableHeaderCell'
38
36
  export { PktTableRow } from './table/TableRow'
39
37
  export { PktTabs } from './tabs/Tabs'
38
+ export { PktTabItem } from './tabs/TabItem'
40
39
  export { PktTag } from './tag/Tag'
41
40
  export { PktTextarea } from './textarea/Textarea'
42
41
  export { PktTextinput } from './textinput/Textinput'
@@ -1,8 +1,9 @@
1
1
  'use client'
2
2
 
3
- import React, { ForwardedRef } from 'react'
3
+ import { ForwardedRef, forwardRef } from 'react'
4
+ import type { InputHTMLAttributes } from 'react'
4
5
 
5
- interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
6
+ interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
6
7
  /** The input's label */
7
8
  label?: string
8
9
  /** The input's id */
@@ -21,7 +22,7 @@ interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
21
22
  * <Input label="First name" id="firstName" validationMessage="First name is required" />
22
23
  *
23
24
  */
24
- export const PktInput = React.forwardRef(
25
+ export const PktInput = forwardRef(
25
26
  ({ label, id, children, ...props }: InputProps, ref: ForwardedRef<HTMLInputElement>): React.ReactElement => {
26
27
  return (
27
28
  <div className="pkt-form-group">
@@ -1,6 +1,7 @@
1
- import React, { ChangeEventHandler, ForwardedRef, forwardRef, ReactNode } from 'react'
1
+ import { ChangeEventHandler, ForwardedRef, forwardRef, ReactNode } from 'react'
2
+ import type { InputHTMLAttributes } from 'react'
2
3
 
3
- export interface IPktRadioButton extends React.InputHTMLAttributes<HTMLInputElement> {
4
+ export interface IPktRadioButton extends InputHTMLAttributes<HTMLInputElement> {
4
5
  id: string
5
6
  name: string
6
7
  label: string
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import React, { ChangeEvent, forwardRef, HTMLProps, ReactNode } from 'react'
3
+ import { ChangeEvent, forwardRef, HTMLProps, ReactNode, createElement } from 'react'
4
4
 
5
5
  import { PktButton } from '../button/Button'
6
6
 
@@ -33,7 +33,7 @@ interface ISearchForm extends ISearch {
33
33
  }
34
34
 
35
35
  interface ISearchInput extends ISearch {
36
- onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
36
+ onChange: (event: ChangeEvent<HTMLInputElement>) => void
37
37
  disabled?: boolean
38
38
  }
39
39
 
@@ -145,7 +145,7 @@ export const PktSearchInput = forwardRef<HTMLInputElement, ISearchInput | ISearc
145
145
  <ul id={`${id}-suggestions`} className="pkt-searchinput__suggestions" aria-live="assertive">
146
146
  {suggestions.map((suggestion, index) => (
147
147
  <li key={`search-suggestion-${index}`}>
148
- {React.createElement(
148
+ {createElement(
149
149
  suggestion.href ? 'a' : suggestion.onClick ? 'button' : 'div',
150
150
  {
151
151
  href: suggestion.href,
@@ -1,11 +1,11 @@
1
1
  'use client'
2
2
 
3
- import { ReactElement, Ref, forwardRef } from 'react'
3
+ import { ReactElement, Ref, forwardRef, Children, isValidElement, cloneElement } from 'react'
4
+ import type { HTMLAttributes } from 'react'
4
5
  import { IPktStep } from './Step'
5
6
  import classNames from 'classnames'
6
- import React from 'react'
7
7
 
8
- export interface IPktStepper extends React.HTMLAttributes<HTMLOListElement> {
8
+ export interface IPktStepper extends HTMLAttributes<HTMLOListElement> {
9
9
  /**
10
10
  * The index of the current active step
11
11
  */
@@ -55,9 +55,9 @@ export const PktStepper = forwardRef(
55
55
  orientation === 'horizontal' ? 'pkt-stepper--horizontal' : 'pkt-stepper--vertical',
56
56
  )
57
57
 
58
- const childrenWithProps = React.Children.map(children, (child, index) => {
59
- if (React.isValidElement(child)) {
60
- return React.cloneElement(child, {
58
+ const childrenWithProps = Children.map(children, (child, index) => {
59
+ if (isValidElement(child)) {
60
+ return cloneElement(child, {
61
61
  className: classNames(child.props.className, {
62
62
  'pkt-step--hideStep': hideNonActiveSteps && index !== activeStep,
63
63
  'pkt-step--hideContent': hideNonActiveStepsContent && index !== activeStep,
@@ -2,10 +2,11 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
7
  export type TTableSkin = 'basic' | 'zebra-blue'
7
8
 
8
- interface ITableProps extends React.HTMLAttributes<HTMLTableElement> {
9
+ interface ITableProps extends HTMLAttributes<HTMLTableElement> {
9
10
  compact?: boolean
10
11
  skin?: 'basic' | 'zebra-blue'
11
12
  responsiveView?: boolean
@@ -2,8 +2,9 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
- interface ITableBodyProps extends React.HTMLAttributes<HTMLTableSectionElement> {
7
+ interface ITableBodyProps extends HTMLAttributes<HTMLTableSectionElement> {
7
8
  className?: string
8
9
  children: React.ReactNode
9
10
  }
@@ -2,8 +2,9 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
- interface TableDataProps extends React.HTMLAttributes<HTMLTableCellElement> {
7
+ interface TableDataProps extends HTMLAttributes<HTMLTableCellElement> {
7
8
  className?: string
8
9
  children: React.ReactNode | React.ReactNode[]
9
10
  }
@@ -2,8 +2,9 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
- interface ITableDataCellProps extends React.HTMLAttributes<HTMLTableCellElement> {
7
+ interface ITableDataCellProps extends HTMLAttributes<HTMLTableCellElement> {
7
8
  className?: string
8
9
  children?: React.ReactNode
9
10
  dataLabel?: string
@@ -2,8 +2,9 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
- interface ITableHeaderProps extends React.HTMLAttributes<HTMLTableSectionElement> {
7
+ interface ITableHeaderProps extends HTMLAttributes<HTMLTableSectionElement> {
7
8
  className?: string
8
9
  children: React.ReactNode
9
10
  }
@@ -2,8 +2,9 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
- interface ITableHeaderCellProps extends React.HTMLAttributes<HTMLTableCellElement> {
7
+ interface ITableHeaderCellProps extends HTMLAttributes<HTMLTableCellElement> {
7
8
  className?: string
8
9
  children: React.ReactNode
9
10
  }
@@ -2,8 +2,9 @@
2
2
 
3
3
  import classNames from 'classnames'
4
4
  import * as React from 'react'
5
+ import type { HTMLAttributes } from 'react'
5
6
 
6
- interface ITableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
7
+ interface ITableRowProps extends HTMLAttributes<HTMLTableRowElement> {
7
8
  className?: string
8
9
  children: React.ReactNode
9
10
  }
@@ -0,0 +1,77 @@
1
+ 'use client'
2
+
3
+ import { ReactNode, MouseEvent, forwardRef } from 'react'
4
+ import { PktIcon } from '../icon/Icon'
5
+ import { PktTag } from '../tag/Tag'
6
+ import type { IPktTag } from '../tag/Tag'
7
+ import { useTabsContext } from './Tabs'
8
+
9
+ export type TSkin = IPktTag['skin']
10
+
11
+ export interface IPktTabItem {
12
+ children: ReactNode
13
+ active?: boolean
14
+ href?: string
15
+ onClick?: (event: MouseEvent) => void
16
+ icon?: string
17
+ controls?: string
18
+ tag?: string
19
+ tagSkin?: TSkin
20
+ index?: number
21
+ }
22
+
23
+ export const PktTabItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, IPktTabItem>(
24
+ ({ children, active, href, onClick, icon, controls, tag, tagSkin, index = 0 }, ref) => {
25
+ const { arrowNav, registerTabRef, handleKeyPress, selectTab } = useTabsContext()
26
+
27
+ const handleClick = (event: MouseEvent<HTMLAnchorElement | HTMLButtonElement>) => {
28
+ selectTab(index)
29
+ onClick?.(event)
30
+ }
31
+
32
+ const commonProps = {
33
+ 'aria-selected': arrowNav ? !!active : undefined,
34
+ 'aria-controls': controls,
35
+ role: arrowNav ? 'tab' : undefined,
36
+ onKeyUp: (event: React.KeyboardEvent) => handleKeyPress(index, event),
37
+ onClick: handleClick,
38
+ tabIndex: active || !arrowNav ? undefined : -1,
39
+ ref: (el: HTMLAnchorElement | HTMLButtonElement | null) => {
40
+ registerTabRef(index, el)
41
+ if (typeof ref === 'function') {
42
+ ref(el)
43
+ } else if (ref) {
44
+ ref.current = el
45
+ }
46
+ },
47
+ }
48
+
49
+ const content = (
50
+ <>
51
+ {icon && <PktIcon name={icon} className="pkt-icon--small" />}
52
+ {children}
53
+ {tag && (
54
+ <PktTag skin={tagSkin} size="small">
55
+ {tag}
56
+ </PktTag>
57
+ )}
58
+ </>
59
+ )
60
+
61
+ if (href) {
62
+ return (
63
+ <a {...commonProps} href={href} className={`pkt-tabs__link ${active ? 'active' : ''}`}>
64
+ {content}
65
+ </a>
66
+ )
67
+ }
68
+
69
+ return (
70
+ <button {...commonProps} type="button" className={`pkt-tabs__button pkt-link-button ${active ? 'active' : ''}`}>
71
+ {content}
72
+ </button>
73
+ )
74
+ },
75
+ )
76
+
77
+ PktTabItem.displayName = 'PktTabItem'