@oslokommune/punkt-react 12.14.2 → 12.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oslokommune/punkt-react",
3
- "version": "12.14.2",
3
+ "version": "12.15.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.14.1",
41
+ "@oslokommune/punkt-elements": "^12.15.0",
42
42
  "angular-html-parser": "^6.0.2",
43
43
  "html-format": "^1.1.7",
44
44
  "prettier": "^3.3.3",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@oslokommune/punkt-assets": "^12.14.0",
51
- "@oslokommune/punkt-css": "^12.14.0",
51
+ "@oslokommune/punkt-css": "^12.15.0",
52
52
  "@testing-library/jest-dom": "^6.5.0",
53
53
  "@testing-library/react": "^16.0.1",
54
54
  "@testing-library/user-event": "^14.5.2",
@@ -111,5 +111,5 @@
111
111
  "url": "https://github.com/oslokommune/punkt/issues"
112
112
  },
113
113
  "license": "MIT",
114
- "gitHead": "ebf92a4691afcf52453556ba41f603c14dc953b0"
114
+ "gitHead": "31e12e08dcb69c897c9cfb553e3364efe5e340a1"
115
115
  }
@@ -42,7 +42,7 @@ export const PktPreview: React.FC<PreviewProps> = ({ specs, children, fullWidth
42
42
  return acc
43
43
  }, {})
44
44
  : {}
45
-
45
+ const [iteratedKey, setIteratedKey] = useState(0)
46
46
  const [props, setProps] = useState(initialProps)
47
47
  const [mode, setMode] = useState<'light' | 'dark'>('light')
48
48
  const [htmlContent, setHtmlContent] = useState('')
@@ -153,6 +153,7 @@ export const PktPreview: React.FC<PreviewProps> = ({ specs, children, fullWidth
153
153
  )
154
154
 
155
155
  const handleChange = (key: string, value: any, displayAsFalse: boolean = false) => {
156
+ setIteratedKey(iteratedKey + 1)
156
157
  if (!displayAsFalse && (!value || value == 'false')) {
157
158
  const { [key]: _, ...rest } = props
158
159
  setProps(rest)
@@ -183,6 +184,7 @@ export const PktPreview: React.FC<PreviewProps> = ({ specs, children, fullWidth
183
184
  <div
184
185
  className={`pkt-preview__component ${fullWidth && 'pkt-preview__component--fullwidth'}`}
185
186
  ref={previewComponent}
187
+ key={iteratedKey}
186
188
  >
187
189
  <div>{component}</div>
188
190
  </div>
@@ -41,7 +41,7 @@ export const PktPreviewPropEditor: FC<PropEditorProps> = ({ propKey, spec, props
41
41
  id={propKey}
42
42
  label={propKey}
43
43
  type="checkbox"
44
- checked={props[propKey]}
44
+ checked={props[propKey] || false}
45
45
  onChange={(e) => handleChange(propKey, e.target.checked, spec.displayAsFalse)}
46
46
  labelPosition="right"
47
47
  isSwitch
@@ -56,7 +56,7 @@ export const PktPreviewPropEditor: FC<PropEditorProps> = ({ propKey, spec, props
56
56
  label={spec.name || propKey}
57
57
  helptext={spec.description || null}
58
58
  id={propKey}
59
- value={props[propKey]}
59
+ value={props[propKey] || ''}
60
60
  onChange={(e) => handleChange(propKey, e.target.value)}
61
61
  requiredTag={spec.required}
62
62
  >
@@ -76,8 +76,8 @@ export const PktPreviewPropEditor: FC<PropEditorProps> = ({ propKey, spec, props
76
76
  id={propKey}
77
77
  label={spec.name || propKey}
78
78
  helptext={spec.description || null}
79
- value={props[propKey]}
80
- multiple={spec.variant === 'multiple'}
79
+ value={props[propKey] || ''}
80
+ multiple={!!(spec.variant === 'multiple')}
81
81
  maxlength={999}
82
82
  onChange={(e) => handleChange(propKey, (e.target as HTMLInputElement).value)}
83
83
  requiredTag={spec.required}
@@ -113,7 +113,7 @@ export const PktPreviewPropEditor: FC<PropEditorProps> = ({ propKey, spec, props
113
113
  label={spec.name || propKey}
114
114
  helptext={spec.description || null}
115
115
  type="number"
116
- value={props[propKey]}
116
+ value={props[propKey] || ''}
117
117
  onChange={(e) => handleChange(propKey, parseFloat(e.currentTarget.value))}
118
118
  requiredTag={spec.required}
119
119
  />
@@ -147,7 +147,7 @@ export const PktPreviewPropEditor: FC<PropEditorProps> = ({ propKey, spec, props
147
147
  label={spec.name || propKey}
148
148
  helptext={spec.description || null}
149
149
  type="text"
150
- value={props[propKey]}
150
+ value={props[propKey] || ''}
151
151
  onChange={(e) =>
152
152
  handleChange(propKey, spec.type === 'number' ? parseFloat(e.currentTarget.value) : e.currentTarget.value)
153
153
  }
@@ -49,8 +49,8 @@ export const PktPreviewSpecs: React.FC<{ specs: ISpecObject }> = ({ specs }) =>
49
49
  <PktTable compact>
50
50
  <PktTableHeader>
51
51
  <PktTableRow>
52
- <PktTableHeaderCell>Navn</PktTableHeaderCell>
53
52
  <PktTableHeaderCell>Prop</PktTableHeaderCell>
53
+ <PktTableHeaderCell>Navn</PktTableHeaderCell>
54
54
  <PktTableHeaderCell>Beskrivelse</PktTableHeaderCell>
55
55
  <PktTableHeaderCell>Type</PktTableHeaderCell>
56
56
  <PktTableHeaderCell>Standardverdi</PktTableHeaderCell>
@@ -67,7 +67,7 @@ export const PktPreviewSpecs: React.FC<{ specs: ISpecObject }> = ({ specs }) =>
67
67
  <>
68
68
  <PktTableDataCell dataLabel="Beskrivelse"></PktTableDataCell>
69
69
  <PktTableDataCell dataLabel="Type">
70
- <pre>{value.join(' \n')}</pre>
70
+ <pre>{value.join('\n')}</pre>
71
71
  </PktTableDataCell>
72
72
  </>
73
73
  ) : (
@@ -9,35 +9,39 @@ import { PktTextinput } from './Textinput'
9
9
  expect.extend(toHaveNoViolations)
10
10
 
11
11
  describe('PktTextinput', () => {
12
- test('renders input field with correct props', () => {
12
+ test('renders input field with correct props', async () => {
13
13
  const { getByLabelText } = render(<PktTextinput label="Input Label" id="inputId" />)
14
+ await window.customElements.whenDefined('pkt-textinput')
14
15
 
15
16
  const inputElement = getByLabelText('Input Label')
16
17
  expect(inputElement).toBeInTheDocument()
17
18
  expect(inputElement.tagName).toBe('INPUT')
18
- expect(inputElement.id).toBe('inputId')
19
+ expect(inputElement.id).toBe('inputId-input')
19
20
  })
20
21
 
21
- test('renders error message when hasError prop is true', () => {
22
+ test('renders error message when hasError prop is true', async () => {
22
23
  const { getByText } = render(<PktTextinput label="Input Label" id="inputId" hasError errorMessage="Input error" />)
24
+ await window.customElements.whenDefined('pkt-textinput')
25
+
23
26
  const errorMessage = getByText('Input error')
24
27
  expect(errorMessage).toBeInTheDocument()
25
- expect(errorMessage.closest('pkt-alert')).toHaveAttribute('id', 'inputId-error')
28
+ expect(errorMessage.closest('.pkt-alert')).toHaveAttribute('id', 'inputId-input-error')
26
29
  })
27
30
 
28
31
  describe('PktTextinput', () => {
29
- test('toggles helptext class', () => {
32
+ test('toggles helptext class', async () => {
30
33
  const { getByText, container } = render(
31
34
  <PktTextinput label="Input Label" id="inputId" helptext="Help Text" helptextDropdown="Help Text" />,
32
35
  )
36
+ await window.customElements.whenDefined('pkt-textinput')
33
37
 
34
- const expandButton = getByText('Les mer')
38
+ const expandButton = getByText('Les mer').closest('button') as HTMLButtonElement
35
39
  const helptextElement = container.querySelector('.pkt-inputwrapper__helptext-expandable-closed')
36
40
 
37
- fireEvent.click(expandButton)
41
+ await fireEvent.click(expandButton)
38
42
  expect(helptextElement).toHaveClass('pkt-inputwrapper__helptext-expandable-open')
39
43
 
40
- fireEvent.click(expandButton)
44
+ await fireEvent.click(expandButton)
41
45
  expect(helptextElement).toHaveClass('pkt-inputwrapper__helptext-expandable-closed')
42
46
  })
43
47
  })
@@ -45,6 +49,7 @@ describe('PktTextinput', () => {
45
49
  describe('accessibility', () => {
46
50
  it('renders with no wcag errors with axe', async () => {
47
51
  const { container } = render(<PktTextinput label="Input Label" id="inputId" />)
52
+ await window.customElements.whenDefined('pkt-textinput')
48
53
  const results = await axe(container)
49
54
  expect(results).toHaveNoViolations()
50
55
  })
@@ -1,11 +1,10 @@
1
- import React, { ForwardedRef, forwardRef, InputHTMLAttributes, useRef, useState, ChangeEvent, ReactNode } from 'react'
1
+ import React, { ForwardRefExoticComponent, LegacyRef, ChangeEventHandler, FocusEventHandler, ReactNode } from 'react'
2
+ import { createComponent, EventName } from '@lit/react'
3
+ import { PktTextinput as PktEl } from '@oslokommune/punkt-elements'
4
+ import type { PktElType, PktEventWithTarget } from '@/interfaces/IPktElements'
2
5
 
3
- import { PktIcon } from '../icon/Icon'
4
- import { PktInputWrapper } from '../inputwrapper/InputWrapper'
5
-
6
- export interface IPktTextinput extends InputHTMLAttributes<HTMLInputElement> {
6
+ export interface IPktTextinput extends Omit<PktElType, 'ref'> {
7
7
  id: string
8
- ariaDescribedby?: string
9
8
  ariaLabelledby?: string
10
9
  autocomplete?: string
11
10
  counter?: boolean
@@ -32,112 +31,24 @@ export interface IPktTextinput extends InputHTMLAttributes<HTMLInputElement> {
32
31
  useWrapper?: boolean
33
32
  value?: string
34
33
  omitSearchIcon?: boolean
34
+ ref?: LegacyRef<PktEl>
35
+ onChange?: ChangeEventHandler<HTMLInputElement>
36
+ onInput?: ChangeEventHandler<HTMLInputElement>
37
+ onBlur?: FocusEventHandler<HTMLInputElement>
38
+ onFocus?: FocusEventHandler<HTMLInputElement>
39
+ onValueChange?: (e: CustomEvent) => void
40
+ onToggleHelpText?: (e: CustomEvent) => void
35
41
  }
36
42
 
37
- export const PktTextinput = forwardRef(
38
- (
39
- {
40
- id,
41
- ariaDescribedby,
42
- ariaLabelledby,
43
- autocomplete = 'off',
44
- counter,
45
- counterMaxLength,
46
- className,
47
- disabled = false,
48
- errorMessage,
49
- hasError = false,
50
- helptext,
51
- helptextDropdown,
52
- helptextDropdownButton,
53
- iconNameRight,
54
- inline = false,
55
- fullwidth = false,
56
- label,
57
- name,
58
- optionalTag = false,
59
- optionalText,
60
- requiredTag = false,
61
- requiredText,
62
- placeholder,
63
- prefix,
64
- suffix,
65
- type = 'text',
66
- useWrapper = true,
67
- omitSearchIcon = false,
68
- value,
69
- onChange,
70
- ...props
71
- }: IPktTextinput,
72
- ref: ForwardedRef<HTMLInputElement>,
73
- ) => {
74
- const classNames = [className, 'pkt-textinput'].join(' ')
75
- const labelledBy = ariaLabelledby || `${id}-label`
76
- const shouldShowSearchIcon = type === 'search' && !iconNameRight && !omitSearchIcon
77
-
78
- const internalRef = useRef<HTMLTextAreaElement>(null)
79
- const [counterCurrent, setCounterCurrent] = useState(0)
80
- const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
81
- counter && setCounterCurrent(e.currentTarget?.value?.length || 0)
82
- if (onChange) {
83
- return onChange(e)
84
- }
85
- }
86
-
87
- return (
88
- <PktInputWrapper
89
- ariaDescribedby={ariaDescribedby}
90
- className={classNames}
91
- disabled={disabled}
92
- errorMessage={errorMessage}
93
- forId={id}
94
- hasError={hasError}
95
- helptext={helptext}
96
- helptextDropdown={helptextDropdown}
97
- helptextDropdownButton={helptextDropdownButton}
98
- inline={inline}
99
- label={label}
100
- optionalTag={optionalTag}
101
- optionalText={optionalText}
102
- requiredTag={requiredTag}
103
- requiredText={requiredText}
104
- useWrapper={useWrapper}
105
- counter={counter}
106
- counterCurrent={counterCurrent}
107
- counterMaxLength={counterMaxLength}
108
- >
109
- <div className="pkt-input__container">
110
- {prefix && <div className="pkt-input-prefix">{prefix}</div>}
111
- <input
112
- ref={ref}
113
- className={`pkt-input ${fullwidth ? 'pkt-input--fullwidth' : ''} ${
114
- counterMaxLength && counterCurrent > counterMaxLength ? 'pkt-input--counter-error' : ''
115
- }`}
116
- type={type}
117
- name={name || id}
118
- id={id}
119
- placeholder={placeholder}
120
- autoComplete={autocomplete}
121
- value={value}
122
- disabled={disabled}
123
- aria-invalid={hasError}
124
- aria-errormessage={`${id}-error`}
125
- aria-labelledby={labelledBy}
126
- {...props}
127
- onChange={handleChange}
128
- />
129
- {suffix && (
130
- <p className="pkt-input-suffix">
131
- {suffix}
132
- {iconNameRight && <PktIcon className="pkt-input-suffix-icon" name={iconNameRight} />}
133
- {shouldShowSearchIcon && <PktIcon className="pkt-input-suffix-icon" name="magnifying-glass-big" />}
134
- </p>
135
- )}
136
-
137
- {!suffix && iconNameRight && <PktIcon className="pkt-input-icon" name={iconNameRight} />}
138
- {!suffix && shouldShowSearchIcon && <PktIcon className="pkt-input-icon" name="magnifying-glass-big" />}
139
- </div>
140
- </PktInputWrapper>
141
- )
43
+ export const PktTextinput: ForwardRefExoticComponent<IPktTextinput> = createComponent({
44
+ tagName: 'pkt-textinput',
45
+ elementClass: PktEl,
46
+ react: React,
47
+ displayName: 'PktTextinput',
48
+ events: {
49
+ onChange: 'change' as EventName<PktEventWithTarget>,
50
+ onBlur: 'blur' as EventName<FocusEvent>,
51
+ onFocus: 'focus' as EventName<FocusEvent>,
52
+ onToggleHelpText: 'toggleHelpText' as EventName<CustomEvent>,
142
53
  },
143
- )
54
+ })