@porsche-design-system/components-react 4.0.0 → 4.1.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 +16 -0
- package/cjs/lib/components/input-search.wrapper.cjs +3 -3
- package/esm/lib/components/input-search.wrapper.d.ts +9 -1
- package/esm/lib/components/input-search.wrapper.mjs +3 -3
- package/esm/lib/types.d.ts +9 -0
- package/package.json +2 -2
- package/ssr/cjs/components/dist/styles/esm/styles-entry.cjs +1 -1
- package/ssr/cjs/components/dist/utils/esm/utils-entry.cjs +7 -1
- package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/components/input-search.wrapper.cjs +4 -4
- package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-base.cjs +8 -2
- package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-search.cjs +1 -1
- package/ssr/esm/components/dist/styles/esm/styles-entry.mjs +1 -1
- package/ssr/esm/components/dist/utils/esm/utils-entry.mjs +7 -2
- package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/components/input-search.wrapper.mjs +4 -4
- package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-base.mjs +9 -3
- package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-search.mjs +1 -1
- package/ssr/esm/lib/components/input-search.wrapper.d.ts +9 -1
- package/ssr/esm/lib/dsr-components/input-base.d.ts +3 -1
- package/ssr/esm/lib/types.d.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
|
|
|
14
14
|
|
|
15
15
|
## [Unreleased]
|
|
16
16
|
|
|
17
|
+
## [4.1.0] - 2026-05-06
|
|
18
|
+
|
|
19
|
+
## [4.1.0-rc.0] - 2026-05-05
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `Input Search`: `aria` prop provides additional context for screen reader
|
|
24
|
+
([#4321](https://github.com/porsche-design-system/porsche-design-system/pull/4321))
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- `Tabs Bar`: scrolling page down when below the fold
|
|
29
|
+
([#4392](https://github.com/porsche-design-system/porsche-design-system/pull/4392))
|
|
30
|
+
|
|
17
31
|
## [4.0.0] - 2026-04-29
|
|
18
32
|
|
|
19
33
|
## [4.0.0-rc.2] - 2026-04-28
|
|
@@ -39,6 +53,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
|
|
|
39
53
|
|
|
40
54
|
### Fixed
|
|
41
55
|
|
|
56
|
+
- `Multi Select`, `Select`: not correctly updating when options within `p-optgroup` change dynamically
|
|
57
|
+
([#4278](https://github.com/porsche-design-system/porsche-design-system/pull/4279))
|
|
42
58
|
- `Flyout`, `Modal`, `Sheet`: `overflow: clip` causing issues
|
|
43
59
|
([#4296](https://github.com/porsche-design-system/porsche-design-system/pull/4296))
|
|
44
60
|
- `Link Pure`: focus border of slotted anchor
|
|
@@ -6,16 +6,16 @@ var react = require('react');
|
|
|
6
6
|
var hooks = require('../../hooks.cjs');
|
|
7
7
|
var utils = require('../../utils.cjs');
|
|
8
8
|
|
|
9
|
-
const PInputSearch = /*#__PURE__*/ react.forwardRef(({ autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, ...rest }, ref) => {
|
|
9
|
+
const PInputSearch = /*#__PURE__*/ react.forwardRef(({ aria, autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, ...rest }, ref) => {
|
|
10
10
|
const elementRef = react.useRef(undefined);
|
|
11
11
|
hooks.useEventCallback(elementRef, 'blur', onBlur);
|
|
12
12
|
hooks.useEventCallback(elementRef, 'change', onChange);
|
|
13
13
|
hooks.useEventCallback(elementRef, 'input', onInput);
|
|
14
14
|
const WebComponentTag = hooks.usePrefix('p-input-search');
|
|
15
|
-
const propsToSync = [autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
15
|
+
const propsToSync = [aria, autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
16
16
|
hooks.useBrowserLayoutEffect(() => {
|
|
17
17
|
const { current } = elementRef;
|
|
18
|
-
['autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
18
|
+
['aria', 'autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
19
19
|
}, propsToSync);
|
|
20
20
|
const props = {
|
|
21
21
|
...rest,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { BaseProps } from '../../BaseProps';
|
|
2
|
-
import type { BreakpointCustomizable, InputSearchBlurEventDetail, InputSearchChangeEventDetail, InputSearchInputEventDetail, InputSearchState } from '../types';
|
|
2
|
+
import type { SelectedAriaAttributes, InputSearchAriaAttribute, BreakpointCustomizable, InputSearchBlurEventDetail, InputSearchChangeEventDetail, InputSearchInputEventDetail, InputSearchState } from '../types';
|
|
3
3
|
export type PInputSearchProps = BaseProps & {
|
|
4
|
+
/**
|
|
5
|
+
* Additional ARIA attributes for the native search input (e.g. `role="combobox"`, `aria-expanded`).
|
|
6
|
+
*/
|
|
7
|
+
aria?: SelectedAriaAttributes<InputSearchAriaAttribute>;
|
|
4
8
|
/**
|
|
5
9
|
* Provides a hint to the browser about what type of data the field expects, which can assist with autofill features (e.g., autocomplete='on').
|
|
6
10
|
*/
|
|
@@ -105,6 +109,10 @@ export type PInputSearchProps = BaseProps & {
|
|
|
105
109
|
value?: string;
|
|
106
110
|
};
|
|
107
111
|
export declare const PInputSearch: import("react").ForwardRefExoticComponent<Omit<import("react").DOMAttributes<{}>, "onChange" | "onInput" | "onToggle"> & Pick<import("react").HTMLAttributes<{}>, "suppressHydrationWarning" | "autoFocus" | "className" | "dir" | "hidden" | "id" | "inert" | "lang" | "slot" | "style" | "tabIndex" | "title" | "translate" | "role"> & {
|
|
112
|
+
/**
|
|
113
|
+
* Additional ARIA attributes for the native search input (e.g. `role="combobox"`, `aria-expanded`).
|
|
114
|
+
*/
|
|
115
|
+
aria?: SelectedAriaAttributes<InputSearchAriaAttribute>;
|
|
108
116
|
/**
|
|
109
117
|
* Provides a hint to the browser about what type of data the field expects, which can assist with autofill features (e.g., autocomplete='on').
|
|
110
118
|
*/
|
|
@@ -4,16 +4,16 @@ import { forwardRef, useRef } from 'react';
|
|
|
4
4
|
import { useEventCallback, usePrefix, useBrowserLayoutEffect, useMergedClass } from '../../hooks.mjs';
|
|
5
5
|
import { syncRef } from '../../utils.mjs';
|
|
6
6
|
|
|
7
|
-
const PInputSearch = /*#__PURE__*/ forwardRef(({ autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, ...rest }, ref) => {
|
|
7
|
+
const PInputSearch = /*#__PURE__*/ forwardRef(({ aria, autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, ...rest }, ref) => {
|
|
8
8
|
const elementRef = useRef(undefined);
|
|
9
9
|
useEventCallback(elementRef, 'blur', onBlur);
|
|
10
10
|
useEventCallback(elementRef, 'change', onChange);
|
|
11
11
|
useEventCallback(elementRef, 'input', onInput);
|
|
12
12
|
const WebComponentTag = usePrefix('p-input-search');
|
|
13
|
-
const propsToSync = [autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
13
|
+
const propsToSync = [aria, autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
14
14
|
useBrowserLayoutEffect(() => {
|
|
15
15
|
const { current } = elementRef;
|
|
16
|
-
['autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
16
|
+
['aria', 'autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
17
17
|
}, propsToSync);
|
|
18
18
|
const props = {
|
|
19
19
|
...rest,
|
package/esm/lib/types.d.ts
CHANGED
|
@@ -1137,6 +1137,15 @@ export type InputSearchState = FormState;
|
|
|
1137
1137
|
export type InputSearchChangeEventDetail = Event;
|
|
1138
1138
|
export type InputSearchBlurEventDetail = Event;
|
|
1139
1139
|
export type InputSearchInputEventDetail = InputEvent;
|
|
1140
|
+
declare const INPUT_SEARCH_ARIA_ATTRIBUTES: readonly [
|
|
1141
|
+
"role",
|
|
1142
|
+
"aria-autocomplete",
|
|
1143
|
+
"aria-controls",
|
|
1144
|
+
"aria-expanded",
|
|
1145
|
+
"aria-haspopup",
|
|
1146
|
+
"aria-label"
|
|
1147
|
+
];
|
|
1148
|
+
export type InputSearchAriaAttribute = (typeof INPUT_SEARCH_ARIA_ATTRIBUTES)[number];
|
|
1140
1149
|
export type InputTelState = FormState;
|
|
1141
1150
|
export type InputTelChangeEventDetail = Event;
|
|
1142
1151
|
export type InputTelBlurEventDetail = Event;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porsche-design-system/components-react",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Porsche Design System is a component library designed to help developers create the best experience for software or services distributed by Dr. Ing. h.c. F. Porsche AG.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"porsche",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"url": "https://github.com/porsche-design-system/porsche-design-system"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@porsche-design-system/components-js": "4.
|
|
24
|
+
"@porsche-design-system/components-js": "4.1.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"ag-grid-community": ">= 35.0.0 <36.0.0",
|
|
@@ -3775,7 +3775,7 @@ const OPTION_LIST_SAFE_ZONE = 6;
|
|
|
3775
3775
|
|
|
3776
3776
|
const getCDNBaseURL = () => global.PORSCHE_DESIGN_SYSTEM_CDN_URL + "/porsche-design-system";
|
|
3777
3777
|
|
|
3778
|
-
const prefix = `[Porsche Design System v${"4.
|
|
3778
|
+
const prefix = `[Porsche Design System v${"4.1.0"}]` // this part isn't covered by unit tests
|
|
3779
3779
|
;
|
|
3780
3780
|
const consoleError = (...messages) => {
|
|
3781
3781
|
console.error(prefix, ...messages);
|
|
@@ -3454,7 +3454,7 @@ const hasShowPickerSupport = () => (hasDocument &&
|
|
|
3454
3454
|
'showPicker' in HTMLInputElement.prototype &&
|
|
3455
3455
|
CSS.supports('selector(::-webkit-calendar-picker-indicator)'));
|
|
3456
3456
|
|
|
3457
|
-
const prefix = `[Porsche Design System v${"4.
|
|
3457
|
+
const prefix = `[Porsche Design System v${"4.1.0"}]` // this part isn't covered by unit tests
|
|
3458
3458
|
;
|
|
3459
3459
|
const consoleError$1 = (...messages) => {
|
|
3460
3460
|
console.error(prefix, ...messages);
|
|
@@ -3605,6 +3605,11 @@ const isInfinitePagination = (amountOfPages) => {
|
|
|
3605
3605
|
return amountOfPages > INFINITE_BULLET_THRESHOLD;
|
|
3606
3606
|
};
|
|
3607
3607
|
|
|
3608
|
+
const mergeInputNativeAria = (passthrough, builtIn) => ({
|
|
3609
|
+
...(parseAndGetAriaAttributes(passthrough) ?? {}),
|
|
3610
|
+
...builtIn,
|
|
3611
|
+
});
|
|
3612
|
+
|
|
3608
3613
|
const labelId = 'label';
|
|
3609
3614
|
const descriptionId = 'description';
|
|
3610
3615
|
|
|
@@ -3987,6 +3992,7 @@ exports.isSortable = isSortable;
|
|
|
3987
3992
|
exports.isStateCompleteOrWarning = isStateCompleteOrWarning;
|
|
3988
3993
|
exports.isUrl = isUrl;
|
|
3989
3994
|
exports.labelId = labelId;
|
|
3995
|
+
exports.mergeInputNativeAria = mergeInputNativeAria;
|
|
3990
3996
|
exports.observedNodesMap = observedNodesMap;
|
|
3991
3997
|
exports.parseAndGetAriaAttributes = parseAndGetAriaAttributes;
|
|
3992
3998
|
exports.parseJSONAttribute = parseJSONAttribute;
|
|
@@ -7,23 +7,23 @@ var hooks = require('../../hooks.cjs');
|
|
|
7
7
|
var utils = require('../../utils.cjs');
|
|
8
8
|
var inputSearch = require('../dsr-components/input-search.cjs');
|
|
9
9
|
|
|
10
|
-
const PInputSearch = /*#__PURE__*/ react.forwardRef(({ autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, children, ...rest }, ref) => {
|
|
10
|
+
const PInputSearch = /*#__PURE__*/ react.forwardRef(({ aria, autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, children, ...rest }, ref) => {
|
|
11
11
|
const elementRef = react.useRef(undefined);
|
|
12
12
|
hooks.useEventCallback(elementRef, 'blur', onBlur);
|
|
13
13
|
hooks.useEventCallback(elementRef, 'change', onChange);
|
|
14
14
|
hooks.useEventCallback(elementRef, 'input', onInput);
|
|
15
15
|
const WebComponentTag = hooks.usePrefix('p-input-search');
|
|
16
|
-
const propsToSync = [autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
16
|
+
const propsToSync = [aria, autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
17
17
|
hooks.useBrowserLayoutEffect(() => {
|
|
18
18
|
const { current } = elementRef;
|
|
19
|
-
['autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
19
|
+
['aria', 'autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
20
20
|
}, propsToSync);
|
|
21
21
|
const props = {
|
|
22
22
|
...rest,
|
|
23
23
|
// @ts-ignore
|
|
24
24
|
...(!process.browser
|
|
25
25
|
? {
|
|
26
|
-
children: (jsxRuntime.jsx(inputSearch.DSRInputSearch, { autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value, children })),
|
|
26
|
+
children: (jsxRuntime.jsx(inputSearch.DSRInputSearch, { aria, autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value, children })),
|
|
27
27
|
}
|
|
28
28
|
: {
|
|
29
29
|
children,
|
package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-base.cjs
CHANGED
|
@@ -19,11 +19,17 @@ id, label: label$1, description, loading, initialLoading, required, disabled, st
|
|
|
19
19
|
// onBlur,
|
|
20
20
|
// onKeyDown,
|
|
21
21
|
// refElement,
|
|
22
|
-
start, end, }) => {
|
|
22
|
+
start, end, aria, }) => {
|
|
23
23
|
const { namedSlotChildren } = splitChildren.splitChildren(children);
|
|
24
24
|
const inputDescriptionId = (description || namedSlotChildren.filter(({ props: { slot } }) => slot === 'description').length > 0) ? utilsEntry.descriptionId : undefined;
|
|
25
25
|
const inputMessageId = (message || namedSlotChildren.filter(({ props: { slot } }) => slot === 'message').length > 0) && ['success', 'error'].includes(state) ? stateMessage.messageId : undefined;
|
|
26
|
-
|
|
26
|
+
const inputAria = utilsEntry.mergeInputNativeAria(aria, {
|
|
27
|
+
'aria-describedby': utilsEntry.setAriaIDREF(loading && loadingMessage.loadingId, inputMessageId, inputDescriptionId),
|
|
28
|
+
'aria-invalid': state === 'error' ? 'true' : null,
|
|
29
|
+
'aria-disabled': disabled || loading ? 'true' : null,
|
|
30
|
+
'aria-readonly': readOnly ? 'true' : null,
|
|
31
|
+
});
|
|
32
|
+
return (jsxRuntime.jsxs("div", { className: "root", children: [jsxRuntime.jsx(label.Label, { hasLabel: !!label$1 || namedSlotChildren.filter(({ props: { slot } }) => slot === 'label').length > 0, hasDescription: !!description || namedSlotChildren.filter(({ props: { slot } }) => slot === 'description').length > 0, host: null, label: label$1, description: description, htmlFor: id, isRequired: required, isLoading: loading, isDisabled: disabled }), jsxRuntime.jsxs("div", { className: "wrapper", children: [jsxRuntime.jsx("slot", { name: "start" }), start, jsxRuntime.jsx("input", { ...inputAria, id: id, name: name, form: form, type: type, required: required, placeholder: placeholder || null, maxLength: maxLength, minLength: minLength, spellCheck: spellCheck, max: max, min: min, step: step, defaultValue: value, readOnly: readOnly, autoComplete: autoComplete, disabled: disabled, pattern: pattern, multiple: multiple, dir: "auto" // This overwrites the default: let the browser now decide in which direction the value should be placed.
|
|
27
33
|
}), end, jsxRuntime.jsx("slot", { name: "end" }), loading && jsxRuntime.jsx(spinner_wrapper.PSpinner, { "aria-hidden": "true" })] }), jsxRuntime.jsx(stateMessage.StateMessage, { hasMessage: (message || namedSlotChildren.filter(({ props: { slot } }) => slot === 'message').length > 0) && ['success', 'error'].includes(state), state: state, message: message, host: null }), jsxRuntime.jsx(loadingMessage.LoadingMessage, { loading: loading, initialLoading: initialLoading })] }));
|
|
28
34
|
};
|
|
29
35
|
|
package/ssr/cjs/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-search.cjs
CHANGED
|
@@ -38,7 +38,7 @@ class DSRInputSearch extends react.Component {
|
|
|
38
38
|
render() {
|
|
39
39
|
splitChildren.splitChildren(this.props.children);
|
|
40
40
|
const style = minifyCss.minifyCss(stylesEntry.getInputSearchCss(this.props.disabled, this.props.loading, this.props.hideLabel, this.props.state, this.props.compact, this.props.readOnly, this.props.clear));
|
|
41
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", shadowrootdelegatesfocus: "true", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(inputBase.InputBase, { children: this.props.children, host: null, label: this.props.label, description: this.props.description, id: "input-search", name: this.props.name, form: this.props.form, type: "search", required: this.props.required, placeholder: this.props.placeholder, maxLength: this.props.maxLength, minLength: this.props.minLength, value: this.props.value, readOnly: this.props.readOnly, autoComplete: this.props.autoComplete, disabled: this.props.disabled, state: this.props.state, message: this.props.message, loading: this.props.loading, initialLoading: this.props.initialLoading, ...(this.props.indicator && {
|
|
41
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("template", { shadowroot: "open", shadowrootmode: "open", shadowrootdelegatesfocus: "true", children: [jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsxRuntime.jsx(inputBase.InputBase, { children: this.props.children, host: null, label: this.props.label, description: this.props.description, id: "input-search", name: this.props.name, form: this.props.form, type: "search", required: this.props.required, placeholder: this.props.placeholder, maxLength: this.props.maxLength, minLength: this.props.minLength, value: this.props.value, readOnly: this.props.readOnly, autoComplete: this.props.autoComplete, disabled: this.props.disabled, state: this.props.state, message: this.props.message, loading: this.props.loading, initialLoading: this.props.initialLoading, aria: this.props.aria, ...(this.props.indicator && {
|
|
42
42
|
start: jsxRuntime.jsx(icon_wrapper.PIcon, { "aria-hidden": "true", name: "search", color: "contrast-medium" }),
|
|
43
43
|
}), ...(this.props.clear && {
|
|
44
44
|
end: (jsxRuntime.jsx(buttonPure_wrapper.PButtonPure, { tabIndex: -1, hideLabel: true, className: "button", type: "button", icon: "close", hidden: !this.props.isClearable, disabled: this.props.readOnly || this.props.disabled, children: "Clear field" })),
|
|
@@ -3773,7 +3773,7 @@ const OPTION_LIST_SAFE_ZONE = 6;
|
|
|
3773
3773
|
|
|
3774
3774
|
const getCDNBaseURL = () => global.PORSCHE_DESIGN_SYSTEM_CDN_URL + "/porsche-design-system";
|
|
3775
3775
|
|
|
3776
|
-
const prefix = `[Porsche Design System v${"4.
|
|
3776
|
+
const prefix = `[Porsche Design System v${"4.1.0"}]` // this part isn't covered by unit tests
|
|
3777
3777
|
;
|
|
3778
3778
|
const consoleError = (...messages) => {
|
|
3779
3779
|
console.error(prefix, ...messages);
|
|
@@ -3452,7 +3452,7 @@ const hasShowPickerSupport = () => (hasDocument &&
|
|
|
3452
3452
|
'showPicker' in HTMLInputElement.prototype &&
|
|
3453
3453
|
CSS.supports('selector(::-webkit-calendar-picker-indicator)'));
|
|
3454
3454
|
|
|
3455
|
-
const prefix = `[Porsche Design System v${"4.
|
|
3455
|
+
const prefix = `[Porsche Design System v${"4.1.0"}]` // this part isn't covered by unit tests
|
|
3456
3456
|
;
|
|
3457
3457
|
const consoleError$1 = (...messages) => {
|
|
3458
3458
|
console.error(prefix, ...messages);
|
|
@@ -3603,6 +3603,11 @@ const isInfinitePagination = (amountOfPages) => {
|
|
|
3603
3603
|
return amountOfPages > INFINITE_BULLET_THRESHOLD;
|
|
3604
3604
|
};
|
|
3605
3605
|
|
|
3606
|
+
const mergeInputNativeAria = (passthrough, builtIn) => ({
|
|
3607
|
+
...(parseAndGetAriaAttributes(passthrough) ?? {}),
|
|
3608
|
+
...builtIn,
|
|
3609
|
+
});
|
|
3610
|
+
|
|
3606
3611
|
const labelId = 'label';
|
|
3607
3612
|
const descriptionId = 'description';
|
|
3608
3613
|
|
|
@@ -3930,4 +3935,4 @@ const getTextTagType = (host, tag) => {
|
|
|
3930
3935
|
return tag;
|
|
3931
3936
|
};
|
|
3932
3937
|
|
|
3933
|
-
export { DISPLAY_TAGS, HEADING_TAGS, ItemType, TEXT_TAGS, anchorSlot, attributeMutationMap, buildCrestImgSrc, buildCrestSrcSet, buildFlagUrl, buildIconUrl, consoleError$1 as consoleError, createPaginationItems, createRange, crestSize, descriptionId, displaySizeToTagMap, getBannerAriaAttributes, getButtonAriaAttributes, getButtonBaseAriaAttributes, getButtonPureAriaAttributes, getCDNBaseURL, getComboboxAriaAttributes, getCurrentActivePage, getDirectChildHTMLElement, getDisplayTagType, getFieldsetAriaAttributes, getHTMLElement, getHasNativePopoverSupport, getHeadingTagType, getInlineNotificationAriaAttributes, getListboxAriaAttributes, getSanitizedActiveTabIndex, getSegmentedControlItemAriaAttributes, getStepperHorizontalIconName, getSvgUrl, getSwitchButtonAriaAttributes, getTagName, getTagNameWithoutPrefix, getTextTagType, getTotalPages, hasDocument, hasShowPickerSupport, hasSpecificDirectChildTag, hasVisibleIcon, hasWindow$1 as hasWindow, headerSlot, internalDrilldown, isCurrentInput, isDisabledOrLoading, isElementOfKind, isInfinitePagination, isListTypeOrdered, isSortable, isStateCompleteOrWarning, isUrl, labelId, observedNodesMap, parseAndGetAriaAttributes, parseJSONAttribute, setAriaIDREF, supportsConstructableStylesheets, supportsNativePopover, tempDiv, tempIcon, tempLabel, traverseTreeAndUpdateState, updateDrilldownItemState };
|
|
3938
|
+
export { DISPLAY_TAGS, HEADING_TAGS, ItemType, TEXT_TAGS, anchorSlot, attributeMutationMap, buildCrestImgSrc, buildCrestSrcSet, buildFlagUrl, buildIconUrl, consoleError$1 as consoleError, createPaginationItems, createRange, crestSize, descriptionId, displaySizeToTagMap, getBannerAriaAttributes, getButtonAriaAttributes, getButtonBaseAriaAttributes, getButtonPureAriaAttributes, getCDNBaseURL, getComboboxAriaAttributes, getCurrentActivePage, getDirectChildHTMLElement, getDisplayTagType, getFieldsetAriaAttributes, getHTMLElement, getHasNativePopoverSupport, getHeadingTagType, getInlineNotificationAriaAttributes, getListboxAriaAttributes, getSanitizedActiveTabIndex, getSegmentedControlItemAriaAttributes, getStepperHorizontalIconName, getSvgUrl, getSwitchButtonAriaAttributes, getTagName, getTagNameWithoutPrefix, getTextTagType, getTotalPages, hasDocument, hasShowPickerSupport, hasSpecificDirectChildTag, hasVisibleIcon, hasWindow$1 as hasWindow, headerSlot, internalDrilldown, isCurrentInput, isDisabledOrLoading, isElementOfKind, isInfinitePagination, isListTypeOrdered, isSortable, isStateCompleteOrWarning, isUrl, labelId, mergeInputNativeAria, observedNodesMap, parseAndGetAriaAttributes, parseJSONAttribute, setAriaIDREF, supportsConstructableStylesheets, supportsNativePopover, tempDiv, tempIcon, tempLabel, traverseTreeAndUpdateState, updateDrilldownItemState };
|
|
@@ -5,23 +5,23 @@ import { useEventCallback, usePrefix, useBrowserLayoutEffect, useMergedClass } f
|
|
|
5
5
|
import { syncRef } from '../../utils.mjs';
|
|
6
6
|
import { DSRInputSearch } from '../dsr-components/input-search.mjs';
|
|
7
7
|
|
|
8
|
-
const PInputSearch = /*#__PURE__*/ forwardRef(({ autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, children, ...rest }, ref) => {
|
|
8
|
+
const PInputSearch = /*#__PURE__*/ forwardRef(({ aria, autoComplete, clear = false, compact = false, description = '', disabled = false, form, hideLabel = false, indicator = false, label = '', loading = false, maxLength, message = '', minLength, name, onBlur, onChange, onInput, placeholder = '', readOnly = false, required = false, state = 'none', value = '', className, children, ...rest }, ref) => {
|
|
9
9
|
const elementRef = useRef(undefined);
|
|
10
10
|
useEventCallback(elementRef, 'blur', onBlur);
|
|
11
11
|
useEventCallback(elementRef, 'change', onChange);
|
|
12
12
|
useEventCallback(elementRef, 'input', onInput);
|
|
13
13
|
const WebComponentTag = usePrefix('p-input-search');
|
|
14
|
-
const propsToSync = [autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
14
|
+
const propsToSync = [aria, autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value];
|
|
15
15
|
useBrowserLayoutEffect(() => {
|
|
16
16
|
const { current } = elementRef;
|
|
17
|
-
['autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
17
|
+
['aria', 'autoComplete', 'clear', 'compact', 'description', 'disabled', 'form', 'hideLabel', 'indicator', 'label', 'loading', 'maxLength', 'message', 'minLength', 'name', 'placeholder', 'readOnly', 'required', 'state', 'value'].forEach((propName, i) => (current[propName] = propsToSync[i]));
|
|
18
18
|
}, propsToSync);
|
|
19
19
|
const props = {
|
|
20
20
|
...rest,
|
|
21
21
|
// @ts-ignore
|
|
22
22
|
...(!process.browser
|
|
23
23
|
? {
|
|
24
|
-
children: (jsx(DSRInputSearch, { autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value, children })),
|
|
24
|
+
children: (jsx(DSRInputSearch, { aria, autoComplete, clear, compact, description, disabled, form, hideLabel, indicator, label, loading, maxLength, message, minLength, name, placeholder, readOnly, required, state, value, children })),
|
|
25
25
|
}
|
|
26
26
|
: {
|
|
27
27
|
children,
|
package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-base.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { splitChildren } from '../../splitChildren.mjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
import '../../provider.mjs';
|
|
5
|
-
import { descriptionId, setAriaIDREF } from '../../../../../../components/dist/utils/esm/utils-entry.mjs';
|
|
5
|
+
import { descriptionId, mergeInputNativeAria, setAriaIDREF } from '../../../../../../components/dist/utils/esm/utils-entry.mjs';
|
|
6
6
|
import { loadingId, LoadingMessage } from './loading-message.mjs';
|
|
7
7
|
import { Label } from './label.mjs';
|
|
8
8
|
import { messageId, StateMessage } from './state-message.mjs';
|
|
@@ -17,11 +17,17 @@ id, label, description, loading, initialLoading, required, disabled, state, mess
|
|
|
17
17
|
// onBlur,
|
|
18
18
|
// onKeyDown,
|
|
19
19
|
// refElement,
|
|
20
|
-
start, end, }) => {
|
|
20
|
+
start, end, aria, }) => {
|
|
21
21
|
const { namedSlotChildren } = splitChildren(children);
|
|
22
22
|
const inputDescriptionId = (description || namedSlotChildren.filter(({ props: { slot } }) => slot === 'description').length > 0) ? descriptionId : undefined;
|
|
23
23
|
const inputMessageId = (message || namedSlotChildren.filter(({ props: { slot } }) => slot === 'message').length > 0) && ['success', 'error'].includes(state) ? messageId : undefined;
|
|
24
|
-
|
|
24
|
+
const inputAria = mergeInputNativeAria(aria, {
|
|
25
|
+
'aria-describedby': setAriaIDREF(loading && loadingId, inputMessageId, inputDescriptionId),
|
|
26
|
+
'aria-invalid': state === 'error' ? 'true' : null,
|
|
27
|
+
'aria-disabled': disabled || loading ? 'true' : null,
|
|
28
|
+
'aria-readonly': readOnly ? 'true' : null,
|
|
29
|
+
});
|
|
30
|
+
return (jsxs("div", { className: "root", children: [jsx(Label, { hasLabel: !!label || namedSlotChildren.filter(({ props: { slot } }) => slot === 'label').length > 0, hasDescription: !!description || namedSlotChildren.filter(({ props: { slot } }) => slot === 'description').length > 0, host: null, label: label, description: description, htmlFor: id, isRequired: required, isLoading: loading, isDisabled: disabled }), jsxs("div", { className: "wrapper", children: [jsx("slot", { name: "start" }), start, jsx("input", { ...inputAria, id: id, name: name, form: form, type: type, required: required, placeholder: placeholder || null, maxLength: maxLength, minLength: minLength, spellCheck: spellCheck, max: max, min: min, step: step, defaultValue: value, readOnly: readOnly, autoComplete: autoComplete, disabled: disabled, pattern: pattern, multiple: multiple, dir: "auto" // This overwrites the default: let the browser now decide in which direction the value should be placed.
|
|
25
31
|
}), end, jsx("slot", { name: "end" }), loading && jsx(PSpinner, { "aria-hidden": "true" })] }), jsx(StateMessage, { hasMessage: (message || namedSlotChildren.filter(({ props: { slot } }) => slot === 'message').length > 0) && ['success', 'error'].includes(state), state: state, message: message, host: null }), jsx(LoadingMessage, { loading: loading, initialLoading: initialLoading })] }));
|
|
26
32
|
};
|
|
27
33
|
|
package/ssr/esm/components-react/projects/react-ssr-wrapper/src/lib/dsr-components/input-search.mjs
CHANGED
|
@@ -36,7 +36,7 @@ class DSRInputSearch extends Component {
|
|
|
36
36
|
render() {
|
|
37
37
|
splitChildren(this.props.children);
|
|
38
38
|
const style = minifyCss(getComponentCss$M(this.props.disabled, this.props.loading, this.props.hideLabel, this.props.state, this.props.compact, this.props.readOnly, this.props.clear));
|
|
39
|
-
return (jsxs(Fragment, { children: [jsxs("template", { shadowroot: "open", shadowrootmode: "open", shadowrootdelegatesfocus: "true", children: [jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsx(InputBase, { children: this.props.children, host: null, label: this.props.label, description: this.props.description, id: "input-search", name: this.props.name, form: this.props.form, type: "search", required: this.props.required, placeholder: this.props.placeholder, maxLength: this.props.maxLength, minLength: this.props.minLength, value: this.props.value, readOnly: this.props.readOnly, autoComplete: this.props.autoComplete, disabled: this.props.disabled, state: this.props.state, message: this.props.message, loading: this.props.loading, initialLoading: this.props.initialLoading, ...(this.props.indicator && {
|
|
39
|
+
return (jsxs(Fragment, { children: [jsxs("template", { shadowroot: "open", shadowrootmode: "open", shadowrootdelegatesfocus: "true", children: [jsx("style", { dangerouslySetInnerHTML: { __html: style } }), jsx(InputBase, { children: this.props.children, host: null, label: this.props.label, description: this.props.description, id: "input-search", name: this.props.name, form: this.props.form, type: "search", required: this.props.required, placeholder: this.props.placeholder, maxLength: this.props.maxLength, minLength: this.props.minLength, value: this.props.value, readOnly: this.props.readOnly, autoComplete: this.props.autoComplete, disabled: this.props.disabled, state: this.props.state, message: this.props.message, loading: this.props.loading, initialLoading: this.props.initialLoading, aria: this.props.aria, ...(this.props.indicator && {
|
|
40
40
|
start: jsx(PIcon, { "aria-hidden": "true", name: "search", color: "contrast-medium" }),
|
|
41
41
|
}), ...(this.props.clear && {
|
|
42
42
|
end: (jsx(PButtonPure, { tabIndex: -1, hideLabel: true, className: "button", type: "button", icon: "close", hidden: !this.props.isClearable, disabled: this.props.readOnly || this.props.disabled, children: "Clear field" })),
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { BaseProps } from '../../BaseProps';
|
|
2
|
-
import type { BreakpointCustomizable, InputSearchBlurEventDetail, InputSearchChangeEventDetail, InputSearchInputEventDetail, InputSearchState } from '../types';
|
|
2
|
+
import type { SelectedAriaAttributes, InputSearchAriaAttribute, BreakpointCustomizable, InputSearchBlurEventDetail, InputSearchChangeEventDetail, InputSearchInputEventDetail, InputSearchState } from '../types';
|
|
3
3
|
export type PInputSearchProps = BaseProps & {
|
|
4
|
+
/**
|
|
5
|
+
* Additional ARIA attributes for the native search input (e.g. `role="combobox"`, `aria-expanded`).
|
|
6
|
+
*/
|
|
7
|
+
aria?: SelectedAriaAttributes<InputSearchAriaAttribute>;
|
|
4
8
|
/**
|
|
5
9
|
* Provides a hint to the browser about what type of data the field expects, which can assist with autofill features (e.g., autocomplete='on').
|
|
6
10
|
*/
|
|
@@ -105,6 +109,10 @@ export type PInputSearchProps = BaseProps & {
|
|
|
105
109
|
value?: string;
|
|
106
110
|
};
|
|
107
111
|
export declare const PInputSearch: import("react").ForwardRefExoticComponent<Omit<import("react").DOMAttributes<{}>, "onChange" | "onInput" | "onToggle"> & Pick<import("react").HTMLAttributes<{}>, "suppressHydrationWarning" | "autoFocus" | "className" | "dir" | "hidden" | "id" | "inert" | "lang" | "slot" | "style" | "tabIndex" | "title" | "translate" | "role"> & {
|
|
112
|
+
/**
|
|
113
|
+
* Additional ARIA attributes for the native search input (e.g. `role="combobox"`, `aria-expanded`).
|
|
114
|
+
*/
|
|
115
|
+
aria?: SelectedAriaAttributes<InputSearchAriaAttribute>;
|
|
108
116
|
/**
|
|
109
117
|
* Provides a hint to the browser about what type of data the field expects, which can assist with autofill features (e.g., autocomplete='on').
|
|
110
118
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { AriaAttributes } from '../types';
|
|
1
2
|
import type { FC } from 'react';
|
|
2
3
|
import type { JSX } from 'react';
|
|
3
|
-
import type
|
|
4
|
+
import { type InputBaseState } from '@porsche-design-system/components/dist/utils';
|
|
4
5
|
type InputBaseProps = {
|
|
5
6
|
children?: JSX.Element;
|
|
6
7
|
host: HTMLElement;
|
|
@@ -30,6 +31,7 @@ type InputBaseProps = {
|
|
|
30
31
|
spellCheck?: boolean;
|
|
31
32
|
start?: JSX.Element;
|
|
32
33
|
end?: JSX.Element;
|
|
34
|
+
aria?: AriaAttributes | string;
|
|
33
35
|
};
|
|
34
36
|
export declare const InputBase: FC<InputBaseProps>;
|
|
35
37
|
export {};
|
package/ssr/esm/lib/types.d.ts
CHANGED
|
@@ -1137,6 +1137,15 @@ export type InputSearchState = FormState;
|
|
|
1137
1137
|
export type InputSearchChangeEventDetail = Event;
|
|
1138
1138
|
export type InputSearchBlurEventDetail = Event;
|
|
1139
1139
|
export type InputSearchInputEventDetail = InputEvent;
|
|
1140
|
+
declare const INPUT_SEARCH_ARIA_ATTRIBUTES: readonly [
|
|
1141
|
+
"role",
|
|
1142
|
+
"aria-autocomplete",
|
|
1143
|
+
"aria-controls",
|
|
1144
|
+
"aria-expanded",
|
|
1145
|
+
"aria-haspopup",
|
|
1146
|
+
"aria-label"
|
|
1147
|
+
];
|
|
1148
|
+
export type InputSearchAriaAttribute = (typeof INPUT_SEARCH_ARIA_ATTRIBUTES)[number];
|
|
1140
1149
|
export type InputTelState = FormState;
|
|
1141
1150
|
export type InputTelChangeEventDetail = Event;
|
|
1142
1151
|
export type InputTelBlurEventDetail = Event;
|