fix: #3619510 Force the string field type and honour the prop enum in the icon picker
Issue: #3619510
Problem
CanvasIconPickerHooks::canvasStorablePropShapeAlter() set only fieldWidget. When an SDC prop also declares an enum, Canvas has already picked field_type: list_string with options_select, so that shape stayed and Canvas silently rendered the select: no error, no picker. Affects any Drupal Canvas site, Drupal CMS included.
Setting the field type alone is not enough either: the picker appears, but selections fail SDC validation, because it stores pack:icon_id and the enum lists bare ids. Today's workaround is to drop the curated enum and lose per-component icon curation.
Fix
- Set
fieldTypeProp = new FieldTypePropExpression('string', 'value')and clearfieldStorageSettingswhen a prop opts in. - Honour the
enum: its values become anallowed_icon_idsinstance setting, the element passes them to the index and sprite endpoints as anidsparameter (server-side filtering, no JS change), andmassageFormValues()strips thepack:prefix to match the schema.IconRepository::resolve()already takes a bare id, so the preview chip works.
Testing
Drupal core 11.4.5, PHP 8.4.20, Drupal Canvas 1.10.1, UI Icons 1.1.2, Canvas Icon Picker 1.0.2; a prop with a curated enum over Bootstrap Icons.
- Before: one 52-option
select,field_widget: canvas_icon_pickerbesidefield_type: list_string. - After:
field_type: string,expression: ℹ︎string␟value,allowed_icon_idsof 43, 50 and 51 on five components. - Index 2078 → 5 icons, sprite 5
symbolelements, both with theurl.query_args:idscache context. - Bare
facebookrendersbi-facebook;bootstrap_icons:facebookis rejected by the enum, hencemassageFormValues(). - Still present in 1.0.3: the hook is unchanged at that tag.
Not verified
phpcs and cspell pass locally. phpstan, phpunit, eslint and stylelint were not run locally and gate on the pipeline (gitlab-ci-local is blocked by firecow/gitlab-ci-local#1893). No test added; tests/src/Kernel/PropShapeAlterTest.php was read, not run, and its seven assertions still hold.
Thanks Aaron for this module.
AI-Generated: Yes
Checkpoints:
- File an issue
- Addition/Change/Update/Fix
- Testing to ensure no regression
- Automated unit testing coverage
- Automated functional testing coverage
-
UX/UI designer responsibilities— no markup or design change, reuses the existing picker UI - Readability —
phpcs,phpstan,cspellgreen - Accessibility — audited, no markup added, two pre-existing gaps reported
- Performance — index payload 60,098 → 272 bytes for a curated prop
- Security —
idsnarrows only, probed for widening and injection - Developer Documentation — this MR adds an
allowed_icon_idsfield setting, which is new public API -
User Guide Documentation— no editor-facing change beyond the picker appearing - Reviewed by human
- Code review by maintainers
- Full testing and approval
- Credit contributors
-
Review with the product owner— not applicable to an upstream contrib fix - Release notes snippet
- Release