Skip to content

Commit 299a2e8

Browse files
committed
fix: enable search in select editable by keeping label as string
The select editable rendered by pimcore_select with a store configuration shows a search box (showSearch + optionFilterProp="label"), but typing never narrows the options — every query returns zero matches. Root cause: transformDocumentEditableStoreToOptions wraps every label in <SanitizeHtml>, producing a React element. antd filters options by String(option.label), so for a React element the comparison becomes '[object Object]' and no user query ever matches. Fix: keep label as a plain string so the built-in filter works; move HTML sanitization to render time via a new renderSanitizedLabel helper, exported alongside the transform and wired into the SelectEditable via labelRender / optionRender. XSS protection is unchanged — the label is still wrapped in <SanitizeHtml> at every point it becomes DOM. The helper is exported (not defined locally in the component) so the adjacent MultiSelectEditable, which shares the same transform, can reuse it without duplication.
1 parent b2ffc56 commit 299a2e8

File tree

2 files changed

+21
-3
lines changed

2 files changed

+21
-3
lines changed

assets/js/src/core/modules/element/dynamic-types/definitions/document/editable/components/select-editable/select-editable.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { CreatableSelect } from '@sdk/components'
1313
import { InheritanceOverlay } from '../inheritance-overlay/inheritance-overlay'
1414
import { toCssDimension } from '@sdk/utils'
1515
import { type SelectOptionType } from '@sdk/modules/element'
16+
import { renderSanitizedLabel } from '../../utils/select-options'
1617
import { useFieldWidth } from '@Pimcore/modules/element/dynamic-types/definitions/objects/data-related/providers/field-width/use-field-width'
1718

1819
interface SelectEditableProps {
@@ -59,8 +60,10 @@ export const SelectEditable = ({
5960
className={ className }
6061
creatable={ editable }
6162
disabled={ inherited }
63+
labelRender={ ({ label }) => renderSanitizedLabel(label) }
6264
onChange={ onChange }
6365
optionFilterProp="label"
66+
optionRender={ (option) => renderSanitizedLabel(option.label) }
6467
options={ options }
6568
popupClassName={ className }
6669
popupMatchSelectWidth={ false }

assets/js/src/core/modules/element/dynamic-types/definitions/document/editable/utils/select-options.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ import { SanitizeHtml } from '@Pimcore/components/sanitize-html/sanitize-html'
1616
export type DocumentEditableStoreEntry = [string | number | null, string] | string | number
1717

1818
/**
19-
* Transforms document editable store entries into SelectOptionType array with sanitized HTML labels
19+
* Transforms document editable store entries into SelectOptionType array.
20+
*
21+
* The `label` is returned as a plain string so that antd's built-in search
22+
* (driven by `optionFilterProp="label"`) can match against it. HTML sanitization
23+
* happens at render time via `renderSanitizedLabel`, used by the consuming
24+
* components in their `optionRender` / `labelRender` props.
2025
*/
2126
export const transformDocumentEditableStoreToOptions = (
2227
store?: DocumentEditableStoreEntry[]
@@ -27,15 +32,25 @@ export const transformDocumentEditableStoreToOptions = (
2732

2833
return {
2934
value: String(value),
30-
label: <SanitizeHtml html={ label } />
35+
label: String(label)
3136
}
3237
} else {
3338
const stringValue = String(item)
3439

3540
return {
3641
value: stringValue,
37-
label: <SanitizeHtml html={ stringValue } />
42+
label: stringValue
3843
}
3944
}
4045
}) ?? []
4146
}
47+
48+
/**
49+
* Renders a label with HTML sanitization. Intended for use in antd's
50+
* `labelRender` / `optionRender` props, so that sanitization happens at the
51+
* moment the label becomes DOM — while `label` itself stays a plain string
52+
* so antd's built-in filter keeps working.
53+
*/
54+
export const renderSanitizedLabel = (label: React.ReactNode): React.JSX.Element => (
55+
<SanitizeHtml html={ typeof label === 'string' ? label : String(label ?? '') } />
56+
)

0 commit comments

Comments
 (0)