Skip to content

Commit

Permalink
Button Group field type
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonkelly committed Feb 26, 2025
1 parent 6d718bf commit b4a3bbc
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
146 changes: 146 additions & 0 deletions src/fields/ButtonGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\fields;

use Craft;
use craft\base\ElementInterface;
use craft\base\SortableFieldInterface;
use craft\fields\data\SingleOptionFieldData;
use craft\helpers\Cp;
use craft\helpers\Html;

/**
* RadioButtons represents a Radio Buttons field.
*
* @author Pixel & Tonic, Inc. <support@pixelandtonic.com>
* @since 3.0.0
*/
class ButtonGroup extends BaseOptionsField implements SortableFieldInterface
{
/**
* @inheritdoc
*/
protected static bool $optionIcons = true;

/**
* @inheritdoc
*/
public static function displayName(): string
{
return Craft::t('app', 'Button Group');
}

/**
* @inheritdoc
*/
public static function icon(): string
{
return 'hand-pointer';
}

/**
* @inheritdoc
*/
public function useFieldset(): bool
{
return true;
}

/**
* @inheritdoc
*/
protected function inputHtml(mixed $value, ?ElementInterface $element, bool $inline): string
{
return $this->_inputHtml($value, $element, false);
}

/**
* @inheritdoc
*/
public function getStaticHtml(mixed $value, ElementInterface $element): string
{
return $this->_inputHtml($value, $element, true);
}

private function _inputHtml(SingleOptionFieldData $value, ?ElementInterface $element, bool $static): string
{
/** @var SingleOptionFieldData $value */
if (!$value->valid) {
Craft::$app->getView()->setInitialDeltaValue($this->handle, null);
}

$id = $this->getInputId();

$html = Html::beginTag('section', [
'id' => $id,
'class' => ['btngroup', 'btngroup--exclusive'],
'aria' => [
'labelledby' => $this->getLabelId(),
],
]);

$value = $this->encodeValue($value);

foreach ($this->translatedOptions(true, $value, $element) as $option) {
$selected = $option['value'] === $value;
$labelHtml = Html::encode($option['label']);
if (!empty($option['icon'])) {
$labelHtml = Html::beginTag('div', ['class' => ['flex', 'flex-inline']]) .
Html::tag('div', Cp::iconSvg($option['icon']), [
'class' => ['cp-icon', 'small'],
]) .
Html::tag('div', $labelHtml) .
Html::endTag('div');
}
$html .= Cp::buttonHtml([
'labelHtml' => $labelHtml,
'type' => 'button',
'class' => array_filter([
$selected ? 'active' : null,
]),
'disabled' => $static,
'attributes' => [
'aria' => [
'pressed' => $selected ? 'true' : false,
],
'data' => [
'value' => $option['value'],
],
],
]);
}

$html .= Html::endTag('section') . // .btngroup
Html::hiddenInput($this->handle, $value, [
'id' => "{$id}-input",
]);

$view = Craft::$app->getView();
$view->registerJsWithVars(fn($id) => <<<JS
(() => {
new Craft.Listbox($('#' + $id), {
onChange: (selectedOption) => {
$('#' + $id + '-input').val(selectedOption.data('value'));
},
});
})();
JS, [
$view->namespaceInputId($id),
]);

return $html;
}

/**
* @inheritdoc
*/
protected function optionsSettingLabel(): string
{
return Craft::t('app', 'Radio Button Options');
}
}
13 changes: 13 additions & 0 deletions src/helpers/Cp.php
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,19 @@ private static function _noticeHtml(string $id, string $class, string $label, ?s
Html::endTag('p');
}

/**
* Renders a button’s HTML.
*
* @param array $config
* @return string
* @throws InvalidArgumentException
* @since 5.7.0
*/
public static function buttonHtml(array $config): string
{
return static::renderTemplate('_includes/forms/button.twig', $config);
}

/**
* Renders a checkbox field’s HTML.
*
Expand Down
2 changes: 2 additions & 0 deletions src/services/Fields.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
use craft\fields\Addresses as AddressesField;
use craft\fields\Assets as AssetsField;
use craft\fields\BaseRelationField;
use craft\fields\ButtonGroup;
use craft\fields\Categories as CategoriesField;
use craft\fields\Checkboxes;
use craft\fields\Color;
Expand Down Expand Up @@ -222,6 +223,7 @@ public function getAllFieldTypes(): array
$fieldTypes = [
AddressesField::class,
AssetsField::class,
ButtonGroup::class,
CategoriesField::class,
Checkboxes::class,
Color::class,
Expand Down
1 change: 1 addition & 0 deletions src/translations/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
'Briefly describe your issue or idea.' => 'Briefly describe your issue or idea.',
'Briefly describe your question.' => 'Briefly describe your question.',
'Bug reports and feature requests' => 'Bug reports and feature requests',
'Button Group' => 'Button Group',
'Buy now' => 'Buy now',
'Buy {name}' => 'Buy {name}',
'Bytes' => 'Bytes',
Expand Down

0 comments on commit b4a3bbc

Please # to comment.