Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 163
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ViewportSwitcher
0.00% covered (danger)
0.00%
0 / 156
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 9
756
0.00% covered (danger)
0.00%
0 / 1
 create
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 defaultConfiguration
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildConfigurationForm
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 configurationSummary
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 build
0.00% covered (danger)
0.00%
0 / 81
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
56
 getDefinitions
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 getMaxWidthValueFromMediaQuery
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 getProvidersOptions
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getProviders
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 5
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\breakpoint\BreakpointManager;
8use Drupal\Core\Extension\ModuleExtensionList;
9use Drupal\Core\Extension\ThemeExtensionList;
10use Drupal\Core\Form\FormStateInterface;
11use Drupal\Core\StringTranslation\TranslatableMarkup;
12use Drupal\display_builder\Attribute\Island;
13use Drupal\display_builder\InstanceInterface;
14use Drupal\display_builder\Island\IslandConfigurationFormInterface;
15use Drupal\display_builder\Island\IslandConfigurationFormTrait;
16use Drupal\display_builder\Island\IslandPluginBase;
17use Drupal\display_builder\Island\IslandType;
18use Symfony\Component\DependencyInjection\ContainerInterface;
19
20/**
21 * Island plugin implementation.
22 */
23#[Island(
24  id: 'viewport',
25  label: new TranslatableMarkup('Responsive width'),
26  description: new TranslatableMarkup('Change main region width according to breakpoints for canvas and preview panels.'),
27  type: IslandType::Floating,
28  modules: ['breakpoint'],
29  attach_to: ['builder', 'preview'],
30)]
31class ViewportSwitcher extends IslandPluginBase implements IslandConfigurationFormInterface {
32
33  use IslandConfigurationFormTrait;
34
35  private const HIDE_PROVIDER = ['toolbar', 'stark'];
36
37  /**
38   * The module list extension service.
39   */
40  protected ThemeExtensionList $themeList;
41
42  /**
43   * The module list extension service.
44   */
45  protected ModuleExtensionList $moduleList;
46
47  /**
48   * The breakpoint manager.
49   */
50  protected BreakpointManager $breakpointManager;
51
52  /**
53   * {@inheritdoc}
54   */
55  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
56    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
57    $instance->themeList = $container->get('extension.list.theme');
58    $instance->moduleList = $container->get('extension.list.module');
59    $instance->breakpointManager = $container->get('breakpoint.manager');
60
61    return $instance;
62  }
63
64  /**
65   * {@inheritdoc}
66   */
67  public function defaultConfiguration(): array {
68    return [
69      'exclude' => [],
70      'format' => 'compact',
71    ];
72  }
73
74  /**
75   * {@inheritdoc}
76   */
77  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
78    $configuration = $this->getConfiguration();
79
80    $form['format'] = [
81      '#type' => 'select',
82      '#title' => $this->t('Selector format'),
83      '#description' => $this->t('Choose the appearance of the selector. Normal select or a compact dropdown menu.'),
84      '#options' => [
85        'default' => $this->t('Default'),
86        'compact' => $this->t('Compact'),
87      ],
88      '#default_value' => $configuration['format'],
89    ];
90
91    $form['exclude'] = [
92      '#type' => 'checkboxes',
93      '#title' => $this->t('Exclude providers'),
94      '#options' => $this->getProvidersOptions($this->t('breakpoint'), $this->t('breakpoints')),
95      '#default_value' => $configuration['exclude'],
96    ];
97
98    return $form;
99  }
100
101  /**
102   * {@inheritdoc}
103   */
104  public function configurationSummary(): array {
105    $configuration = $this->getConfiguration();
106    $summary = [];
107
108    $exclude = \array_filter($configuration['exclude'] ?? []);
109
110    $summary[] = $this->t('Excluded providers: @exclude', [
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
112    ]);
113
114    $summary[] = $this->t('Format: @format', [
115      '@format' => $configuration['format'] ?? 'default',
116    ]);
117
118    return $summary;
119  }
120
121  /**
122   * {@inheritdoc}
123   */
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
187      return $select;
188    }
189
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
230
231  /**
232   * Get the definitions list which is used by a few methods.
233   *
234   * @return array
235   *   Breakpoints plugin definitions as associative arrays.
236   */
237  public function getDefinitions(): array {
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
253
254  /**
255   * Get width and max width from media query.
256   *
257   * @param string $query
258   *   The media query from the breakpoint definition.
259   *
260   * @return ?string
261   *   The width with its unit (120px, 13em, 100vh...). Null is no width found.
262   */
263  protected function getMaxWidthValueFromMediaQuery(string $query): ?string {
264    if (\str_contains($query, 'not ')) {
265      // Queries with negated expression(s) are not supported.
266      return NULL;
267    }
268    // Look for max-width: 1250px or max-width: 1250 px.
269    \preg_match('/max-width:\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
270
271    if (\count($matches) > 2) {
272      return $matches[1] . $matches[2];
273    }
274    // Looking for width <= 1250px or <= 1250 px.
275    \preg_match('/width\s*<=\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
276
277    if (\count($matches) > 1) {
278      return $matches[1];
279    }
280
281    // @todo Currently only supports queries with max-width or width <= using
282    // px, em, vh units.
283    // Does not support min-width, percentage units, or complex/combined media
284    // queries.
285    return NULL;
286  }
287
288  /**
289   * Get providers options for select input.
290   *
291   * @param string|TranslatableMarkup $singular
292   *   Singular label of the plugins.
293   * @param string|TranslatableMarkup $plural
294   *   Plural label of the plugins.
295   *
296   * @return array
297   *   An associative array with extension ID as key and extension description
298   *   as value.
299   */
300  protected function getProvidersOptions(string|TranslatableMarkup $singular = 'definition', string|TranslatableMarkup $plural = 'definitions'): array {
301    $options = [];
302
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
304      $params = [
305        '@name' => $provider['name'],
306        '@type' => $provider['type'],
307        '@count' => $provider['count'],
308        '@singular' => $singular,
309        '@plural' => $plural,
310      ];
311      $options[$provider_id] = $this->formatPlural($provider['count'], '@name (@type, @count @singular)', '@name (@type, @count @plural)', $params);
312    }
313
314    return $options;
315  }
316
317  /**
318   * Get all providers.
319   *
320   * @param array $definitions
321   *   Plugin definitions.
322   *
323   * @return array
324   *   Drupal extension definitions, keyed by extension ID
325   */
326  protected function getProviders(array $definitions): array {
327    $themes = $this->themeList->getAllInstalledInfo();
328    $modules = $this->moduleList->getAllInstalledInfo();
329    $providers = [];
330
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
339      $providers[$provider_id] = $provider;
340    }
341
342    return $providers;
343  }
344
345}

Paths

Below are the source code lines that represent each code path as identified by Xdebug. Please note a path is not necessarily coterminous with a line, a line may contain multiple paths and therefore show up more than once. Please also be aware that some paths may include implicit rather than explicit branches, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

ViewportSwitcher->build
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
132        continue;
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
131      if (!isset($definition['group'])) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
156          continue;
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
 
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
187      return $select;
124  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
125    $configuration = $this->getConfiguration();
126    $definitions = $this->getDefinitions();
127
128    $groups = [];
129
130    foreach ($definitions as $definition) {
 
130    foreach ($definitions as $definition) {
131      if (!isset($definition['group'])) {
132        continue;
133      }
134      $groups[$definition['group']] = $definition['group'];
135    }
136
137    $options = $data = [];
138    $items = [
139      [
140        'title' => $this->t('Fluid (Current viewport)'),
141        'class' => 'active',
142      ],
143      [
144        'divider' => TRUE,
145      ],
146    ];
147
148    foreach ($groups as $group_id => $label) {
 
148    foreach ($groups as $group_id => $label) {
149      $points = $this->breakpointManager->getBreakpointsByGroup($group_id);
150
151      foreach ($points as $point_id => $point) {
152        $query = $point->getMediaQuery();
153        $width = $this->getMaxWidthValueFromMediaQuery($query);
154
155        if (!$width) {
156          continue;
157        }
158        $point_label = $point->getLabel();
159        $options[$label][$point_id] = $point_label;
160        $items[] = [
161          'title' => $point_label,
162          'value' => $point_id,
163        ];
164        $data[$point_id] = $width;
165      }
166    }
167
168    $select = [
169      '#type' => 'component',
170      '#component' => 'display_builder:select',
171      '#attached' => [
172        'library' => ['display_builder/viewport_switcher'],
173      ],
174      '#props' => [
175        'options' => $options,
176        'icon' => 'window',
177        'empty_option' => $this->t('Fluid (Current viewport)'),
178      ],
179      '#attributes' => [
180        'style' => 'display: inline-block;',
181        'data-points' => \json_encode($data),
182        'data-island-action' => 'viewport',
183      ],
184    ];
185
186    if ($configuration['format'] !== 'compact') {
 
190    unset($select['#attributes']['style']);
191    $select['#props']['icon'] = NULL;
192
193    // A plain title attribute, not the dropdown's own #props.tooltip (which
194    // wraps the trigger in a Shoelace <sl-tooltip>): Floating UI computes a
195    // permanently broken position for a tooltip that's part of the
196    // server-rendered HTML inside a floating controls cluster.
197    $button = $this->buildButton('', NULL, 'display');
198    $button['#attributes']['class'] = ['switch-viewport-btn'];
199    $button['#attributes']['size'] = 'small';
200    $button['#attributes']['title'] = $this->t('Switch viewport of this display');
201
202    return [
203      '#type' => 'component',
204      '#component' => 'display_builder:dropdown',
205      '#slots' => [
206        'button' => $button,
207        'content' => [
208          '#type' => 'component',
209          '#component' => 'display_builder:menu',
210          '#props' => [
211            'items' => $items,
212          ],
213          '#attributes' => [
214            'class' => ['viewport-menu', 'db-background'],
215            'data-points' => \json_encode($data),
216          ],
217        ],
218      ],
219      '#attributes' => [
220        // db-background: visual surface now that this floats over the
221        // pane's own content, instead of sitting in the toolbar's chrome.
222        'class' => ['switch-viewport', 'db-background'],
223        'data-island-action' => 'viewport',
224      ],
225      '#attached' => [
226        'library' => ['display_builder/viewport_switcher'],
227      ],
228    ];
229  }
ViewportSwitcher->buildConfigurationForm
77  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
78    $configuration = $this->getConfiguration();
79
80    $form['format'] = [
81      '#type' => 'select',
82      '#title' => $this->t('Selector format'),
83      '#description' => $this->t('Choose the appearance of the selector. Normal select or a compact dropdown menu.'),
84      '#options' => [
85        'default' => $this->t('Default'),
86        'compact' => $this->t('Compact'),
87      ],
88      '#default_value' => $configuration['format'],
89    ];
90
91    $form['exclude'] = [
92      '#type' => 'checkboxes',
93      '#title' => $this->t('Exclude providers'),
94      '#options' => $this->getProvidersOptions($this->t('breakpoint'), $this->t('breakpoints')),
95      '#default_value' => $configuration['exclude'],
96    ];
97
98    return $form;
99  }
ViewportSwitcher->configurationSummary
105    $configuration = $this->getConfiguration();
106    $summary = [];
107
108    $exclude = \array_filter($configuration['exclude'] ?? []);
109
110    $summary[] = $this->t('Excluded providers: @exclude', [
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
 
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
 
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
112    ]);
113
114    $summary[] = $this->t('Format: @format', [
115      '@format' => $configuration['format'] ?? 'default',
116    ]);
117
118    return $summary;
119  }
105    $configuration = $this->getConfiguration();
106    $summary = [];
107
108    $exclude = \array_filter($configuration['exclude'] ?? []);
109
110    $summary[] = $this->t('Excluded providers: @exclude', [
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
 
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
 
111      '@exclude' => ($exclude = \array_filter($configuration['exclude'] ?? [])) ? \implode(', ', $exclude) : $this->t('None'),
112    ]);
113
114    $summary[] = $this->t('Format: @format', [
115      '@format' => $configuration['format'] ?? 'default',
116    ]);
117
118    return $summary;
119  }
ViewportSwitcher->create
55  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
56    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
57    $instance->themeList = $container->get('extension.list.theme');
58    $instance->moduleList = $container->get('extension.list.module');
59    $instance->breakpointManager = $container->get('breakpoint.manager');
60
61    return $instance;
62  }
ViewportSwitcher->defaultConfiguration
69      'exclude' => [],
70      'format' => 'compact',
71    ];
72  }
ViewportSwitcher->getDefinitions
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
 
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
238    $definitions = $this->breakpointManager->getDefinitions();
239
240    foreach ($definitions as $definition_id => $definition) {
 
240    foreach ($definitions as $definition_id => $definition) {
241      if (isset($definition['provider']) && \in_array($definition['provider'], self::HIDE_PROVIDER, TRUE)) {
242        unset($definitions[$definition_id]);
243      }
244
245      // Exclude definitions with not supported media queries.
246      if (!$this->getMaxWidthValueFromMediaQuery($definition['mediaQuery'])) {
247        unset($definitions[$definition_id]);
248      }
249    }
250
251    return $definitions;
252  }
ViewportSwitcher->getMaxWidthValueFromMediaQuery
263  protected function getMaxWidthValueFromMediaQuery(string $query): ?string {
264    if (\str_contains($query, 'not ')) {
 
266      return NULL;
263  protected function getMaxWidthValueFromMediaQuery(string $query): ?string {
264    if (\str_contains($query, 'not ')) {
 
269    \preg_match('/max-width:\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
270
271    if (\count($matches) > 2) {
 
272      return $matches[1] . $matches[2];
263  protected function getMaxWidthValueFromMediaQuery(string $query): ?string {
264    if (\str_contains($query, 'not ')) {
 
269    \preg_match('/max-width:\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
270
271    if (\count($matches) > 2) {
 
275    \preg_match('/width\s*<=\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
276
277    if (\count($matches) > 1) {
 
278      return $matches[1];
263  protected function getMaxWidthValueFromMediaQuery(string $query): ?string {
264    if (\str_contains($query, 'not ')) {
 
269    \preg_match('/max-width:\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
270
271    if (\count($matches) > 2) {
 
275    \preg_match('/width\s*<=\s*([0-9]+)\s*([A-Za-z]+)/', $query, $matches);
276
277    if (\count($matches) > 1) {
 
285    return NULL;
286  }
ViewportSwitcher->getProviders
326  protected function getProviders(array $definitions): array {
327    $themes = $this->themeList->getAllInstalledInfo();
328    $modules = $this->moduleList->getAllInstalledInfo();
329    $providers = [];
330
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
 
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
 
336        continue;
 
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
339      $providers[$provider_id] = $provider;
340    }
341
342    return $providers;
343  }
326  protected function getProviders(array $definitions): array {
327    $themes = $this->themeList->getAllInstalledInfo();
328    $modules = $this->moduleList->getAllInstalledInfo();
329    $providers = [];
330
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
 
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
 
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
 
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
 
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
339      $providers[$provider_id] = $provider;
340    }
341
342    return $providers;
343  }
326  protected function getProviders(array $definitions): array {
327    $themes = $this->themeList->getAllInstalledInfo();
328    $modules = $this->moduleList->getAllInstalledInfo();
329    $providers = [];
330
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
 
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
 
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
 
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
 
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
339      $providers[$provider_id] = $provider;
340    }
341
342    return $providers;
343  }
326  protected function getProviders(array $definitions): array {
327    $themes = $this->themeList->getAllInstalledInfo();
328    $modules = $this->moduleList->getAllInstalledInfo();
329    $providers = [];
330
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
339      $providers[$provider_id] = $provider;
340    }
341
342    return $providers;
343  }
326  protected function getProviders(array $definitions): array {
327    $themes = $this->themeList->getAllInstalledInfo();
328    $modules = $this->moduleList->getAllInstalledInfo();
329    $providers = [];
330
331    foreach ($definitions as $definition) {
 
331    foreach ($definitions as $definition) {
332      $provider_id = $definition['provider'];
333      $provider = $themes[$provider_id] ?? $modules[$provider_id] ?? NULL;
334
335      if (!$provider) {
336        continue;
337      }
338      $provider['count'] = isset($providers[$provider_id]) ? ($providers[$provider_id]['count']) + 1 : 1;
339      $providers[$provider_id] = $provider;
340    }
341
342    return $providers;
343  }
ViewportSwitcher->getProvidersOptions
300  protected function getProvidersOptions(string|TranslatableMarkup $singular = 'definition', string|TranslatableMarkup $plural = 'definitions'): array {
301    $options = [];
302
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
304      $params = [
305        '@name' => $provider['name'],
306        '@type' => $provider['type'],
307        '@count' => $provider['count'],
308        '@singular' => $singular,
309        '@plural' => $plural,
310      ];
311      $options[$provider_id] = $this->formatPlural($provider['count'], '@name (@type, @count @singular)', '@name (@type, @count @plural)', $params);
312    }
313
314    return $options;
315  }
300  protected function getProvidersOptions(string|TranslatableMarkup $singular = 'definition', string|TranslatableMarkup $plural = 'definitions'): array {
301    $options = [];
302
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
304      $params = [
305        '@name' => $provider['name'],
306        '@type' => $provider['type'],
307        '@count' => $provider['count'],
308        '@singular' => $singular,
309        '@plural' => $plural,
310      ];
311      $options[$provider_id] = $this->formatPlural($provider['count'], '@name (@type, @count @singular)', '@name (@type, @count @plural)', $params);
312    }
313
314    return $options;
315  }
300  protected function getProvidersOptions(string|TranslatableMarkup $singular = 'definition', string|TranslatableMarkup $plural = 'definitions'): array {
301    $options = [];
302
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
 
303    foreach ($this->getProviders($this->getDefinitions()) as $provider_id => $provider) {
304      $params = [
305        '@name' => $provider['name'],
306        '@type' => $provider['type'],
307        '@count' => $provider['count'],
308        '@singular' => $singular,
309        '@plural' => $plural,
310      ];
311      $options[$provider_id] = $this->formatPlural($provider['count'], '@name (@type, @count @singular)', '@name (@type, @count @plural)', $params);
312    }
313
314    return $options;
315  }