@oslokommune/punkt-react 17.1.3 → 18.0.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 +18 -0
- package/dist/components/backlink/BackLink.d.ts +3 -0
- package/dist/components/breadcrumbs/Breadcrumbs.d.ts +3 -0
- package/dist/components/calendar/types.d.ts +14 -12
- package/dist/components/checkbox/Checkbox.d.ts +5 -0
- package/dist/components/combobox/types.d.ts +5 -0
- package/dist/components/consent/strings.d.ts +1 -85
- package/dist/components/datepicker/DateTags.d.ts +2 -2
- package/dist/components/datepicker/types.d.ts +6 -3
- package/dist/components/fileupload/DropZone.d.ts +3 -0
- package/dist/components/fileupload/FileUpload.d.ts +3 -0
- package/dist/components/header/types.d.ts +5 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/inputwrapper/InputWrapper.d.ts +6 -0
- package/dist/components/radio/RadioButton.d.ts +5 -0
- package/dist/components/searchinput/SearchInput.d.ts +4 -0
- package/dist/components/select/Select.d.ts +3 -0
- package/dist/components/strings/PktStringsProvider.d.ts +21 -0
- package/dist/components/strings/strings-override.test.d.ts +1 -0
- package/dist/components/tag/Tag.d.ts +3 -0
- package/dist/components/textarea/Textarea.d.ts +3 -0
- package/dist/components/textinput/Textinput.d.ts +3 -0
- package/dist/components/timepicker/types.d.ts +3 -2
- package/dist/components/timepicker/useTimepickerState.d.ts +9 -1
- package/dist/punkt-react.cjs +1 -1
- package/dist/punkt-react.js +2969 -2749
- package/dist/shared-strings/consent.d.ts +71 -0
- package/dist/shared-strings/format.d.ts +21 -0
- package/dist/shared-strings/index.d.ts +14 -0
- package/dist/shared-strings/nb.d.ts +118 -0
- package/dist/shared-strings/resolve.d.ts +12 -0
- package/dist/shared-strings/store.d.ts +27 -0
- package/dist/shared-strings/types.d.ts +29 -0
- package/dist/shared-types/fileupload.d.ts +0 -27
- package/dist/shared-types/index.d.ts +1 -2
- package/dist/shared-utils/combobox/index.d.ts +1 -0
- package/dist/shared-utils/combobox/input-utils.d.ts +2 -1
- package/dist/shared-utils/combobox/messages.d.ts +7 -0
- package/dist/shared-utils/combobox/option-utils.d.ts +2 -1
- package/dist/shared-utils/combobox/selection-manager.d.ts +3 -2
- package/package.json +4 -4
- package/src/components/backlink/BackLink.tsx +11 -2
- package/src/components/breadcrumbs/Breadcrumbs.tsx +8 -2
- package/src/components/calendar/Calendar.core.test.tsx +7 -5
- package/src/components/calendar/types.ts +14 -34
- package/src/components/calendar/useCalendarState.ts +16 -2
- package/src/components/checkbox/Checkbox.tsx +20 -4
- package/src/components/combobox/Combobox.tsx +1 -0
- package/src/components/combobox/Listbox.tsx +4 -2
- package/src/components/combobox/types.ts +6 -0
- package/src/components/combobox/useComboboxState.ts +15 -8
- package/src/components/consent/strings.ts +1 -125
- package/src/components/datepicker/DateTags.tsx +4 -3
- package/src/components/datepicker/Datepicker.accessibility.test.tsx +2 -2
- package/src/components/datepicker/Datepicker.tsx +1 -0
- package/src/components/datepicker/DatepickerInputs.tsx +6 -6
- package/src/components/datepicker/types.ts +6 -3
- package/src/components/datepicker/useDatepickerState.ts +4 -5
- package/src/components/fileupload/DropZone.tsx +20 -15
- package/src/components/fileupload/FileUpload.test.tsx +37 -0
- package/src/components/fileupload/FileUpload.tsx +41 -8
- package/src/components/header/HeaderGlobal.tsx +5 -2
- package/src/components/header/HeaderService.tsx +12 -7
- package/src/components/header/types.ts +6 -0
- package/src/components/index.ts +10 -0
- package/src/components/inputwrapper/InputWrapper.tsx +28 -6
- package/src/components/radio/RadioButton.tsx +18 -2
- package/src/components/searchinput/SearchInput.tsx +13 -3
- package/src/components/select/Select.tsx +5 -0
- package/src/components/strings/PktStringsProvider.tsx +38 -0
- package/src/components/strings/strings-override.test.tsx +130 -0
- package/src/components/tag/Tag.tsx +13 -2
- package/src/components/textarea/Textarea.tsx +5 -0
- package/src/components/textinput/Textinput.tsx +5 -0
- package/src/components/timepicker/Timepicker.tsx +1 -0
- package/src/components/timepicker/types.ts +3 -2
- package/src/components/timepicker/useTimepickerState.ts +20 -22
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { describe, expect, test, afterEach } from 'vitest'
|
|
2
|
+
import { render, screen, cleanup } from '@testing-library/react'
|
|
3
|
+
import { resetPktStrings, setPktStrings } from 'shared-strings'
|
|
4
|
+
|
|
5
|
+
import { PktBackLink } from '../backlink/BackLink'
|
|
6
|
+
import { PktBreadcrumbs } from '../breadcrumbs/Breadcrumbs'
|
|
7
|
+
import { PktFileUpload } from '../fileupload/FileUpload'
|
|
8
|
+
import { PktSearchInput } from '../searchinput/SearchInput'
|
|
9
|
+
import { PktTextinput } from '../textinput/Textinput'
|
|
10
|
+
import { PktStringsProvider } from './PktStringsProvider'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sjekker at hvert av de tre lagene faktisk slår gjennom på ekte komponenter:
|
|
14
|
+
* global store, provider og `strings`-propen på komponenten.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
cleanup()
|
|
19
|
+
resetPktStrings()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('strings-propen per komponent', () => {
|
|
23
|
+
test('backlink bruker teksten fra propen', () => {
|
|
24
|
+
render(<PktBackLink href="/" strings={{ backlink: { label: 'Tilbake til lista' } }} />)
|
|
25
|
+
expect(screen.getByLabelText('Tilbake til lista')).toBeInTheDocument()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('breadcrumbs bruker teksten fra propen', () => {
|
|
29
|
+
render(
|
|
30
|
+
<PktBreadcrumbs
|
|
31
|
+
breadcrumbs={[
|
|
32
|
+
{ text: 'Hjem', href: '/' },
|
|
33
|
+
{ text: 'Skjema', href: '/skjema' },
|
|
34
|
+
]}
|
|
35
|
+
strings={{ breadcrumbs: { ariaLabel: 'Sti' } }}
|
|
36
|
+
/>,
|
|
37
|
+
)
|
|
38
|
+
expect(screen.getByLabelText('Sti')).toBeInTheDocument()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('searchinput bruker teksten fra propen', () => {
|
|
42
|
+
render(
|
|
43
|
+
<PktSearchInput id="s" strings={{ searchinput: { placeholder: 'Finn ansatt' } }} />,
|
|
44
|
+
)
|
|
45
|
+
expect(screen.getByPlaceholderText('Finn ansatt')).toBeInTheDocument()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('fileupload bruker drop zone-tekst fra propen', () => {
|
|
49
|
+
render(
|
|
50
|
+
<PktFileUpload
|
|
51
|
+
name="files"
|
|
52
|
+
multiple
|
|
53
|
+
strings={{
|
|
54
|
+
fileupload: {
|
|
55
|
+
dropZoneDragMultiple: 'Dra dokumentene hit eller',
|
|
56
|
+
dropZoneOpenFileDialogMultiple: 'bla i filene',
|
|
57
|
+
},
|
|
58
|
+
}}
|
|
59
|
+
/>,
|
|
60
|
+
)
|
|
61
|
+
expect(screen.getByText(/Dra dokumentene hit eller/)).toBeInTheDocument()
|
|
62
|
+
expect(screen.getByText('bla i filene')).toBeInTheDocument()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('textinput sender propen videre til input-wrapperen', () => {
|
|
66
|
+
render(
|
|
67
|
+
<PktTextinput
|
|
68
|
+
id="t"
|
|
69
|
+
name="t"
|
|
70
|
+
label="Navn"
|
|
71
|
+
optionalTag
|
|
72
|
+
strings={{ forms: { optional: 'Frivillig' } }}
|
|
73
|
+
/>,
|
|
74
|
+
)
|
|
75
|
+
expect(screen.getByText('Frivillig')).toBeInTheDocument()
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
describe('lagene i rekkefølge', () => {
|
|
80
|
+
test('propen vinner over den globale overstyringen', () => {
|
|
81
|
+
setPktStrings({ searchinput: { placeholder: 'Global' } })
|
|
82
|
+
render(<PktSearchInput id="s" strings={{ searchinput: { placeholder: 'Instans' } }} />)
|
|
83
|
+
expect(screen.getByPlaceholderText('Instans')).toBeInTheDocument()
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('den globale overstyringen gjelder uten prop', () => {
|
|
87
|
+
setPktStrings({ searchinput: { placeholder: 'Global' } })
|
|
88
|
+
render(<PktSearchInput id="s" />)
|
|
89
|
+
expect(screen.getByPlaceholderText('Global')).toBeInTheDocument()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test('provideren gjelder for undertreet', () => {
|
|
93
|
+
render(
|
|
94
|
+
<PktStringsProvider strings={{ forms: { optional: 'Kan stå tomt' } }}>
|
|
95
|
+
<PktTextinput id="t" name="t" label="Navn" optionalTag />
|
|
96
|
+
</PktStringsProvider>,
|
|
97
|
+
)
|
|
98
|
+
expect(screen.getByText('Kan stå tomt')).toBeInTheDocument()
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('propen vinner over provideren', () => {
|
|
102
|
+
render(
|
|
103
|
+
<PktStringsProvider strings={{ forms: { optional: 'Fra provider' } }}>
|
|
104
|
+
<PktTextinput
|
|
105
|
+
id="t"
|
|
106
|
+
name="t"
|
|
107
|
+
label="Navn"
|
|
108
|
+
optionalTag
|
|
109
|
+
strings={{ forms: { optional: 'Fra prop' } }}
|
|
110
|
+
/>
|
|
111
|
+
</PktStringsProvider>,
|
|
112
|
+
)
|
|
113
|
+
expect(screen.getByText('Fra prop')).toBeInTheDocument()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test('den utfasede optionalText-propen vinner over alt', () => {
|
|
117
|
+
setPktStrings({ forms: { optional: 'Global' } })
|
|
118
|
+
render(
|
|
119
|
+
<PktTextinput
|
|
120
|
+
id="t"
|
|
121
|
+
name="t"
|
|
122
|
+
label="Navn"
|
|
123
|
+
optionalTag
|
|
124
|
+
optionalText="Gammel"
|
|
125
|
+
strings={{ forms: { optional: 'Fra prop' } }}
|
|
126
|
+
/>,
|
|
127
|
+
)
|
|
128
|
+
expect(screen.getByText('Gammel')).toBeInTheDocument()
|
|
129
|
+
})
|
|
130
|
+
})
|
|
@@ -17,8 +17,13 @@ import {
|
|
|
17
17
|
import type { TTagSkin } from 'shared-types'
|
|
18
18
|
|
|
19
19
|
import { PktIcon } from '../icon/Icon'
|
|
20
|
+
import { usePktStrings } from '../../hooks/usePktStrings'
|
|
21
|
+
import { formatString, type TPktStringsOverride } from 'shared-strings'
|
|
20
22
|
|
|
21
23
|
interface BasePktTagProps {
|
|
24
|
+
/** Overstyrer tekster for denne komponenten. */
|
|
25
|
+
strings?: TPktStringsOverride
|
|
26
|
+
|
|
22
27
|
skin?: TTagSkin
|
|
23
28
|
textStyle?: 'normal-text' | 'thin-text'
|
|
24
29
|
size?: 'small' | 'medium' | 'large'
|
|
@@ -56,6 +61,7 @@ export const PktTag = forwardRef<HTMLSpanElement | HTMLButtonElement, ButtonPktT
|
|
|
56
61
|
onClose,
|
|
57
62
|
type,
|
|
58
63
|
'aria-description': ariaDescriptionPropValue,
|
|
64
|
+
strings,
|
|
59
65
|
...props
|
|
60
66
|
}: ButtonPktTagProps | SpanPktTagProps,
|
|
61
67
|
forwardedRef: ForwardedRef<HTMLElement>,
|
|
@@ -76,9 +82,14 @@ export const PktTag = forwardRef<HTMLSpanElement | HTMLButtonElement, ButtonPktT
|
|
|
76
82
|
setLabelText(spanRef.current?.textContent?.trim() ?? '')
|
|
77
83
|
}, [children])
|
|
78
84
|
|
|
85
|
+
const s = usePktStrings(['tag'], strings)
|
|
86
|
+
|
|
79
87
|
const ariaDescription = useMemo(() => {
|
|
80
|
-
if (closeTag && !ariaLabel)
|
|
81
|
-
|
|
88
|
+
if (closeTag && !ariaLabel)
|
|
89
|
+
return (
|
|
90
|
+
(labelText && formatString(s.tag.remove, { label: labelText })) || ariaDescriptionPropValue
|
|
91
|
+
)
|
|
92
|
+
}, [closeTag, ariaLabel, labelText, ariaDescriptionPropValue, s])
|
|
82
93
|
|
|
83
94
|
const classes = {
|
|
84
95
|
'pkt-tag': true,
|
|
@@ -14,8 +14,11 @@ import {
|
|
|
14
14
|
import { PktInputWrapper } from '../inputwrapper/InputWrapper'
|
|
15
15
|
import { TPktInputSize } from 'shared-types/size'
|
|
16
16
|
import { describedByIds } from 'shared-utils/forms/described-by'
|
|
17
|
+
import type { TPktStringsOverride } from 'shared-strings'
|
|
17
18
|
|
|
18
19
|
export interface IPktTextarea extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
20
|
+
/** Overstyrer tekster for denne komponenten. */
|
|
21
|
+
strings?: TPktStringsOverride
|
|
19
22
|
id: string
|
|
20
23
|
ariaDescribedby?: string
|
|
21
24
|
ariaLabelledby?: string
|
|
@@ -87,6 +90,7 @@ export const PktTextarea = forwardRef(
|
|
|
87
90
|
readOnly,
|
|
88
91
|
skipForwardTestid = false,
|
|
89
92
|
inputSize = 'medium',
|
|
93
|
+
strings,
|
|
90
94
|
...props
|
|
91
95
|
}: IPktTextarea,
|
|
92
96
|
ref: ForwardedRef<HTMLTextAreaElement>,
|
|
@@ -125,6 +129,7 @@ export const PktTextarea = forwardRef(
|
|
|
125
129
|
return (
|
|
126
130
|
<div className={outerClasses}>
|
|
127
131
|
<PktInputWrapper
|
|
132
|
+
strings={strings}
|
|
128
133
|
ariaDescribedby={ariaDescribedby}
|
|
129
134
|
disabled={disabled}
|
|
130
135
|
errorMessage={errorMessage}
|
|
@@ -14,8 +14,11 @@ import {
|
|
|
14
14
|
import { PktIcon } from '../icon/Icon'
|
|
15
15
|
import { PktInputWrapper } from '../inputwrapper/InputWrapper'
|
|
16
16
|
import { describedByIds } from 'shared-utils/forms/described-by'
|
|
17
|
+
import type { TPktStringsOverride } from 'shared-strings'
|
|
17
18
|
|
|
18
19
|
export interface IPktTextinput extends InputHTMLAttributes<HTMLInputElement> {
|
|
20
|
+
/** Overstyrer tekster for denne komponenten. */
|
|
21
|
+
strings?: TPktStringsOverride
|
|
19
22
|
id: string
|
|
20
23
|
ariaDescribedby?: string
|
|
21
24
|
ariaLabelledby?: string
|
|
@@ -106,6 +109,7 @@ export const PktTextinput = forwardRef(
|
|
|
106
109
|
onChange,
|
|
107
110
|
skipForwardTestid = false,
|
|
108
111
|
inputSize = 'medium',
|
|
112
|
+
strings,
|
|
109
113
|
...props
|
|
110
114
|
}: IPktTextinput,
|
|
111
115
|
ref: ForwardedRef<HTMLInputElement>,
|
|
@@ -140,6 +144,7 @@ export const PktTextinput = forwardRef(
|
|
|
140
144
|
return (
|
|
141
145
|
<div className={outerClasses}>
|
|
142
146
|
<PktInputWrapper
|
|
147
|
+
strings={strings}
|
|
143
148
|
ariaDescribedby={ariaDescribedby}
|
|
144
149
|
disabled={disabled}
|
|
145
150
|
errorMessage={errorMessage}
|
|
@@ -220,6 +220,7 @@ export const PktTimepicker = forwardRef<HTMLDivElement, IPktTimepicker>((props,
|
|
|
220
220
|
onBlur={state.handleFocusOut}
|
|
221
221
|
>
|
|
222
222
|
<PktInputWrapper
|
|
223
|
+
strings={state.stringsOverride}
|
|
223
224
|
forId={state.hoursId}
|
|
224
225
|
label={state.label}
|
|
225
226
|
disabled={state.disabled}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import type { TPktStringsOverride } from 'shared-strings'
|
|
1
2
|
import type { ChangeEvent, FocusEvent, InputHTMLAttributes, ReactNode } from 'react'
|
|
2
3
|
import { TPktInputSize } from 'shared-types/size'
|
|
3
|
-
import type { ITimepickerStrings } from 'shared-types/timepicker'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Props for {@link PktTimepicker}: a React time picker with `HH:MM`, aligned with Elements `pkt-timepicker`.
|
|
@@ -95,7 +95,8 @@ export interface IPktTimepicker extends Omit<
|
|
|
95
95
|
ariaDescribedby?: string
|
|
96
96
|
|
|
97
97
|
/** Copy for hours, minutes, buttons, and popup. */
|
|
98
|
-
|
|
98
|
+
/** Overstyrer tekster for denne komponenten. */
|
|
99
|
+
strings?: TPktStringsOverride
|
|
99
100
|
|
|
100
101
|
/** Change event from the hidden input (`e.target.value` is `HH:MM`). In React, `onChange` already fires on input. */
|
|
101
102
|
onChange?: (e: ChangeEvent<HTMLInputElement>) => void
|
|
@@ -8,13 +8,14 @@ import {
|
|
|
8
8
|
useRef,
|
|
9
9
|
useState,
|
|
10
10
|
} from 'react'
|
|
11
|
-
import { defaultTimepickerStrings } from 'shared-types/timepicker'
|
|
12
11
|
import { getHourOptions, getMinuteOptions, getMinuteStep } from 'shared-utils/timepicker/options'
|
|
13
12
|
import { stepTime } from 'shared-utils/timepicker/stepper'
|
|
14
13
|
import { isValidTimeString, timeToMinutes } from 'shared-utils/timepicker/time-utils'
|
|
15
14
|
|
|
16
15
|
import type { IPktTimepicker } from './types'
|
|
17
16
|
import { TPktInputSize } from 'shared-types/size'
|
|
17
|
+
import { usePktStrings } from '../../hooks/usePktStrings'
|
|
18
|
+
import { formatString, type TPktStrings } from 'shared-strings'
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* ## Why this hook exists (React form model)
|
|
@@ -42,15 +43,6 @@ import { TPktInputSize } from 'shared-types/size'
|
|
|
42
43
|
* node” idea. React components don’t get `attachInternals()` for that API on a `<div>`, so this pattern
|
|
43
44
|
* is the sustainable equivalent in plain React.
|
|
44
45
|
*/
|
|
45
|
-
const FORM_MESSAGES = {
|
|
46
|
-
required: 'Dette feltet er påkrevd',
|
|
47
|
-
invalid: 'Ugyldig verdi',
|
|
48
|
-
timeStepMismatch: 'Må treffe på et steg, for eksempel 0, {step} minutter',
|
|
49
|
-
timeStepMismatchHour: 'Må treffe på hver hele time',
|
|
50
|
-
timeStepMismatchHalfHour: 'Må treffe på hver hele eller halve time',
|
|
51
|
-
rangeUnderflowMin: 'Verdien må være større enn eller lik {min}.',
|
|
52
|
-
rangeOverflowMax: 'Verdien må være mindre enn eller lik {max}.',
|
|
53
|
-
} as const
|
|
54
46
|
|
|
55
47
|
function splitValid(value: string | undefined): [string, string] {
|
|
56
48
|
if (value && isValidTimeString(value)) {
|
|
@@ -68,38 +60,41 @@ function displaySegmentsToCommittedTime(h: string, m: string): string {
|
|
|
68
60
|
function validateTimeValue(
|
|
69
61
|
value: string,
|
|
70
62
|
opts: { required?: boolean; min?: string | number; max?: string | number; step?: number },
|
|
63
|
+
messages: TPktStrings['validation'],
|
|
71
64
|
): { valid: boolean; message?: string } {
|
|
72
65
|
const { required, min, max, step } = opts
|
|
73
66
|
if (required && !value) {
|
|
74
|
-
return { valid: false, message:
|
|
67
|
+
return { valid: false, message: messages.valueMissing }
|
|
75
68
|
}
|
|
76
69
|
if (!value) {
|
|
77
70
|
return { valid: true }
|
|
78
71
|
}
|
|
79
72
|
if (!isValidTimeString(value)) {
|
|
80
|
-
return { valid: false, message:
|
|
73
|
+
return { valid: false, message: messages.typeMismatch }
|
|
81
74
|
}
|
|
82
75
|
const totalMinutes = timeToMinutes(value)
|
|
83
76
|
const minuteStep = getMinuteStep(step)
|
|
84
77
|
if (min && totalMinutes < timeToMinutes(String(min))) {
|
|
85
78
|
return {
|
|
86
79
|
valid: false,
|
|
87
|
-
message:
|
|
80
|
+
message: formatString(messages.rangeUnderflowMin, { min: String(min) }),
|
|
88
81
|
}
|
|
89
82
|
}
|
|
90
83
|
if (max && totalMinutes > timeToMinutes(String(max))) {
|
|
91
84
|
return {
|
|
92
85
|
valid: false,
|
|
93
|
-
message:
|
|
86
|
+
message: formatString(messages.rangeOverflowMax, { max: String(max) }),
|
|
94
87
|
}
|
|
95
88
|
}
|
|
96
89
|
if (step && totalMinutes % minuteStep !== 0) {
|
|
97
90
|
const stepMessage =
|
|
98
91
|
minuteStep === 60
|
|
99
|
-
?
|
|
92
|
+
? messages.timeStepMismatchHour
|
|
100
93
|
: minuteStep === 30
|
|
101
|
-
?
|
|
102
|
-
:
|
|
94
|
+
? messages.timeStepMismatchHalfHour
|
|
95
|
+
: formatString(messages.timeStepMismatch, {
|
|
96
|
+
step: `${minuteStep}, ${minuteStep * 2}, ${minuteStep * 3}`,
|
|
97
|
+
})
|
|
103
98
|
return { valid: false, message: stepMessage }
|
|
104
99
|
}
|
|
105
100
|
return { valid: true }
|
|
@@ -145,7 +140,9 @@ export function useTimepickerState(props: IPktTimepicker, ref: React.ForwardedRe
|
|
|
145
140
|
onBlur: onBlurProp,
|
|
146
141
|
} = props
|
|
147
142
|
|
|
148
|
-
const
|
|
143
|
+
const catalog = usePktStrings(['timepicker', 'validation'], stringsProp)
|
|
144
|
+
const strings = catalog.timepicker
|
|
145
|
+
const stringsOverride = stringsProp
|
|
149
146
|
|
|
150
147
|
const isControlled = value !== undefined
|
|
151
148
|
const initialStringValue = value !== undefined ? (value ?? '') : (defaultValue ?? '')
|
|
@@ -225,10 +222,10 @@ export function useTimepickerState(props: IPktTimepicker, ref: React.ForwardedRe
|
|
|
225
222
|
useEffect(() => {
|
|
226
223
|
const anchor = hoursInputRef.current
|
|
227
224
|
if (!anchor) return
|
|
228
|
-
const validation = validateTimeValue(effectiveValue, { required, min, max, step })
|
|
225
|
+
const validation = validateTimeValue(effectiveValue, { required, min, max, step }, catalog.validation)
|
|
229
226
|
anchor.setCustomValidity(validation.valid ? '' : (validation.message ?? ''))
|
|
230
227
|
setIsInvalid(touched && !validation.valid)
|
|
231
|
-
}, [effectiveValue, required, min, max, step, touched])
|
|
228
|
+
}, [effectiveValue, required, min, max, step, touched, catalog.validation])
|
|
232
229
|
|
|
233
230
|
const commitValue = useCallback(
|
|
234
231
|
(newValue: string) => {
|
|
@@ -282,9 +279,9 @@ export function useTimepickerState(props: IPktTimepicker, ref: React.ForwardedRe
|
|
|
282
279
|
const hidden = changeInputRef.current
|
|
283
280
|
if (!hoursEl) return
|
|
284
281
|
const raw = hidden?.value ?? ''
|
|
285
|
-
const result = validateTimeValue(raw, { required, min, max, step })
|
|
282
|
+
const result = validateTimeValue(raw, { required, min, max, step }, catalog.validation)
|
|
286
283
|
hoursEl.setCustomValidity(result.valid ? '' : (result.message ?? ''))
|
|
287
|
-
}, [syncValueFromDisplay, required, min, max, step])
|
|
284
|
+
}, [syncValueFromDisplay, required, min, max, step, catalog.validation])
|
|
288
285
|
|
|
289
286
|
useEffect(() => {
|
|
290
287
|
const root = containerRef.current
|
|
@@ -793,6 +790,7 @@ export function useTimepickerState(props: IPktTimepicker, ref: React.ForwardedRe
|
|
|
793
790
|
outerClasses,
|
|
794
791
|
inputSize,
|
|
795
792
|
strings,
|
|
793
|
+
stringsOverride,
|
|
796
794
|
label,
|
|
797
795
|
disabled,
|
|
798
796
|
required,
|