Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 55
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
UiSkinsPanel
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 11
462
0.00% covered (danger)
0.00%
0 / 1
 create
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 label
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildForm
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
 validateForm
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 alterElement
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 onAttachToRoot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAttachToSlot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onActive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onDelete
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isApplicable
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 filterValues
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder\Plugin\display_builder\Island;
6
7use Drupal\Core\Form\FormStateInterface;
8use Drupal\Core\StringTranslation\TranslatableMarkup;
9use Drupal\display_builder\Attribute\Island;
10use Drupal\display_builder\IslandPluginBase;
11use Drupal\display_builder\IslandType;
12use Drupal\display_builder\IslandWithFormInterface;
13use Drupal\display_builder\IslandWithFormTrait;
14use Drupal\display_builder\RenderableAltererInterface;
15use Drupal\ui_skins\CssVariable\CssVariablePluginManagerInterface;
16use Drupal\ui_skins\UiSkinsUtility;
17use Symfony\Component\DependencyInjection\ContainerInterface;
18
19/**
20 * Skins island plugin implementation.
21 *
22 * @todo must move to UI Styles module.
23 */
24#[Island(
25  id: 'ui_skins',
26  label: new TranslatableMarkup('UI Skins'),
27  description: new TranslatableMarkup('CSS variables to override for the active element.'),
28  type: IslandType::Contextual,
29)]
30class UiSkinsPanel extends IslandPluginBase implements IslandWithFormInterface, RenderableAltererInterface {
31
32  use IslandWithFormTrait;
33
34  /**
35   * The UI Skins CSS variables manager.
36   */
37  protected CssVariablePluginManagerInterface $cssVariablePluginManager;
38
39  /**
40   * {@inheritdoc}
41   */
42  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
43    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
44    $instance->cssVariablePluginManager = $container->get('plugin.manager.ui_skins.css_variable');
45
46    return $instance;
47  }
48
49  /**
50   * {@inheritdoc}
51   */
52  public function label(): string {
53    return 'Tokens';
54  }
55
56  /**
57   * {@inheritdoc}
58   */
59  public function buildForm(array &$form, FormStateInterface $form_state): void {
60    $data = $form_state->getBuildInfo()['args'][0];
61    $instance = $data['instance'] ?? [];
62    $grouped_plugin_definitions = $this->cssVariablePluginManager->getGroupedDefinitions();
63
64    if (empty($grouped_plugin_definitions)) {
65      return;
66    }
67
68    foreach ($grouped_plugin_definitions as $group => $definitions) {
69      $variables = [];
70
71      foreach ($definitions as $definition_id => $definition) {
72        $default = $definition->getDefaultValues();
73
74        if (!isset($default[':root'])) {
75          continue;
76        }
77        $variables[$definition_id] = [
78          '#type' => $definition->getType(),
79          '#title' => $definition->getLabel(),
80          '#default_value' => $instance[$definition_id] ?? $default[':root'] ?? '',
81        ];
82      }
83
84      if (!empty($variables)) {
85        $variables['#type'] = 'details';
86        $variables['#title'] = $group;
87        $form[$group] = $variables;
88      }
89    }
90  }
91
92  /**
93   * {@inheritdoc}
94   */
95  public function validateForm(array &$form, FormStateInterface $form_state): void {
96    $variables = $form_state->getValues();
97    $variables = $this->filterValues($variables);
98    $variables = $form_state->setValues($variables);
99    // Those two lines are necessary to prevent the form from being rebuilt.
100    // if rebuilt, the form state values will have both the computed ones
101    // and the raw ones (wrapper key and values).
102    $form_state->setRebuild(FALSE);
103    $form_state->setExecuted();
104  }
105
106  /**
107   * {@inheritdoc}
108   */
109  public function alterElement(array $element, array $data = []): array {
110    $inline_css = [];
111
112    foreach ($data as $variable => $value) {
113      $variable = UiSkinsUtility::getCssVariableName($variable);
114      $inline_css[] = "{$variable}{$value};";
115    }
116    $element['#attributes']['style'] = \implode(' ', $inline_css);
117
118    return $element;
119  }
120
121  /**
122   * {@inheritdoc}
123   */
124  public function onAttachToRoot(string $builder_id, string $instance_id): array {
125    return $this->reloadWithInstanceData($builder_id, $instance_id);
126  }
127
128  /**
129   * {@inheritdoc}
130   */
131  public function onAttachToSlot(string $builder_id, string $instance_id, string $parent_id): array {
132    return $this->reloadWithInstanceData($builder_id, $instance_id);
133  }
134
135  /**
136   * {@inheritdoc}
137   */
138  public function onActive(string $builder_id, array $data): array {
139    return $this->reloadWithLocalData($builder_id, $data);
140  }
141
142  /**
143   * {@inheritdoc}
144   */
145  public function onDelete(string $builder_id, string $parent_id): array {
146    return $this->reloadWithLocalData($builder_id, []);
147  }
148
149  /**
150   * {@inheritdoc}
151   */
152  public function isApplicable(): bool {
153    return parent::isApplicable() && \Drupal::service('module_handler')
154      ->moduleExists('ui_skins');
155  }
156
157  /**
158   * Extract values to save in configuration.
159   *
160   * @param array $variables
161   *   The variables to filter.
162   *
163   * @return array
164   *   An array of filtered variables.
165   */
166  protected function filterValues(array $variables): array {
167    $cleaned_variables = [];
168
169    foreach ($variables as $variable => $value) {
170      /** @var \Drupal\ui_skins\Definition\CssVariableDefinition $plugin_definition */
171      $plugin_definition = $this->cssVariablePluginManager->getDefinition($variable, FALSE);
172
173      if (!$plugin_definition) {
174        continue;
175      }
176
177      // Remove values that do not differ from the default values of the plugin.
178      if ($plugin_definition->isDefaultScopeValue(':root', $value)) {
179        continue;
180      }
181
182      $cleaned_variables[$variable] = $value;
183    }
184
185    return $cleaned_variables;
186  }
187
188}