Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.

Commit 9d14631

Browse files
author
Nate Wiebe
authored
Merge pull request #43 from Pixelrobin/accessible-icons
Accessible icons
2 parents fc3f19a + c5a03c2 commit 9d14631

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

src/Icon.php

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,48 @@ class Icon
1010

1111
private $content;
1212

13-
public function __construct(string $name, array $attributes, string $content)
13+
private $altText;
14+
15+
public function __construct(string $name, string $content, array $attributes = [], ?string $altText = null)
1416
{
1517
$this->name = $name;
16-
$this->attributes = $attributes;
1718
$this->content = $content;
19+
$this->attributes = $attributes;
20+
$this->altText = $altText;
1821
}
1922

2023
public function getName(): string
2124
{
2225
return $this->name;
2326
}
2427

28+
public function setAltText(?string $altText): self
29+
{
30+
$this->altText = $altText;
31+
32+
return $this;
33+
}
34+
35+
public function getAltText(): ?string
36+
{
37+
return $this->altText;
38+
}
39+
2540
public function render(): string
2641
{
42+
$altText = '';
2743
$attributes = $this->filterAttributes($this->attributes);
2844

45+
if (!empty($this->altText)) {
46+
$uniqId = \uniqid(\sprintf('feather-%s-title-', $this->getName()));
47+
48+
$attributes['role'] = $attributes['role'] ?? 'img';
49+
$attributes['aria-labelledby'] = $uniqId;
50+
$altText = \sprintf('<title id="%s">%s</title>', $this->escapeString($uniqId), $this->escapeString((string)$this->getAltText()));
51+
} else {
52+
$attributes['aria-hidden'] = true;
53+
}
54+
2955
$svgAttributes = \array_reduce(
3056
\array_keys($attributes),
3157
function ($final, $current) use ($attributes): string {
@@ -35,14 +61,14 @@ function ($final, $current) use ($attributes): string {
3561
$attributeValue = $attributeValue ? 'true' : 'false';
3662
}
3763

38-
$attributeValue = \htmlspecialchars((string)$attributeValue, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', false);
64+
$attributeValue = $this->escapeString((string)$attributeValue);
3965

4066
return \sprintf('%s %s="%s"', $final, $current, $attributeValue);
4167
},
4268
''
4369
);
4470

45-
return '<svg ' . $svgAttributes . '>' . $this->content . '</svg>';
71+
return '<svg ' . $svgAttributes . '>' . $altText . $this->content . '</svg>';
4672
}
4773

4874
private function filterAttributes(array $attributes): array
@@ -63,6 +89,11 @@ function ($item): bool {
6389
);
6490
}
6591

92+
private function escapeString(string $string): string
93+
{
94+
return \htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8', false);
95+
}
96+
6697
public function __toString(): string
6798
{
6899
return $this->render();

src/IconManager.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ public function getIconNames(): array
2121
return \array_keys($this->icons);
2222
}
2323

24-
public function getIcon(string $name, array $attributes = []): Icon
24+
public function getIcon(string $name, array $attributes = [], ?string $altText = null): Icon
2525
{
2626
if (!isset($this->icons[$name])) {
2727
throw new IconNotFoundException(\sprintf('Icon `%s` not found', $name));
2828
}
2929

30-
return new Icon($name, \array_merge($this->attributes, $attributes), $this->icons[$name]);
30+
return new Icon($name, $this->icons[$name], \array_merge($this->attributes, $attributes), $altText);
3131
}
3232
}

tests/XMLTestData.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)