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

  1. Set fieldTypeProp = new FieldTypePropExpression('string', 'value') and clear fieldStorageSettings when a prop opts in.
  2. Honour the enum: its values become an allowed_icon_ids instance setting, the element passes them to the index and sprite endpoints as an ids parameter (server-side filtering, no JS change), and massageFormValues() strips the pack: 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_picker beside field_type: list_string.
  • After: field_type: string, expression: ℹ︎string␟value, allowed_icon_ids of 43, 50 and 51 on five components.
  • Index 2078 → 5 icons, sprite 5 symbol elements, both with the url.query_args:ids cache context.
  • Bare facebook renders bi-facebook; bootstrap_icons:facebook is rejected by the enum, hence massageFormValues().
  • 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, cspell green
  • Accessibility — audited, no markup added, two pre-existing gaps reported
  • Performance — index payload 60,098 → 272 bytes for a curated prop
  • Security — ids narrows only, probed for widening and injection
  • Developer Documentation — this MR adds an allowed_icon_ids field 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
Edited by Rajab Natshah

Merge request reports

Loading
Loading