Icon Component

To create an icon component, you can use any image file format such as jpg, png, or svg. However, it is recommended to use svg because it can be easily scaled and styled with CSS or Tailwind CSS.

In this example, we will use the Google Icons package from Google Icons to create a SearchIcon component. To do this, copy the search SVG icon and paste it into the render method of the component class.

To get started, create a new file at src/app/Lib/PHPX/GoogleIcons/SearchIcon.php and add the following code snippet:

The icon component will accept the following attributes, along with any other attributes you wish to pass:

  • class: Custom CSS classes for additional styling.
  • children: Content to be rendered within the component.

Note: If the class attribute is not specified, it will default to an empty string. The children attribute is optional and can be used to pass additional content inside the icon component.

<?php

  namespace Lib\PHPX\GoogleIcons;
  
  use Lib\PHPX\IPHPX;
  use Lib\PHPX\Utils;
  
  class SearchIcon implements IPHPX
  {
      /**
       * @var array<string, mixed> The properties or attributes passed to the component.
       */
      private array $props;
  
      /**
       * @var mixed The children elements or content to be rendered within the component.
       */
      private mixed $children;
  
      /**
       * @var string The CSS class for custom styling.
       */
      private string $class;
  
      /**
       * @var string Stores the precomputed CSS classes for the component.
       */
      private string $computedClass;
  
      /**
       * Constructor to initialize the component with the given properties.
       * 
       * @param array<string, mixed> $props Optional properties to customize the component.
       */
      public function __construct(array $props = [])
      {
          $this->props = $props;
          $this->children = $props['children'] ?? '';
          $this->class = $props['class'] ?? '';
  
          // Precompute the static classes once during construction
          $this->computedClass = $this->getComputedClasses();
      }
  
      /**
       * Registers or initializes any necessary components or settings. (Placeholder method).
       */
      public static function init(): void
      {
          // Register the component or any necessary initialization
      }
  
      /**
       * Combines and returns the CSS classes for the component.
       * 
       * @return string The merged CSS class string.
       */
      private function getComputedClasses(): string
      {
          $baseClass = ''; // Define any base classes if necessary
          return Utils::mergeClasses($baseClass, $this->class);
      }
  
      /**
       * Generates and returns a string of HTML attributes from the provided props.
       * Excludes 'class' and 'children' props from being added as attributes.
       * 
       * @return string The generated HTML attributes.
       */
      private function getAttributes(): string
      {
          // Filter out 'class' and 'children' props
          $filteredProps = array_filter($this->props, function ($key) {
              return !in_array($key, ['class', 'children']);
          }, ARRAY_FILTER_USE_KEY);
  
          // Build attributes string by escaping keys and values
          $attributes = [];
          foreach ($filteredProps as $key => $value) {
              $escapedKey = htmlspecialchars($key, ENT_QUOTES, 'UTF-8');
              $escapedValue = htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
              $attributes[] = "$escapedKey='$escapedValue'";
          }
  
          return implode(' ', $attributes);
      }
  
      /**
       * Renders the component as an HTML string with the appropriate classes and attributes.
       * Also, allows for dynamic children rendering if a callable is passed.
       * 
       * @return string The final rendered HTML of the component.
       */
      public function render(): string
      {
          $attributes = $this->getAttributes();
          $class = $this->computedClass;
  
        return "<svg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 -960 960 960' width='24px' fill='currentColor' class='$class' $attributes>
            <path d='M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.  5T200-580q0 75 52.5 127.5T380-400Z'/>" . $this->children . "
          </svg>";
      }
  
      /**
       * Converts the object to its string representation by rendering it.
       *
       * @return string The rendered HTML output of the component.
       */
      public function __toString(): string
      {
          return $this->render();
      }
  }

Now, you can integrate the SearchIcon component into your Prisma PHP application by following the example below:

<?php

  use Lib\PHPX\GoogleIcons\SearchIcon;
  
  SearchIcon::init();
  
  ?>
  
  <div class="w-screen h-screen grid place-items-center">
      <div class="flex gap-2 flex-col">
          <SearchIcon class="size-10 text-blue-500" />
          <div class="relative">
              <label for="search">
                  <SearchIcon class="absolute left-2 top-1/2 transform -translate-y-1/2 text-gray-500" />
              </label>
              <input
                  id="search"
                  name="search"
                  class="p-1 pl-10 rounded-md border w-full"
                  type="text"
                  placeholder="Search" />
          </div>
          <button class="p-2 rounded-md bg-blue-500 flex justify-center gap-2 text-white">
              Search
              <SearchIcon />
          </button>
      </div>
  </div>

By following the steps above, you have successfully created a reusable SearchIcon component using Prisma PHPX. You can now use this component in your application to display the search icon wherever needed.

In the render method, we use the svg tag to render the icon. You can copy any SVG icon from Google Icons and create a new component following the same steps outlined above.