*/ protected static array $contents = []; /** * One symbol, from the cut drawn for the optical size it will be seen at. * * The package ships Google's 24 and 20 cuts; the 20 one lives in a `-20` folder under the * same names, so a symbol that exists exists in both. Any optical size but 20 draws the * standard 24 cut, which is also what a caller who says nothing gets. */ public static function symbol(string $name, bool $filled, ComponentAttributeBag $attributes, int $optical = 24): HtmlString { if (preg_match('/^[a-z0-9_]+$/', $name) !== 1) { throw new InvalidArgumentException("[{$name}] is not a Material Symbol name. Symbols are named in lowercase with underscores, as on fonts.google.com/icons: `calendar_month`, `arrow_back`."); } $folder = ($filled ? 'filled' : 'outlined').($optical === 20 ? '-20' : ''); $path = static::directory('svg/symbols/'.$folder)."/{$name}.svg"; if (! is_file($path)) { throw new InvalidArgumentException("There is no Material Symbol named [{$name}]."); } return static::render($path, $attributes); } public static function shape(string $name, ComponentAttributeBag $attributes): HtmlString { $path = static::directory('svg/shapes')."/{$name}.svg"; if (preg_match('/^[a-z0-9-]+$/', $name) !== 1 || ! is_file($path)) { throw new InvalidArgumentException("There is no M3 Expressive shape named [{$name}]."); } return static::render($path, $attributes); } /** * M3 Expressive's loading indicator: the morphing, rotating shape, or the shape at rest. */ public static function loadingIndicator(bool $animated, ComponentAttributeBag $attributes): HtmlString { return static::render(static::directory('svg/loading-indicator/'.($animated ? 'indeterminate' : 'static').'.svg'), $attributes); } /** * The names of every Material Symbol the package ships, in either cut: Google draws the * same catalogue at optical size 24 and at 20, so one folder answers for all four. * * @return list */ public static function symbolNames(): array { return array_map( fn (string $file): string => basename($file, '.svg'), glob(static::directory('svg/symbols/outlined').'/*.svg') ?: [], ); } /** * The names of every shape the package ships. * * @return list */ public static function shapeNames(): array { return array_map( fn (string $file): string => basename($file, '.svg'), glob(static::directory('svg/shapes').'/*.svg') ?: [], ); } protected static function render(string $path, ComponentAttributeBag $attributes): HtmlString { $svg = static::$contents[$path] ??= trim((string) file_get_contents($path)); return new HtmlString(preg_replace('/^toHtml(), $svg, 1)); } protected static function directory(string $path): string { return dirname(__DIR__, 2).'/resources/'.$path; } }