<?php /** * Generate an ellipsis menu. * * Only supports links for now, no buttons. * * Example usage: * * $menu = new EllipsisMenu(); * $menu->add_item( __( 'Item 1', 'p2020' ), 'https://wordpress.com' ); * $menu->add_item( __( 'Item 2', 'p2020' ), 'https://wordpress.com' ); * echo html_output( $menu->generate() ); * * @package p2020 */ namespace Automattic\P2\Themes\P2020; class EllipsisMenu { public const SEPARATOR = 'separator'; private $items = []; public $label; public $classes; public function add_item( string $label, string $url, string $icon = null, array $attributes = [] ) { $this->items[] = [ 'label' => $label, 'url' => $url, 'attributes' => $attributes, 'icon' => $icon, ]; } public function add_item_html( string $html ) { $this->items[] = [ 'html' => $html, ]; } public function add_separator() { $this->items[] = self::SEPARATOR; } public function add_item_skeleton( $id ) { $skeleton_item = <<<HTML <div id="{$id}"> <div class="p2020-ellipsis-menu__item-skeleton"> <div class="p2-skeleton-icon"></div> <div class="p2-skeleton-text"></div> </div> </div> HTML; $this->add_item_html( $skeleton_item ); } public function generate_item_html( $item ): string { if ( self::SEPARATOR === $item ) { return '<li class="p2020-ellipsis-menu-separator" role="separator"/>'; } if ( isset( $item['html'] ) ) { $link = $item['html']; return <<<ITEM <li role="menuitem"> $link </li> ITEM; } $label = esc_html( $item['label'] ); $url = esc_url( $item['url'] ); $attributes_html = ''; if ( $item['attributes'] ) { foreach ( $item['attributes'] as $key => $value ) { $attributes_html .= ' ' . esc_html( $key ) . '="' . esc_attr( $value ) . '"'; } } if ( ! $url ) { return <<<ITEM <li role="menuitem"> <span $attributes_html> $label </span> </li> ITEM; } return <<<ITEM <li role="menuitem"> <a href="$url" $attributes_html> $label </a> </li> ITEM; } private function make_list(): string { return implode( array_map( array( $this, 'generate_item_html' ), $this->items ) ); } public function header( $trigger_id ) { $menu_label = esc_attr__( 'More', 'p2020' ); if ( $this->label ) { $menu_label = $this->label; } $classes = $this->classes; return <<<HEADER <nav class="$classes"> <button id="$trigger_id" aria-haspopup="true" aria-expanded="false" aria-label="$menu_label" class="p2020-ellipsis-button" data-tippy-menu-trigger > </button> <div data-tippy-menu-content hidden> <ul class="p2020-ellipsis-menu" role="menu"> HEADER; } public function footer() { return <<<FOOTER </ul> </div> </nav> FOOTER; } /** * Returns the HTML for the menu. * * @param string $id trigger button id * * @return string */ public function generate( $trigger_id = 'p2020-ellipsis-button' ): string { $header = $this->header( $trigger_id ); $list = $this->make_list(); $footer = $this->footer(); // Outer div is required for proper tab order return $header . $list . $footer; } }