From a49a91d363a70f6c4af0c282f0b420f31926a05b Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 10:02:43 +0100
Subject: [PATCH 01/12] fix: Add style object

---
 src/Plugin/UiPatterns/Source/MediaSource.php  |  3 +-
 src/Template/Styles.php                       | 56 ++++++++++++++++++
 src/Template/TwigExtension.php                | 48 +++++++++++++++
 tests/fixtures/StyleDataSet.yml               | 58 +++++++++++++++++++
 .../test-style-component.component.yml        | 18 ++++++
 .../test-style-component.twig                 | 23 ++++++++
 .../ui_patterns_settings_test.info.yml        |  4 ++
 tests/src/Kernel/Source/MediaSourceTest.php   |  1 -
 .../src/Kernel/UiPSSourcePluginsTestBase.php  |  4 +-
 tests/src/Unit/Template/StylesTest.php        | 41 +++++++++++++
 ui_patterns_settings.api.php                  | 52 -----------------
 ui_patterns_settings.module                   |  1 -
 ui_patterns_settings.services.yml             |  6 +-
 13 files changed, 258 insertions(+), 57 deletions(-)
 create mode 100644 src/Template/Styles.php
 create mode 100644 src/Template/TwigExtension.php
 create mode 100644 tests/fixtures/StyleDataSet.yml
 create mode 100644 tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml
 create mode 100644 tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig
 create mode 100644 tests/modules/ui_patterns_settings_test/ui_patterns_settings_test.info.yml
 create mode 100644 tests/src/Unit/Template/StylesTest.php
 delete mode 100644 ui_patterns_settings.api.php

diff --git a/src/Plugin/UiPatterns/Source/MediaSource.php b/src/Plugin/UiPatterns/Source/MediaSource.php
index a6ac2dc..8bbe494 100644
--- a/src/Plugin/UiPatterns/Source/MediaSource.php
+++ b/src/Plugin/UiPatterns/Source/MediaSource.php
@@ -65,7 +65,7 @@ class MediaSource extends SourcePluginBase {
 
     $media = $this->getMedia();
     if ($media === NULL) {
-     return '';
+      return '';
     }
     $view_mode = $this->getSetting('view_mode') ?? 'default';
     if ($view_mode === NULL) {
@@ -110,6 +110,7 @@ class MediaSource extends SourcePluginBase {
 
     return $form;
   }
+
   /**
    * {@inheritdoc}
    */
diff --git a/src/Template/Styles.php b/src/Template/Styles.php
new file mode 100644
index 0000000..cf07cfa
--- /dev/null
+++ b/src/Template/Styles.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\ui_patterns_settings\Template;
+
+use Drupal\Core\Template\Attribute;
+
+/**
+ * Collects, sanitizes, and renders HTML attributes.
+ */
+class Styles {
+
+  /**
+   * Constructs a \Drupal\ui_patterns_settings\Template\Style object.
+   *
+   * @param array $styles
+   *   An array of styles configuration to be converted.
+   * @param array $styleSet
+   *   An associative array of key-value pairs of selected subset.
+   */
+  public function __construct(protected array $styles = [], protected array $styleSet = []) {
+  }
+
+  /**
+   * Converts style object to an array of attributes.
+   */
+  public function toAttributes(): array {
+    $classes_map = $this->toClasses();
+    $attributes_map = [];
+    foreach ($classes_map as $prop_id => $class) {
+      $attributes_map[$prop_id] = new Attribute(['class' => $class]);
+    }
+    return $attributes_map;
+  }
+
+  /**
+   * Converts style object to an array of classes.
+   */
+  public function toClasses(): array {
+    $style_set = $this->styleSet;
+    $classes_map = [];
+    if (is_array($this->styles['default'])) {
+      foreach ($this->styles['default'] as $default_key => $default_value) {
+        $classes_map[$default_key] = $default_value;
+      }
+    }
+    foreach ($style_set as $style_set_id => $value) {
+      if (isset($this->styles[$style_set_id][$value])) {
+        foreach ($this->styles[$style_set_id][$value] as $style_key => $style_value) {
+          $classes_map[$style_key] = $style_value;
+        }
+      }
+    }
+    return $classes_map;
+  }
+
+}
diff --git a/src/Template/TwigExtension.php b/src/Template/TwigExtension.php
new file mode 100644
index 0000000..a485775
--- /dev/null
+++ b/src/Template/TwigExtension.php
@@ -0,0 +1,48 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_patterns_settings\Template;
+
+use Twig\Extension\AbstractExtension;
+use Twig\TwigFunction;
+
+/**
+ * Twig extension providing UI Patterns-settings functionalities.
+ *
+ * @package Drupal\ui_patterns_settings\Template
+ */
+class TwigExtension extends AbstractExtension {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getName(): string {
+    return 'ui_patterns_settings';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFunctions() {
+    return [
+      new TwigFunction('create_style', [$this, 'createStyle']),
+    ];
+  }
+
+  /**
+   * Create style attribute.
+   *
+   * @param array $styles
+   *   The style config.
+   * @param array $style_set
+   *   The style set config.
+   *
+   * @return array
+   *   An associative array keyed by the style name.
+   */
+  public function createStyle(array $styles, array $style_set): array {
+    return (new Styles($styles, $style_set))->toAttributes();
+  }
+
+}
diff --git a/tests/fixtures/StyleDataSet.yml b/tests/fixtures/StyleDataSet.yml
new file mode 100644
index 0000000..8b1e1ca
--- /dev/null
+++ b/tests/fixtures/StyleDataSet.yml
@@ -0,0 +1,58 @@
+---
+style:
+  default:
+    background: ''
+    text: ''
+    border: ''
+  variant:
+    primary:
+      background: bg-blue
+      border: bg-none
+    outline:
+      background: bg-none
+      border: bg-gray
+  button_size:
+    small:
+      text: text-sm
+    medium:
+      text: text-lm
+expected:
+  -
+    input:
+      variant: primary
+      button_size: small
+    output:
+      text: text-sm
+      background: bg-blue
+      border: bg-none
+  -
+    input:
+      variant: primary
+      button_size: medium
+    output:
+      text: text-lm
+      background: bg-blue
+      border: bg-none
+  -
+    input:
+      variant: outline
+      button_size: small
+    output:
+      text: text-sm
+      background: bg-none
+      border: bg-gray
+  -
+    input:
+      variant: outline
+      button_size: medium
+    output:
+      text: text-lm
+      background: bg-none
+      border: bg-gray
+  -
+    input:
+      variant: outline
+    output:
+      text:
+      background: bg-none
+      border: bg-gray
diff --git a/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml
new file mode 100644
index 0000000..59c4a8c
--- /dev/null
+++ b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml
@@ -0,0 +1,18 @@
+name: "UI Patterns Settings Test style component"
+variants:
+  primary:
+    title: "Primary"
+  outline:
+    title: "Outline"
+props:
+  type: object
+  properties:
+    button_size:
+      title: "String"
+      type: "string"
+      enum:
+       - small
+       - medium
+slots:
+  title:
+    title: "Slot"
diff --git a/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig
new file mode 100644
index 0000000..e392fe1
--- /dev/null
+++ b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig
@@ -0,0 +1,23 @@
+{% set style = create_style(
+    {
+    'default': {
+        'border': '',
+        'background': ''
+    },
+    'variant': {
+        'primary': {
+              'background': 'bg-blue',
+              'border': 'border-none'
+        },
+          'outline': {
+              'background': 'bg-blue',
+              'border': 'border-none'
+        }
+    }
+    }
+, {'variant': variant|default('primary'), 'button_size': button_size|default('medium')}) %}
+{{ dump(style) }}
+<div{{ style.background.merge(style.border) }}>
+    BUTTON
+    {{ title }}
+</div>
\ No newline at end of file
diff --git a/tests/modules/ui_patterns_settings_test/ui_patterns_settings_test.info.yml b/tests/modules/ui_patterns_settings_test/ui_patterns_settings_test.info.yml
new file mode 100644
index 0000000..331a468
--- /dev/null
+++ b/tests/modules/ui_patterns_settings_test/ui_patterns_settings_test.info.yml
@@ -0,0 +1,4 @@
+name: "UI Patterns Settings Test"
+type: module
+description: "Provides test plugin."
+package: "Testing"
diff --git a/tests/src/Kernel/Source/MediaSourceTest.php b/tests/src/Kernel/Source/MediaSourceTest.php
index aecb567..215c52b 100644
--- a/tests/src/Kernel/Source/MediaSourceTest.php
+++ b/tests/src/Kernel/Source/MediaSourceTest.php
@@ -21,7 +21,6 @@ class MediaSourceTest extends UiPSSourcePluginsTestBase {
     'ui_patterns_settings',
   ];
 
-
   /**
    * Test TokenSource Plugin.
    */
diff --git a/tests/src/Kernel/UiPSSourcePluginsTestBase.php b/tests/src/Kernel/UiPSSourcePluginsTestBase.php
index 06e142f..960f014 100644
--- a/tests/src/Kernel/UiPSSourcePluginsTestBase.php
+++ b/tests/src/Kernel/UiPSSourcePluginsTestBase.php
@@ -22,9 +22,11 @@ class UiPSSourcePluginsTestBase extends SourcePluginsTestBase {
 
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function runSourcePluginTests(?string $test_starts_with = NULL, ?string $tests_path = NULL): void {
     parent::runSourcePluginTests($test_starts_with, __DIR__ . "/../../fixtures/TestDataSet.yml");
   }
 
-
 }
diff --git a/tests/src/Unit/Template/StylesTest.php b/tests/src/Unit/Template/StylesTest.php
new file mode 100644
index 0000000..17a7cd6
--- /dev/null
+++ b/tests/src/Unit/Template/StylesTest.php
@@ -0,0 +1,41 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\ui_patterns_settings\Unit\Template;
+
+use Drupal\Component\Serialization\Yaml;
+use Drupal\Tests\UnitTestCase;
+use Drupal\ui_patterns_settings\Template\Styles;
+
+/**
+ * @coversDefaultClass \Drupal\ui_patterns_settings\Template\Styles
+ *
+ * @group ui_patterns
+ */
+final class StylesTest extends UnitTestCase {
+
+  /**
+   * Test the method ::toClasses().
+   *
+   * @dataProvider provideStyleData
+   */
+  public function testStyle(array $style, array $input, array $expected): void {
+    $classes_map = (new Styles($style, $input))->toClasses();
+    $this->assertEquals($expected, $classes_map);
+  }
+
+  /**
+   * Provide data for provideStyleData.
+   */
+  public static function provideStyleData(): array {
+    $file_contents = file_get_contents(__DIR__ . "/../../../fixtures/StyleDataSet.yml");
+    $data = $file_contents ? Yaml::decode($file_contents) : [];
+    $result = [];
+    foreach ($data['expected'] as $expected) {
+      $result[] = [$data['style'], $expected['input'], $expected['output']];
+    }
+    return $result;
+  }
+
+}
diff --git a/ui_patterns_settings.api.php b/ui_patterns_settings.api.php
deleted file mode 100644
index 1e09880..0000000
--- a/ui_patterns_settings.api.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * @file
- * API file.
- */
-
-/**
- * Alter UI Patterns Settings settings before they are printed.
- *
- * Implement this hook to override the configured pattern settings for
- * specific patterns or to configure custom setting logic.
- *
- * @param array $settings
- *   Pattern settings.
- * @param array $context
- *   Context Properties: The context and the entity of the pattern.
- *   keys:
- *    - #pattern_id: The pattern id.
- *    - #variant: The variant id.
- *    - #context: The pattern context
- *
- * @see \Drupal\ui_patterns_settings\Element\PatternSettings
- */
-function hook_ui_pattern_settings_settings_alter(array &$settings, array $context) {
-  if ($context['#pattern_id'] === 'button') {
-    $settings['padding_bottom'] = 'large';
-  }
-}
-
-/**
- * Alter UI Patterns variant before they are passed to settings.
- *
- * Implement this hook to override the configured pattern variant for
- * specific patterns or to configure custom variant logic.
- *
- * @param $variant
- *   Pattern variant.
- * @param array $context
- *   Context Properties: The context and the entity of the pattern.
- *   keys:
- *    - #pattern_id: The pattern id.
- *    - #variant: The variant id.
- *    - #context: The pattern context
- *
- * @see \Drupal\ui_patterns_settings\Element\PatternSettings
- */
-function hook_ui_pattern_settings_variant_alter(&$variant, array $context) {
-  if ($context['#pattern_id'] === 'section') {
-    $variant = 'column_1';
-  }
-}
diff --git a/ui_patterns_settings.module b/ui_patterns_settings.module
index fba211c..68201a6 100644
--- a/ui_patterns_settings.module
+++ b/ui_patterns_settings.module
@@ -4,4 +4,3 @@
  * @file
  * Contains ui_patterns_settings.module.
  */
-
diff --git a/ui_patterns_settings.services.yml b/ui_patterns_settings.services.yml
index ad189dd..bfbd035 100644
--- a/ui_patterns_settings.services.yml
+++ b/ui_patterns_settings.services.yml
@@ -1 +1,5 @@
-services: {}
+services:
+  ui_patterns_settings.twig.extension:
+    class: Drupal\ui_patterns_settings\Template\TwigExtension
+    tags:
+      - { name: twig.extension }
-- 
GitLab


From e0c3e5de892847ca14d428d004bdc4677f40e11e Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 10:23:44 +0100
Subject: [PATCH 02/12] Rename to attributes set

---
 src/Template/{Styles.php => AttributesSet.php} | 18 +++++++++---------
 src/Template/TwigExtension.php                 |  6 +++---
 .../test-style-component.twig                  |  6 +++---
 .../{StylesTest.php => AttributesSetTest.php}  | 12 ++++++------
 4 files changed, 21 insertions(+), 21 deletions(-)
 rename src/Template/{Styles.php => AttributesSet.php} (65%)
 rename tests/src/Unit/Template/{StylesTest.php => AttributesSetTest.php} (66%)

diff --git a/src/Template/Styles.php b/src/Template/AttributesSet.php
similarity index 65%
rename from src/Template/Styles.php
rename to src/Template/AttributesSet.php
index cf07cfa..39c7eb2 100644
--- a/src/Template/Styles.php
+++ b/src/Template/AttributesSet.php
@@ -7,17 +7,17 @@ use Drupal\Core\Template\Attribute;
 /**
  * Collects, sanitizes, and renders HTML attributes.
  */
-class Styles {
+class AttributesSet {
 
   /**
    * Constructs a \Drupal\ui_patterns_settings\Template\Style object.
    *
-   * @param array $styles
+   * @param array $attributesSetConfig
    *   An array of styles configuration to be converted.
-   * @param array $styleSet
+   * @param array $attributesSet
    *   An associative array of key-value pairs of selected subset.
    */
-  public function __construct(protected array $styles = [], protected array $styleSet = []) {
+  public function __construct(protected array $attributesSetConfig = [], protected array $attributesSet = []) {
   }
 
   /**
@@ -36,16 +36,16 @@ class Styles {
    * Converts style object to an array of classes.
    */
   public function toClasses(): array {
-    $style_set = $this->styleSet;
+    $style_set = $this->attributesSet;
     $classes_map = [];
-    if (is_array($this->styles['default'])) {
-      foreach ($this->styles['default'] as $default_key => $default_value) {
+    if (is_array($this->attributesSetConfig['default'])) {
+      foreach ($this->attributesSetConfig['default'] as $default_key => $default_value) {
         $classes_map[$default_key] = $default_value;
       }
     }
     foreach ($style_set as $style_set_id => $value) {
-      if (isset($this->styles[$style_set_id][$value])) {
-        foreach ($this->styles[$style_set_id][$value] as $style_key => $style_value) {
+      if (isset($this->attributesSetConfig[$style_set_id][$value])) {
+        foreach ($this->attributesSetConfig[$style_set_id][$value] as $style_key => $style_value) {
           $classes_map[$style_key] = $style_value;
         }
       }
diff --git a/src/Template/TwigExtension.php b/src/Template/TwigExtension.php
index a485775..1c7d50e 100644
--- a/src/Template/TwigExtension.php
+++ b/src/Template/TwigExtension.php
@@ -26,7 +26,7 @@ class TwigExtension extends AbstractExtension {
    */
   public function getFunctions() {
     return [
-      new TwigFunction('create_style', [$this, 'createStyle']),
+      new TwigFunction('create_attributes_set', [$this, 'createAttributesSet']),
     ];
   }
 
@@ -41,8 +41,8 @@ class TwigExtension extends AbstractExtension {
    * @return array
    *   An associative array keyed by the style name.
    */
-  public function createStyle(array $styles, array $style_set): array {
-    return (new Styles($styles, $style_set))->toAttributes();
+  public function createAttributesSet(array $styles, array $style_set): array {
+    return (new AttributesSet($styles, $style_set))->toAttributes();
   }
 
 }
diff --git a/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig
index e392fe1..8c67dcd 100644
--- a/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig
+++ b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.twig
@@ -1,4 +1,4 @@
-{% set style = create_style(
+{% set attributes_set = create_attributes_set(
     {
     'default': {
         'border': '',
@@ -16,8 +16,8 @@
     }
     }
 , {'variant': variant|default('primary'), 'button_size': button_size|default('medium')}) %}
-{{ dump(style) }}
-<div{{ style.background.merge(style.border) }}>
+
+<div{{ attributes_set.background.merge(attributes_set.border) }}>
     BUTTON
     {{ title }}
 </div>
\ No newline at end of file
diff --git a/tests/src/Unit/Template/StylesTest.php b/tests/src/Unit/Template/AttributesSetTest.php
similarity index 66%
rename from tests/src/Unit/Template/StylesTest.php
rename to tests/src/Unit/Template/AttributesSetTest.php
index 17a7cd6..2461928 100644
--- a/tests/src/Unit/Template/StylesTest.php
+++ b/tests/src/Unit/Template/AttributesSetTest.php
@@ -6,22 +6,22 @@ namespace Drupal\Tests\ui_patterns_settings\Unit\Template;
 
 use Drupal\Component\Serialization\Yaml;
 use Drupal\Tests\UnitTestCase;
-use Drupal\ui_patterns_settings\Template\Styles;
+use Drupal\ui_patterns_settings\Template\AttributesSet;
 
 /**
- * @coversDefaultClass \Drupal\ui_patterns_settings\Template\Styles
+ * @coversDefaultClass \Drupal\ui_patterns_settings\Template\AttributesSet
  *
- * @group ui_patterns
+ * @group ui_patterns_settings
  */
-final class StylesTest extends UnitTestCase {
+final class AttributesSetTest extends UnitTestCase {
 
   /**
    * Test the method ::toClasses().
    *
    * @dataProvider provideStyleData
    */
-  public function testStyle(array $style, array $input, array $expected): void {
-    $classes_map = (new Styles($style, $input))->toClasses();
+  public function testAttributesSet(array $style, array $input, array $expected): void {
+    $classes_map = (new AttributesSet($style, $input))->toClasses();
     $this->assertEquals($expected, $classes_map);
   }
 
-- 
GitLab


From ad43c9bddd3b9d680290be71fe3f84b466c2c434 Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 10:34:49 +0100
Subject: [PATCH 03/12] fix: Add ui patterns constraint

---
 ui_patterns_settings.info.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ui_patterns_settings.info.yml b/ui_patterns_settings.info.yml
index b0ea5a3..407dd4b 100644
--- a/ui_patterns_settings.info.yml
+++ b/ui_patterns_settings.info.yml
@@ -4,5 +4,5 @@ description: Configure patterns with settings
 package: User interface
 core_version_requirement: ^10.3 || ^11
 dependencies:
-  - ui_patterns:ui_patterns
+  - ui_patterns:ui_patterns (>=2.0)
   - token:token
-- 
GitLab


From 995885c09d5fd38bd8b92971009a875339214290 Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:16:50 +0100
Subject: [PATCH 04/12] fix media tests

---
 README.md                                     | 101 ------------------
 composer.json                                 |  22 ++++
 phpstan.neon                                  |   6 --
 src/Plugin/UiPatterns/Source/MediaSource.php  |   5 +-
 ...leDataSet.yml => AttributesSetDataSet.yml} |   0
 tests/fixtures/TestDataSet.yml                |   5 +-
 tests/src/Kernel/Source/MediaSourceTest.php   |  22 ++++
 tests/src/Unit/Template/AttributesSetTest.php |   2 +-
 8 files changed, 49 insertions(+), 114 deletions(-)
 create mode 100644 composer.json
 rename tests/fixtures/{StyleDataSet.yml => AttributesSetDataSet.yml} (100%)

diff --git a/README.md b/README.md
index 6f9dac4..e497e21 100644
--- a/README.md
+++ b/README.md
@@ -1,102 +1 @@
 # UI Patterns Settings
-
-INTRODUCTION
-------------
-Make UI Patterns configurable through settings.
-
-Sample pattern:
-```
-card:
-  label: Card
-  description: A card component.
-  variants:
-    product:
-      label: Artwork
-      settings:
-        modifier: artwork
-        attributes: "class=\"shadow-bottom\""
-  settings:
-    modifier:
-      type: textfield
-      label: Modifier
-      description: Add modifier here
-    url:
-      type: token
-      label: Url
-      default_value: "[node:url]"
-    attributes:
-      type: attributes
-      label: Attributes
-  fields:
-    image:
-      type: image
-      label: Image
-      description: Card image.
-      preview:
-        type: pattern
-        id: image
-        fields:
-          image:
-            theme: image
-            uri: http://lorempixel.com/400/200/nature/2
-    title:
-      type: text
-      label: Title
-      description: Card title.
-      preview: Card title
-    text:
-      type: text
-      label: Text
-      description: Card text.
-      preview: Cras justo odio, dapibus ac facilisis in.
-```
-Sample card pattern template:
-```
-
-<a href="{{ url }}" class="card card--{{ modifier }} {{ attributes.class }}" 
-{{ attributes|without('class') }}>
-  <div class="thumbnail">
-    {{ image }}
-    <div class="caption">
-      <h3>{{ title }}</h3>
-      <p>{{ text }}</p>
-    </div>
-  </div>
-</a>
-```
-
-**Sample Images:**
-Settings in manage display:
-![pattern settings](images/settings.png)
-
-Each settings type is a plugin. 
-You can easily create your own setting types. 
-**hook_preprocess is not needed any more**
-
-**Currently available setting types are:**
-- textfield
-- select
-- boolean
-- checkbox (multi value)
-- attributes
-- token
-- url (Generates urls from uri or user input. 
-  Tokens are accepted. Useful for linkfield uris?)
-
-REQUIREMENTS
-------------
-
-* ui patterns >= 1.1.
-
-INSTALLATION
-------------
-
-* Install the UI Patterns Setting module as you would 
-normally install a contributed
-  Drupal module. Visit https://www.drupal.org/node/1897420. 
-  
-CONFIGURATION
-------------
-
-Navigate to Manage Display of your entity type select an pattern and 
-you will find your configured settings.
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..ecd8c6b
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,22 @@
+{
+    "name": "drupal/ui_patterns_settings",
+    "type": "drupal-module",
+    "description": "Extend UI Patterns with settings.",
+    "keywords": [
+        "drupal",
+        "web",
+        "ui"
+    ],
+    "license": "GPL-2.0+",
+    "minimum-stability": "dev",
+    "prefer-stable": true,
+    "authors": [
+        {
+            "name": "Christian Wiedemann",
+            "email": "christian.wiedemann@key-tec.de"
+        }
+    ],
+    "require": {
+      "drupal/ui_patterns": "^2.0"
+    }
+}
diff --git a/phpstan.neon b/phpstan.neon
index 263a761..e3fc903 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -48,12 +48,6 @@ parameters:
     - '#should return string but returns Drupal\\Core\\StringTranslation\\TranslatableMarkup\.#'
     - '#Parameter \#1 \$field of method Drupal\\Core\\Entity\\Query\\QueryInterface::condition\(\) expects Drupal\\Core\\Condition\\ConditionInterface\|string, Drupal\\Core\\Entity\\Query\\ConditionInterface given\.#'
     -
-      identifier: missingType.iterableValue
-    - '#Method Drupal\\ui_patterns_views\\Plugin\\views\\row\\ComponentRow::buildOptionsForm\(\) has parameter \$form with no type specified.#'
-    - '#Method Drupal\\ui_patterns_views\\Plugin\\views\\row\\ComponentRow::submitOptionsForm\(\) has parameter \$form with no type specified.#'
-    - '#Method Drupal\\ui_patterns_views\\Plugin\\views\\style\\ComponentStyle::buildOptionsForm\(\) has parameter \$form with no type specified.#'
-    - '#Method Drupal\\ui_patterns\\Element\\UiPatternsOperations::preRenderDropbutton\(\) has parameter \$element with no type specified.#'
-    - '#Method Drupal\\ui_patterns_views\\Plugin\\views\\row\\ComponentRow::render\(\) should return string but returns array.#'
 #    - '#Plugin definitions cannot be altered.#'
     - '#Method Drupal\\Tests\\ui_patterns[a-zA-Z0-9:\\_]+\(\) has parameter \$[a-zA-Z0-9\\_]+ with no type specified.#'
     - '#Method Drupal\\Tests\\ui_patterns[a-zA-Z0-9:\\_]+\(\) has no return type specified.#'
diff --git a/src/Plugin/UiPatterns/Source/MediaSource.php b/src/Plugin/UiPatterns/Source/MediaSource.php
index 8bbe494..fefa736 100644
--- a/src/Plugin/UiPatterns/Source/MediaSource.php
+++ b/src/Plugin/UiPatterns/Source/MediaSource.php
@@ -68,9 +68,6 @@ class MediaSource extends SourcePluginBase {
       return '';
     }
     $view_mode = $this->getSetting('view_mode') ?? 'default';
-    if ($view_mode === NULL) {
-      return $media->id();
-    }
     $view_mode_builder = $this->entityTypeManager->getViewBuilder('media');
     return $view_mode_builder->view($media, $view_mode);
 
@@ -90,7 +87,7 @@ class MediaSource extends SourcePluginBase {
   public function configureForm(array $form, FormStateInterface $form_state): array {
     $configuration = $this->getConfiguration();
     $form = parent::configureForm($form, $form_state);
-    /** @var \Drupal\media\Entity\MediaType $bundles */
+    /** @var \Drupal\media\Entity\MediaType[] $bundles */
     $bundles = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
     $bundle_options = [];
     foreach ($bundles as $bundle_id => $bundle) {
diff --git a/tests/fixtures/StyleDataSet.yml b/tests/fixtures/AttributesSetDataSet.yml
similarity index 100%
rename from tests/fixtures/StyleDataSet.yml
rename to tests/fixtures/AttributesSetDataSet.yml
diff --git a/tests/fixtures/TestDataSet.yml b/tests/fixtures/TestDataSet.yml
index 5911789..502179d 100644
--- a/tests/fixtures/TestDataSet.yml
+++ b/tests/fixtures/TestDataSet.yml
@@ -8,13 +8,14 @@ media_main:
           -
             source_id: media
             source:
-              media_id: 112
+              media:
+                media_library_selection: '12'
 
   output:
     slots:
       slot:
         -
-          normalized_value: '12'
+          normalized_value: ''
 
 
   entity: {}
diff --git a/tests/src/Kernel/Source/MediaSourceTest.php b/tests/src/Kernel/Source/MediaSourceTest.php
index 215c52b..ed40d62 100644
--- a/tests/src/Kernel/Source/MediaSourceTest.php
+++ b/tests/src/Kernel/Source/MediaSourceTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace Drupal\Tests\ui_patterns_settings\Kernel\Source;
 
+use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
 use Drupal\Tests\ui_patterns_settings\Kernel\UiPSSourcePluginsTestBase;
 
 /**
@@ -13,12 +14,33 @@ use Drupal\Tests\ui_patterns_settings\Kernel\UiPSSourcePluginsTestBase;
  * @group ui_patterns_settings
  */
 class MediaSourceTest extends UiPSSourcePluginsTestBase {
+  protected $strictConfigSchema = FALSE;
+  use MediaTypeCreationTrait;
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->installEntitySchema('file');
+    $this->installEntitySchema('media');
+    $this->createMediaType('image');
+    $this->installConfig(['file', 'image', 'media']);
+
+    $media_type_storage = $this->container->get('entity_type.manager')->getStorage('media_type');
+  }
 
   /**
    * {@inheritdoc}
    */
   protected static $modules = [
     'ui_patterns_settings',
+    'image',
+    'file',
+    'media',
+    'media_test_source',
+    'options',
+    'link'
   ];
 
   /**
diff --git a/tests/src/Unit/Template/AttributesSetTest.php b/tests/src/Unit/Template/AttributesSetTest.php
index 2461928..6baa07b 100644
--- a/tests/src/Unit/Template/AttributesSetTest.php
+++ b/tests/src/Unit/Template/AttributesSetTest.php
@@ -29,7 +29,7 @@ final class AttributesSetTest extends UnitTestCase {
    * Provide data for provideStyleData.
    */
   public static function provideStyleData(): array {
-    $file_contents = file_get_contents(__DIR__ . "/../../../fixtures/StyleDataSet.yml");
+    $file_contents = file_get_contents(__DIR__ . "/../../../fixtures/AttributesSetDataSet.yml");
     $data = $file_contents ? Yaml::decode($file_contents) : [];
     $result = [];
     foreach ($data['expected'] as $expected) {
-- 
GitLab


From 1cdd17fee1d1a76ec4be9028e46da883e05798b7 Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:25:01 +0100
Subject: [PATCH 05/12] fix media tests

---
 phpstan.neon                                |  3 +--
 tests/src/Kernel/Source/MediaSourceTest.php | 12 +++++++-----
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/phpstan.neon b/phpstan.neon
index e3fc903..0b4a2c2 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -47,8 +47,7 @@ parameters:
     - '#should return array\<string\> but returns array\<int, Drupal\\Core\\StringTranslation\\TranslatableMarkup\>\.#'
     - '#should return string but returns Drupal\\Core\\StringTranslation\\TranslatableMarkup\.#'
     - '#Parameter \#1 \$field of method Drupal\\Core\\Entity\\Query\\QueryInterface::condition\(\) expects Drupal\\Core\\Condition\\ConditionInterface\|string, Drupal\\Core\\Entity\\Query\\ConditionInterface given\.#'
-    -
-#    - '#Plugin definitions cannot be altered.#'
+#   - '#Plugin definitions cannot be altered.#'
     - '#Method Drupal\\Tests\\ui_patterns[a-zA-Z0-9:\\_]+\(\) has parameter \$[a-zA-Z0-9\\_]+ with no type specified.#'
     - '#Method Drupal\\Tests\\ui_patterns[a-zA-Z0-9:\\_]+\(\) has no return type specified.#'
   treatPhpDocTypesAsCertain: false
diff --git a/tests/src/Kernel/Source/MediaSourceTest.php b/tests/src/Kernel/Source/MediaSourceTest.php
index ed40d62..c2af7c2 100644
--- a/tests/src/Kernel/Source/MediaSourceTest.php
+++ b/tests/src/Kernel/Source/MediaSourceTest.php
@@ -14,20 +14,22 @@ use Drupal\Tests\ui_patterns_settings\Kernel\UiPSSourcePluginsTestBase;
  * @group ui_patterns_settings
  */
 class MediaSourceTest extends UiPSSourcePluginsTestBase {
-  protected $strictConfigSchema = FALSE;
   use MediaTypeCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $strictConfigSchema = FALSE;
+
   /**
    * {@inheritdoc}
    */
   protected function setUp(): void {
     parent::setUp();
-
     $this->installEntitySchema('file');
     $this->installEntitySchema('media');
     $this->createMediaType('image');
     $this->installConfig(['file', 'image', 'media']);
-
-    $media_type_storage = $this->container->get('entity_type.manager')->getStorage('media_type');
   }
 
   /**
@@ -40,7 +42,7 @@ class MediaSourceTest extends UiPSSourcePluginsTestBase {
     'media',
     'media_test_source',
     'options',
-    'link'
+    'link',
   ];
 
   /**
-- 
GitLab


From 41cabdaf5c84010bf02c727af2bbe4f28d317ebe Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:29:43 +0100
Subject: [PATCH 06/12] fix media tests

---
 src/Plugin/UiPatterns/Source/MediaSource.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Plugin/UiPatterns/Source/MediaSource.php b/src/Plugin/UiPatterns/Source/MediaSource.php
index fefa736..9128895 100644
--- a/src/Plugin/UiPatterns/Source/MediaSource.php
+++ b/src/Plugin/UiPatterns/Source/MediaSource.php
@@ -86,7 +86,7 @@ class MediaSource extends SourcePluginBase {
    */
   public function configureForm(array $form, FormStateInterface $form_state): array {
     $configuration = $this->getConfiguration();
-    $form = parent::configureForm($form, $form_state);
+    $form = parent::configureForm($form, $form_state); // @phpstan-ignore-line
     /** @var \Drupal\media\Entity\MediaType[] $bundles */
     $bundles = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
     $bundle_options = [];
-- 
GitLab


From a3991fa584cc7e2227bc3ef9e8eb5cf596768379 Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:30:52 +0100
Subject: [PATCH 07/12] fix media tests

---
 tests/fixtures/AttributesSetDataSet.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/fixtures/AttributesSetDataSet.yml b/tests/fixtures/AttributesSetDataSet.yml
index 8b1e1ca..72240ab 100644
--- a/tests/fixtures/AttributesSetDataSet.yml
+++ b/tests/fixtures/AttributesSetDataSet.yml
@@ -53,6 +53,6 @@ expected:
     input:
       variant: outline
     output:
-      text:
+      text: ''
       background: bg-none
       border: bg-gray
-- 
GitLab


From a8039018afd4eabe422d7b762bda82c6b2ffd5f8 Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:36:59 +0100
Subject: [PATCH 08/12] fix media tests

---
 src/Plugin/UiPatterns/Source/MediaSource.php                  | 3 ++-
 .../test-style-component/test-style-component.component.yml   | 4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/Plugin/UiPatterns/Source/MediaSource.php b/src/Plugin/UiPatterns/Source/MediaSource.php
index 9128895..b6f307e 100644
--- a/src/Plugin/UiPatterns/Source/MediaSource.php
+++ b/src/Plugin/UiPatterns/Source/MediaSource.php
@@ -86,7 +86,8 @@ class MediaSource extends SourcePluginBase {
    */
   public function configureForm(array $form, FormStateInterface $form_state): array {
     $configuration = $this->getConfiguration();
-    $form = parent::configureForm($form, $form_state); // @phpstan-ignore-line
+    // @phpstan-ignore-line
+    $form = parent::configureForm($form, $form_state);
     /** @var \Drupal\media\Entity\MediaType[] $bundles */
     $bundles = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
     $bundle_options = [];
diff --git a/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml
index 59c4a8c..0a7521f 100644
--- a/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml
+++ b/tests/modules/ui_patterns_settings_test/components/test-style-component/test-style-component.component.yml
@@ -11,8 +11,8 @@ props:
       title: "String"
       type: "string"
       enum:
-       - small
-       - medium
+        - small
+        - medium
 slots:
   title:
     title: "Slot"
-- 
GitLab


From 5636be2c20373949dcf3eb20bc46ed5ab9757dea Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:46:34 +0100
Subject: [PATCH 09/12] fix media tests

---
 src/Plugin/UiPatterns/Source/MediaSource.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/Plugin/UiPatterns/Source/MediaSource.php b/src/Plugin/UiPatterns/Source/MediaSource.php
index b6f307e..90b79ac 100644
--- a/src/Plugin/UiPatterns/Source/MediaSource.php
+++ b/src/Plugin/UiPatterns/Source/MediaSource.php
@@ -86,8 +86,9 @@ class MediaSource extends SourcePluginBase {
    */
   public function configureForm(array $form, FormStateInterface $form_state): array {
     $configuration = $this->getConfiguration();
-    // @phpstan-ignore-line
+
     $form = parent::configureForm($form, $form_state);
+    // @phpstan-ignore-line
     /** @var \Drupal\media\Entity\MediaType[] $bundles */
     $bundles = $this->entityTypeManager->getStorage('media_type')->loadMultiple();
     $bundle_options = [];
-- 
GitLab


From 714254b0688318e3a293df892fc435d676eaba2f Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 11:53:03 +0100
Subject: [PATCH 10/12] fix media tests

---
 phpstan.neon | 1 +
 1 file changed, 1 insertion(+)

diff --git a/phpstan.neon b/phpstan.neon
index 0b4a2c2..bde5d36 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -2,6 +2,7 @@ parameters:
   excludePaths:
     - */bower_components/*
     - */node_modules/*
+    - src/Plugin/UiPatterns/Source/MediaSource.php
   # Ignore some type hint errors due to hooks that should not have typed hint
   # parameters or return.
   ignoreErrors:
-- 
GitLab


From 562a359305a232a7b86876aae8ca32d7638d1826 Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 15:28:18 +0100
Subject: [PATCH 11/12] simplify attributset

---
 src/Template/AttributesSet.php          |  9 +++++++--
 tests/fixtures/AttributesSetDataSet.yml | 12 ++++++++++++
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/Template/AttributesSet.php b/src/Template/AttributesSet.php
index 39c7eb2..0cb4a7f 100644
--- a/src/Template/AttributesSet.php
+++ b/src/Template/AttributesSet.php
@@ -45,9 +45,14 @@ class AttributesSet {
     }
     foreach ($style_set as $style_set_id => $value) {
       if (isset($this->attributesSetConfig[$style_set_id][$value])) {
-        foreach ($this->attributesSetConfig[$style_set_id][$value] as $style_key => $style_value) {
-          $classes_map[$style_key] = $style_value;
+        if (is_array($this->attributesSetConfig[$style_set_id][$value])) {
+          foreach ($this->attributesSetConfig[$style_set_id][$value] as $style_key => $style_value) {
+            $classes_map[$style_key] = $style_value;
+          }
+        } else {
+          $classes_map[$style_set_id] = $this->attributesSetConfig[$style_set_id][$value];
         }
+
       }
     }
     return $classes_map;
diff --git a/tests/fixtures/AttributesSetDataSet.yml b/tests/fixtures/AttributesSetDataSet.yml
index 72240ab..3d9a816 100644
--- a/tests/fixtures/AttributesSetDataSet.yml
+++ b/tests/fixtures/AttributesSetDataSet.yml
@@ -4,6 +4,7 @@ style:
     background: ''
     text: ''
     border: ''
+    border_size: ''
   variant:
     primary:
       background: bg-blue
@@ -16,23 +17,30 @@ style:
       text: text-sm
     medium:
       text: text-lm
+  border_size:
+    small: border-sm
+    medium: border-md
 expected:
   -
     input:
       variant: primary
       button_size: small
+      border_size: small
     output:
       text: text-sm
       background: bg-blue
       border: bg-none
+      border_size: border-sm
   -
     input:
       variant: primary
       button_size: medium
+      border_size: small
     output:
       text: text-lm
       background: bg-blue
       border: bg-none
+      border_size: border-sm
   -
     input:
       variant: outline
@@ -41,14 +49,17 @@ expected:
       text: text-sm
       background: bg-none
       border: bg-gray
+      border_size: ''
   -
     input:
       variant: outline
+      border_size: medium
       button_size: medium
     output:
       text: text-lm
       background: bg-none
       border: bg-gray
+      border_size: border-md
   -
     input:
       variant: outline
@@ -56,3 +67,4 @@ expected:
       text: ''
       background: bg-none
       border: bg-gray
+      border_size: ''
-- 
GitLab


From a1712fdabf072b836cd0107d2b33d5e4dc3ded4a Mon Sep 17 00:00:00 2001
From: Christian Wiedemann <christian.wiedemann@key-tec.de>
Date: Wed, 5 Feb 2025 15:34:31 +0100
Subject: [PATCH 12/12] merge

---
 src/Template/AttributesSet.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/Template/AttributesSet.php b/src/Template/AttributesSet.php
index 0cb4a7f..8a05235 100644
--- a/src/Template/AttributesSet.php
+++ b/src/Template/AttributesSet.php
@@ -49,7 +49,8 @@ class AttributesSet {
           foreach ($this->attributesSetConfig[$style_set_id][$value] as $style_key => $style_value) {
             $classes_map[$style_key] = $style_value;
           }
-        } else {
+        }
+        else {
           $classes_map[$style_set_id] = $this->attributesSetConfig[$style_set_id][$value];
         }
 
-- 
GitLab