diff --git a/src/Element/ComponentFormBase.php b/src/Element/ComponentFormBase.php index 7e4fa5dee3ad1c7270487713312562ed3209e770..08ef13420650c144a6d4f1501ddc54820a31dc36 100644 --- a/src/Element/ComponentFormBase.php +++ b/src/Element/ComponentFormBase.php @@ -187,12 +187,19 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb /** * Get source plugin form. */ - protected static function getSourcePluginForm(FormStateInterface $form_state, SourceInterface $source, string $wrapper_id): array { + protected static function getSourcePluginForm(FormStateInterface $form_state, ?SourceInterface $source, string $wrapper_id): array { + if (!$source) { + return [ + "#type" => 'container', + "#attributes" => [ + 'id' => $wrapper_id, + ], + ]; + } $form = $source->settingsForm([], $form_state); - $form["#type"] = 'container'; - $form['#attributes'] = [ - 'id' => $wrapper_id, - ]; + // @phpstan-ignore-next-line + $form['#prefix'] = "<div id='" . $wrapper_id . "'>" . ($form['#prefix'] ?? ''); + $form['#suffix'] = ($form['#suffix'] ?? '') . "</div>"; // Weird, but :switchSourceForm() AJAX handler doesn't work without that. foreach (Element::children($form) as $child) { if (isset($form[$child]['#description']) && !isset($form[$child]['#description_display'])) { @@ -221,6 +228,28 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb return $source; } } + return static::selectDefaultSource($sources); + } + + /** + * Select default source plugin from a list. + * + * @param array $sources + * The sources. + * + * @return \Drupal\ui_patterns\SourceInterface|null + * The selected source or NULL. + */ + protected static function selectDefaultSource(array $sources): ?SourceInterface { + // Try to return the first widget source. + foreach ($sources as $source) { + /** @var \Drupal\ui_patterns\SourceInterface $source */ + $plugin_definition = $source->getPluginDefinition() ?? []; + $tags = is_array($plugin_definition) ? ($plugin_definition["tags"] ?? []) : []; + if (in_array("widget", $tags)) { + return $source; + } + } return NULL; } @@ -244,6 +273,28 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb return $element; } + /** + * Add title and description to the source element. + * + * @param array $element + * The element. + * + * @return array + * The element with title and description. + */ + protected static function addTitleAndDescription(array $element): array { + if (isset($element["source"]["value"])) { + $element["source"]["value"]["#title_display"] = 'before'; + if (empty($element["source"]["value"]["#title"])) { + $element["source"]["value"]["#title"] = $element["#title"]; + } + if (empty($element["source"]["value"]["#description"])) { + $element["source"]["value"]["#description"] = $element['#description'] ?? NULL; + } + } + return $element; + } + /** * Alter the element after the form is built. * @@ -303,7 +354,7 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb if (empty($sources)) { return []; } - if (count($sources) == 1) { + if ($selected_source && (count($sources) == 1)) { return [ '#type' => 'hidden', '#value' => array_keys($sources)[0], @@ -318,6 +369,7 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb '#attributes' => [ 'class' => ["uip-source-selector"], ], + '#empty_option' => t('- Select -'), // '#prop_id' => $selected_source?->getPropId(), // '#prop_definition' => $selected_source?->getPropDefinition(), '#ajax' => [ diff --git a/src/Element/ComponentPropForm.php b/src/Element/ComponentPropForm.php index 4665483cad407c32572a7ce45c62bd441fcb909c..64f8110fdbaa322e43034d2099bc37abdfa99a30 100644 --- a/src/Element/ComponentPropForm.php +++ b/src/Element/ComponentPropForm.php @@ -76,32 +76,30 @@ class ComponentPropForm extends ComponentFormBase { */ public static function buildForm(array &$element, FormStateInterface $form_state): array { $element['#tree'] = TRUE; - $prop_id = $element['#prop_id']; $component = static::getComponent($element); - if (!$component) { + if (!$component || !isset($element['#prop_id'])) { return []; } + $prop_id = $element['#prop_id']; $definition = $component->metadata->schema['properties'][$prop_id]; $configuration = $element['#default_value'] ?? []; + $wrapper_id = static::getElementId($element, 'ui-patterns-prop-item-' . $prop_id); + // ----- $sources = static::getSources($prop_id, $definition, $element); $selected_source = static::getSelectedSource($configuration, $sources); - if (!$selected_source) { - // Default source is in first position. - $selected_source = current($sources); - } - if (!$selected_source) { - return []; - } - - $wrapper_id = static::getElementId($element, 'ui-patterns-prop-item-' . $prop_id); $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); - $source_form = static::getSourcePluginForm($form_state, $selected_source, $wrapper_id); + $source_form = $selected_source ? static::getSourcePluginForm($form_state, $selected_source, $wrapper_id) : [ + '#type' => 'container', + '#attributes' => [ + 'id' => $wrapper_id, + ], + ]; $element += [ 'source_id' => $source_selector, 'source' => array_merge($source_form, ['#prop_id' => $prop_id]), ]; - if (!($element['#render_sources'] ?? TRUE)) { + if (!($element['#render_sources'] ?? TRUE) && $selected_source) { $element['source_id'] = [ '#type' => 'hidden', '#value' => $selected_source->getPluginId(), @@ -109,14 +107,8 @@ class ComponentPropForm extends ComponentFormBase { } $element = static::addRequired($element, $prop_id); // This allows "widgets" to have a title when #wrap is unset. - if (!($element['#wrap'] ?? TRUE) && isset($element["source"]["value"])) { - $element["source"]["value"]["#title_display"] = 'before'; - if (empty($element["source"]["value"]["#title"])) { - $element["source"]["value"]["#title"] = $element["#title"]; - } - if (empty($element["source"]["value"]["#description"])) { - $element["source"]["value"]["#description"] = $element['#description'] ?? NULL; - } + if (!($element['#wrap'] ?? TRUE)) { + $element = static::addTitleAndDescription($element); } return $element; } diff --git a/src/Element/ComponentSlotForm.php b/src/Element/ComponentSlotForm.php index e19fc3540cd08bd44a9ed4c46dc38968418e4938..d548017b5162e80ffabe4777428aaf53dec801bc 100644 --- a/src/Element/ComponentSlotForm.php +++ b/src/Element/ComponentSlotForm.php @@ -278,9 +278,9 @@ class ComponentSlotForm extends ComponentFormBase { if (!isset($element['#default_value'])) { $element['#default_value'] = $configuration; } + $wrapper_id = static::getElementId($element, 'ui-patterns-slot-item-' . $slot_id); $sources = static::getSources($slot_id, $definition, $element); $selected_source = static::getSelectedSource($configuration, $sources); - $wrapper_id = static::getElementId($element, 'ui-patterns-slot-item-' . $slot_id); $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); $form = [ 'source_id' => $source_selector, @@ -291,7 +291,14 @@ class ComponentSlotForm extends ComponentFormBase { ], ], ]; - return empty($slot_id) ? $form : static::addRequired($form, $slot_id); + if (empty($slot_id)) { + return $form; + } + $form = static::addRequired($form, $slot_id); + if (!($element['#wrap'] ?? TRUE)) { + $form = static::addTitleAndDescription($form); + } + return $form; } /** diff --git a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php index 1a49db7d92e10a45a78974a20b8150c66d6a7c6d..f86452e374f99b51f004bbb16d72826a4fa5964f 100644 --- a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php +++ b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php @@ -244,7 +244,7 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { '#tree' => TRUE, ]; if (!$derivable_context || !array_key_exists($derivable_context, $derivableContexts)) { - $form["source"] = $source_container; + $form[$derivable_context ?? ''] = $source_container; return $form; } $source = $this->getSetting($derivable_context) ?? []; @@ -254,7 +254,6 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { $derived_contexts = $derivable_context_plugin->getDerivedContexts(); $form[$derivable_context] = $source_container; if (count($derived_contexts) === 0) { - $form["source"] = $source_container; return $form; } /** @var array<string, mixed> $derivable_context_form */ @@ -271,15 +270,15 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { } $derivable_context_form["value"] = [ '#type' => $is_slot ? 'component_slot_form' : 'component_prop_form', - '#default_value' => $source, '#component_id' => $component_id, '#title' => '', - '#source_contexts' => $derived_context, '#cardinality_multiple' => FALSE, '#display_remove' => FALSE, "#wrap" => FALSE, '#' . ($is_slot ? 'slot_id' : 'prop_id') => $this->getPropId(), '#tree' => TRUE, + '#default_value' => $source, + '#source_contexts' => $derived_context, '#tag_filter' => $this->getSourcesTagFilter(), ]; return $form;