2
0
mirror of https://github.com/iconify/iconify.git synced 2024-10-24 01:22:04 +00:00
iconify/packages/svelte/src/render.ts

139 lines
3.2 KiB
TypeScript
Raw Normal View History

import type { IconifyIcon } from '@iconify/types';
import { defaults } from '@iconify/core/lib/customisations';
import {
flipFromString,
alignmentFromString,
} from '@iconify/core/lib/customisations/shorthand';
import { rotateFromString } from '@iconify/core/lib/customisations/rotate';
import { iconToSVG } from '@iconify/core/lib/builder';
import { replaceIDs } from '@iconify/core/lib/builder/ids';
import { merge } from '@iconify/core/lib/misc/merge';
2021-04-29 18:06:25 +00:00
import type { IconProps } from './props';
/**
* Default SVG attributes
*/
const svgDefaults = {
'xmlns': 'http://www.w3.org/2000/svg',
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
'aria-hidden': true,
'role': 'img',
};
2021-04-29 18:06:25 +00:00
/**
* Result
*/
export interface RenderResult {
2021-04-29 18:06:25 +00:00
attributes: Record<string, unknown>;
body: string;
}
/**
* Generate icon from properties
*/
export function render(
// Icon must be validated before calling this function
icon: Required<IconifyIcon>,
// Properties
props: IconProps
): RenderResult {
2021-04-29 18:06:25 +00:00
const customisations = merge(defaults, props as typeof defaults);
const componentProps = merge(svgDefaults) as Record<string, unknown>;
// Create style if missing
let style = typeof props.style === 'string' ? props.style : '';
// Get element properties
for (let key in props) {
2021-04-29 18:06:25 +00:00
const value = props[key as keyof typeof props] as unknown;
switch (key) {
// Properties to ignore
case 'icon':
case 'style':
case 'onLoad':
break;
// Flip as string: 'horizontal,vertical'
case 'flip':
2021-04-29 18:06:25 +00:00
if (typeof value === 'string') {
flipFromString(customisations, value);
}
break;
// Alignment as string
case 'align':
2021-04-29 18:06:25 +00:00
if (typeof value === 'string') {
alignmentFromString(customisations, value);
}
break;
2021-04-30 09:51:31 +00:00
// Color: copy to style, add extra ';' in case style is missing it
case 'color':
2021-04-30 09:51:31 +00:00
style =
style +
(style.length > 0 && style.trim().slice(-1) !== ';'
? ';'
: '') +
'color: ' +
value +
'; ';
break;
// Rotation as string
case 'rotate':
2021-04-29 18:06:25 +00:00
if (typeof value === 'string') {
customisations[key] = rotateFromString(value);
2021-04-29 18:06:25 +00:00
} else if (typeof value === 'number') {
2021-05-06 13:49:46 +00:00
customisations[key] = value;
}
break;
// Remove aria-hidden
case 'ariaHidden':
case 'aria-hidden':
if (value !== true && value !== 'true') {
delete componentProps['aria-hidden'];
}
break;
// Copy missing property if it does not exist in customisations
default:
2021-04-29 18:06:25 +00:00
if ((defaults as Record<string, unknown>)[key] === void 0) {
componentProps[key] = value;
}
}
}
// Generate icon
const item = iconToSVG(icon, customisations);
// Add icon stuff
for (let key in item.attributes) {
2021-04-29 18:06:25 +00:00
componentProps[key] =
item.attributes[key as keyof typeof item.attributes];
}
if (item.inline) {
2021-04-30 09:51:31 +00:00
// Style overrides it
style = 'vertical-align: -0.125em; ' + style;
}
// Style
if (style !== '') {
componentProps.style = style;
}
// Counter for ids based on "id" property to render icons consistently on server and client
let localCounter = 0;
const id = props.id;
// Generate HTML
return {
attributes: componentProps,
body: replaceIDs(
item.body,
id ? () => id + '-' + localCounter++ : 'iconify-svelte-'
),
};
}