claro.theme

Same filename and directory in other branches
  1. 10 core/themes/claro/claro.theme
  2. 11.x core/themes/claro/claro.theme
  3. 9 core/themes/claro/claro.theme
  4. 8.9.x core/themes/claro/claro.theme

Functions to support theming in the Claro theme.

File

core/themes/claro/claro.theme

View source
<?php


/**
 * @file
 * Functions to support theming in the Claro theme.
 */

use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\file\FileInterface;

/**
 * Converts a link render element to an action link.
 *
 * This helper merges every attributes from $link['#attributes'], from
 * $link['#options']['attributes'] and from the Url object's.
 *
 * @param array $link
 *   Link renderable array.
 * @param string|null $icon_name
 *   The name of the needed icon. When specified, a CSS class will be added with
 *   the following pattern: 'action-link--icon-[icon_name]'. If the needed icon
 *   is not implemented in CSS, no icon will be added.
 *   Currently available icons are:
 *    - checkmark,
 *    - cog,
 *    - ex,
 *    - plus,
 *    - trash.
 * @param string $size
 *   Name of the small action link variant. Defaults to 'default'.
 *   Supported sizes are:
 *    - default,
 *    - small,
 *    - extrasmall.
 * @param string $variant
 *   Variant of the action link. Supported variants are 'default' and 'danger'.
 *   Defaults to 'default'.
 *
 * @return array
 *   The link renderable converted to action link.
 */
function _claro_convert_link_to_action_link(array $link, $icon_name = NULL, $size = 'default', $variant = 'default') : array {
  // Early opt-out if we cannot do anything.
  if (empty($link['#type']) || $link['#type'] !== 'link' || empty($link['#url'])) {
    return $link;
  }
  // \Drupal\Core\Render\Element\Link::preRenderLink adds $link['#attributes']
  // to $link[#options]['attributes'] if it is not empty, but it does not merges
  // the 'class' subkey deeply.
  // Because of this, when $link[#options]['attributes']['class'] is set, the
  // classes defined in $link['#attributes']['class'] are ignored.
  //
  // To keep this behavior we repeat this for action-link, which means that this
  // conversion happens a bit earlier. We unset $link['#attributes'] to prevent
  // Link::preRenderLink() doing the same, because for action-links, that would
  // be needless.
  $link += [
    '#options' => [],
  ];
  if (isset($link['#attributes'])) {
    $link['#options'] += [
      'attributes' => [],
    ];
    $link['#options']['attributes'] += $link['#attributes'];
    unset($link['#attributes']);
  }
  $link['#options'] += [
    'attributes' => [],
  ];
  $link['#options']['attributes'] += [
    'class' => [],
  ];
  // Determine the needed (type) variant.
  $variants_supported = [
    'default',
    'danger',
  ];
  $variant = is_string($variant) && in_array($variant, $variants_supported) ? $variant : reset($variants_supported);
  // Remove button, button modifier CSS classes and other unwanted ones.
  $link['#options']['attributes']['class'] = array_diff($link['#options']['attributes']['class'], [
    'button',
    'button--action',
    'button--primary',
    'button--danger',
    'button--small',
    'button--extrasmall',
    'link',
  ]);
  // Adding the needed CSS classes.
  $link['#options']['attributes']['class'][] = 'action-link';
  // Add the variant-modifier CSS class only if the variant is not the default.
  if ($variant !== reset($variants_supported)) {
    $link['#options']['attributes']['class'][] = Html::getClass("action-link--{$variant}");
  }
  // Add the icon modifier CSS class.
  if (!empty($icon_name)) {
    $link['#options']['attributes']['class'][] = Html::getClass("action-link--icon-{$icon_name}");
  }
  if ($size && in_array($size, [
    'small',
    'extrasmall',
  ])) {
    $link['#options']['attributes']['class'][] = Html::getClass("action-link--{$size}");
  }
  // If the provided $link is an item of the 'links' theme function, then only
  // the attributes of the Url object are processed during rendering.
  $url_attributes = $link['#url']->getOption('attributes') ?: [];
  $url_attributes = NestedArray::mergeDeep($url_attributes, $link['#options']['attributes']);
  $link['#url']->setOption('attributes', $url_attributes);
  return $link;
}

/**
 * Helper pre-process callback for file_managed_file and image_widget.
 *
 * @param array $variables
 *   The renderable array of image and file widgets, with 'element' and 'data'
 *   keys.
 */
function _claro_preprocess_file_and_image_widget(array &$variables) : void {
  $element = $variables['element'];
  $main_item_keys = [
    'upload',
    'upload_button',
    'remove_button',
  ];
  // Calculate helper values for the template.
  $upload_is_accessible = !isset($element['upload']['#access']) || $element['upload']['#access'] !== FALSE;
  $is_multiple = !empty($element['#cardinality']) && $element['#cardinality'] !== 1;
  $has_value = isset($element['#value']['fids']) && !empty($element['#value']['fids']);
  // File widget properties.
  $display_can_be_displayed = !empty($element['#display_field']);
  // Display is rendered in a separate table cell for multiple value widgets.
  $display_is_visible = $display_can_be_displayed && !$is_multiple && isset($element['display']['#type']) && $element['display']['#type'] !== 'hidden';
  $description_can_be_displayed = !empty($element['#description_field']);
  $description_is_visible = $description_can_be_displayed && isset($element['description']);
  // Image widget properties.
  $alt_can_be_displayed = !empty($element['#alt_field']);
  $alt_is_visible = $alt_can_be_displayed && (!isset($element['alt']['#access']) || $element['alt']['#access'] !== FALSE);
  $title_can_be_displayed = !empty($element['#title_field']);
  $title_is_visible = $title_can_be_displayed && (!isset($element['title']['#access']) || $element['title']['#access'] !== FALSE);
  $variables['multiple'] = $is_multiple;
  $variables['upload'] = $upload_is_accessible;
  $variables['has_value'] = $has_value;
  $variables['has_meta'] = $alt_is_visible || $title_is_visible || $display_is_visible || $description_is_visible;
  $variables['display'] = $display_is_visible;
  // Handle the default checkbox display after the file is uploaded.
  if (array_key_exists('display', $element)) {
    $variables['data']['display']['#checked'] = $element['display']['#value'];
  }
  // Render file upload input and upload button (or file name and remove button,
  // if the field is not empty) in an emphasized div.
  foreach ($variables['data'] as $key => $item) {
    $item_is_filename = isset($item['filename']['#file']) && $item['filename']['#file'] instanceof FileInterface;
    // Move filename to main items.
    if ($item_is_filename) {
      $variables['main_items']['filename'] = $item;
      unset($variables['data'][$key]);
      continue;
    }
    // Move buttons, upload input and hidden items to main items.
    if (in_array($key, $main_item_keys)) {
      $variables['main_items'][$key] = $item;
      unset($variables['data'][$key]);
    }
  }
}

/**
 * Called by system.module via its hook_library_info_alter().
 *
 * If the active theme is not Claro, but Claro is the admin theme, this alters
 * the toolbar library config so Claro's toolbar stylesheets are used.
 *
 * @see system_library_info_alter()
 */
function claro_system_module_invoked_library_info_alter(&$libraries, $extension) : void {
  if ($extension === 'toolbar') {
    $claro_info = \Drupal::service('theme_handler')->listInfo()['claro']->info;
    $path_prefix = '/core/themes/claro/';
    $claro_toolbar_overrides = $claro_info['libraries-override']['toolbar/toolbar'];
    foreach ($claro_toolbar_overrides['css'] as $concern => $overrides) {
      foreach ($claro_toolbar_overrides['css'][$concern] as $key => $value) {
        $config = $libraries['toolbar']['css'][$concern][$key];
        $libraries['toolbar']['css'][$concern][$path_prefix . $value] = $config;
        unset($libraries['toolbar']['css'][$concern][$key]);
      }
    }
    $claro_toolbar_menu_overrides = $claro_info['libraries-override']['toolbar/toolbar.menu'];
    foreach ($claro_toolbar_menu_overrides['css'] as $concern => $overrides) {
      foreach ($claro_toolbar_menu_overrides['css'][$concern] as $key => $value) {
        $config = $libraries['toolbar.menu']['css'][$concern][$key];
        $libraries['toolbar.menu']['css'][$concern][$path_prefix . $value] = $config;
        unset($libraries['toolbar.menu']['css'][$concern][$key]);
      }
    }
  }
}

/**
 * Called by system.module via its hook_theme_registry_alter().
 *
 * If the active theme is not Claro, but Claro is the admin theme, this alters
 * the registry so Claro's toolbar templates are used.
 *
 * @see system_theme_registry_alter()
 */
function claro_system_module_invoked_theme_registry_alter(array &$theme_registry) : void {
  foreach ([
    'toolbar',
    'menu__toolbar',
  ] as $registry_item) {
    if (isset($theme_registry[$registry_item])) {
      $theme_registry[$registry_item]['path'] = 'core/themes/claro/templates/navigation';
    }
  }
}

Functions

Title Deprecated Summary
claro_system_module_invoked_library_info_alter Called by system.module via its hook_library_info_alter().
claro_system_module_invoked_theme_registry_alter Called by system.module via its hook_theme_registry_alter().
_claro_convert_link_to_action_link Converts a link render element to an action link.
_claro_preprocess_file_and_image_widget Helper pre-process callback for file_managed_file and image_widget.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.