mirror of
https://github.com/iconify/iconify.git
synced 2024-11-09 23:00:56 +00:00
Move few more functions from Core to Utils
This commit is contained in:
parent
ebeb8de02c
commit
85a3717618
@ -9,7 +9,7 @@ import {
|
||||
} from '@iconify/react/lib/icon';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
|
@ -7,7 +7,7 @@ import type {
|
||||
IconifyHorizontalIconAlignment,
|
||||
IconifyVerticalIconAlignment,
|
||||
IconifyIconSize,
|
||||
} from '@iconify/core/lib/customisations';
|
||||
} from '@iconify/utils/lib/customisations';
|
||||
import { defaults } from '@iconify/utils/lib/customisations';
|
||||
import {
|
||||
flipFromString,
|
||||
@ -15,7 +15,7 @@ import {
|
||||
} from '@iconify/utils/lib/customisations/shorthand';
|
||||
import { rotateFromString } from '@iconify/utils/lib/customisations/rotate';
|
||||
import { fullIcon } from '@iconify/utils/lib/icon';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
||||
import { parseIconSet } from '@iconify/core/lib/icon/icon-set';
|
||||
|
||||
|
@ -4,7 +4,7 @@ import type {
|
||||
} from '../interfaces/loader';
|
||||
import { getStorage } from '../storage/storage';
|
||||
import type { SortedIcons } from '../icon/sort';
|
||||
import type { IconifyIconSource } from '../icon/name';
|
||||
import type { IconifyIconSource } from '@iconify/utils/lib/icon/name';
|
||||
|
||||
/**
|
||||
* Storage for callbacks
|
||||
@ -25,13 +25,10 @@ interface CallbackItem {
|
||||
|
||||
// Records sorted by provider and prefix
|
||||
// This export is only for unit testing, should not be used
|
||||
export const callbacks: Record<
|
||||
string,
|
||||
Record<string, CallbackItem[]>
|
||||
> = Object.create(null);
|
||||
const pendingUpdates: Record<string, Record<string, boolean>> = Object.create(
|
||||
null
|
||||
);
|
||||
export const callbacks: Record<string, Record<string, CallbackItem[]>> =
|
||||
Object.create(null);
|
||||
const pendingUpdates: Record<string, Record<string, boolean>> =
|
||||
Object.create(null);
|
||||
|
||||
/**
|
||||
* Remove callback
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { IconifyAPIInternalStorage } from '.';
|
||||
import { API, getRedundancyCache } from '.';
|
||||
import type { IconifyIconName } from '../icon/name';
|
||||
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import type {
|
||||
IconifyIconLoaderAbort,
|
||||
IconifyIconLoaderCallback,
|
||||
|
@ -15,7 +15,10 @@ import type { IconifyAPIConfig } from './config';
|
||||
import { getAPIConfig } from './config';
|
||||
import { getStorage, addIconSet } from '../storage/storage';
|
||||
import { coreModules } from '../modules';
|
||||
import type { IconifyIconName, IconifyIconSource } from '../icon/name';
|
||||
import type {
|
||||
IconifyIconName,
|
||||
IconifyIconSource,
|
||||
} from '@iconify/utils/lib/icon/name';
|
||||
import { listToIcons } from '../icon/list';
|
||||
import { allowSimpleNames } from '../storage/functions';
|
||||
|
||||
@ -35,10 +38,8 @@ function emptyCallback(): void {
|
||||
* [provider][prefix][icon] = time when icon was added to queue
|
||||
*/
|
||||
type PendingIcons = Record<string, number>;
|
||||
const pendingIcons: Record<
|
||||
string,
|
||||
Record<string, PendingIcons>
|
||||
> = Object.create(null);
|
||||
const pendingIcons: Record<string, Record<string, PendingIcons>> =
|
||||
Object.create(null);
|
||||
|
||||
/**
|
||||
* List of icons that are waiting to be loaded.
|
||||
@ -50,14 +51,12 @@ const pendingIcons: Record<
|
||||
*
|
||||
* [provider][prefix] = array of icon names
|
||||
*/
|
||||
const iconsToLoad: Record<string, Record<string, string[]>> = Object.create(
|
||||
null
|
||||
);
|
||||
const iconsToLoad: Record<string, Record<string, string[]>> =
|
||||
Object.create(null);
|
||||
|
||||
// Flags to merge multiple synchronous icon requests in one asynchronous request
|
||||
const loaderFlags: Record<string, Record<string, boolean>> = Object.create(
|
||||
null
|
||||
);
|
||||
const loaderFlags: Record<string, Record<string, boolean>> =
|
||||
Object.create(null);
|
||||
const queueFlags: Record<string, Record<string, boolean>> = Object.create(null);
|
||||
|
||||
// Redundancy instances cache, sorted by provider
|
||||
@ -65,10 +64,8 @@ export interface IconifyAPIInternalStorage {
|
||||
config: IconifyAPIConfig;
|
||||
redundancy: Redundancy;
|
||||
}
|
||||
const redundancyCache: Record<
|
||||
string,
|
||||
IconifyAPIInternalStorage
|
||||
> = Object.create(null);
|
||||
const redundancyCache: Record<string, IconifyAPIInternalStorage> =
|
||||
Object.create(null);
|
||||
|
||||
/**
|
||||
* Get Redundancy instance for provider
|
||||
@ -296,9 +293,8 @@ const loadIcons: IconifyLoadIcons = (
|
||||
}
|
||||
|
||||
// Get all sources for pending icons
|
||||
const newIcons: Record<string, Record<string, string[]>> = Object.create(
|
||||
null
|
||||
);
|
||||
const newIcons: Record<string, Record<string, string[]>> =
|
||||
Object.create(null);
|
||||
const sources: IconifyIconSource[] = [];
|
||||
let lastProvider: string, lastPrefix: string;
|
||||
|
||||
|
@ -7,8 +7,8 @@ import {
|
||||
mergeCustomisations,
|
||||
} from '@iconify/utils/lib/customisations';
|
||||
import type { IconifyIconCustomisations } from '@iconify/utils/lib/customisations';
|
||||
import { iconToSVG } from '.';
|
||||
import type { IconifyIconBuildResult } from '.';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
|
||||
/**
|
||||
* Interface for exported builder functions
|
||||
|
@ -1,237 +0,0 @@
|
||||
import type { FullIconifyIcon } from '@iconify/utils/lib/icon';
|
||||
import type { FullIconCustomisations } from '@iconify/utils/lib/customisations';
|
||||
import { calculateSize } from '@iconify/utils/lib/svg/size';
|
||||
|
||||
/**
|
||||
* Get preserveAspectRatio value
|
||||
*/
|
||||
function preserveAspectRatio(props: FullIconCustomisations): string {
|
||||
let result = '';
|
||||
switch (props.hAlign) {
|
||||
case 'left':
|
||||
result += 'xMin';
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
result += 'xMax';
|
||||
break;
|
||||
|
||||
default:
|
||||
result += 'xMid';
|
||||
}
|
||||
switch (props.vAlign) {
|
||||
case 'top':
|
||||
result += 'YMin';
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
result += 'YMax';
|
||||
break;
|
||||
|
||||
default:
|
||||
result += 'YMid';
|
||||
}
|
||||
result += props.slice ? ' slice' : ' meet';
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for getSVGData() result
|
||||
*/
|
||||
export interface IconifyIconBuildResult {
|
||||
attributes: {
|
||||
// Attributes for <svg>
|
||||
width: string;
|
||||
height: string;
|
||||
preserveAspectRatio: string;
|
||||
viewBox: string;
|
||||
};
|
||||
// Content
|
||||
body: string;
|
||||
// True if 'vertical-align: -0.125em' or equivalent should be added by implementation
|
||||
inline?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for viewBox
|
||||
*/
|
||||
interface ViewBox {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SVG attributes and content from icon + customisations
|
||||
*
|
||||
* Does not generate style to make it compatible with frameworks that use objects for style, such as React.
|
||||
* Instead, it generates 'inline' value. If true, rendering engine should add verticalAlign: -0.125em to icon.
|
||||
*
|
||||
* Customisations should be normalised by platform specific parser.
|
||||
* Result should be converted to <svg> by platform specific parser.
|
||||
* Use replaceIDs to generate unique IDs for body.
|
||||
*/
|
||||
export function iconToSVG(
|
||||
icon: FullIconifyIcon,
|
||||
customisations: FullIconCustomisations
|
||||
): IconifyIconBuildResult {
|
||||
// viewBox
|
||||
const box: ViewBox = {
|
||||
left: icon.left,
|
||||
top: icon.top,
|
||||
width: icon.width,
|
||||
height: icon.height,
|
||||
};
|
||||
|
||||
// Body
|
||||
let body = icon.body;
|
||||
|
||||
// Apply transformations
|
||||
[icon, customisations].forEach((props) => {
|
||||
const transformations: string[] = [];
|
||||
const hFlip = props.hFlip;
|
||||
const vFlip = props.vFlip;
|
||||
let rotation = props.rotate;
|
||||
|
||||
// Icon is flipped first, then rotated
|
||||
if (hFlip) {
|
||||
if (vFlip) {
|
||||
rotation += 2;
|
||||
} else {
|
||||
// Horizontal flip
|
||||
transformations.push(
|
||||
'translate(' +
|
||||
(box.width + box.left) +
|
||||
' ' +
|
||||
(0 - box.top) +
|
||||
')'
|
||||
);
|
||||
transformations.push('scale(-1 1)');
|
||||
box.top = box.left = 0;
|
||||
}
|
||||
} else if (vFlip) {
|
||||
// Vertical flip
|
||||
transformations.push(
|
||||
'translate(' +
|
||||
(0 - box.left) +
|
||||
' ' +
|
||||
(box.height + box.top) +
|
||||
')'
|
||||
);
|
||||
transformations.push('scale(1 -1)');
|
||||
box.top = box.left = 0;
|
||||
}
|
||||
|
||||
let tempValue: number;
|
||||
if (rotation < 0) {
|
||||
rotation -= Math.floor(rotation / 4) * 4;
|
||||
}
|
||||
rotation = rotation % 4;
|
||||
switch (rotation) {
|
||||
case 1:
|
||||
// 90deg
|
||||
tempValue = box.height / 2 + box.top;
|
||||
transformations.unshift(
|
||||
'rotate(90 ' + tempValue + ' ' + tempValue + ')'
|
||||
);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// 180deg
|
||||
transformations.unshift(
|
||||
'rotate(180 ' +
|
||||
(box.width / 2 + box.left) +
|
||||
' ' +
|
||||
(box.height / 2 + box.top) +
|
||||
')'
|
||||
);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// 270deg
|
||||
tempValue = box.width / 2 + box.left;
|
||||
transformations.unshift(
|
||||
'rotate(-90 ' + tempValue + ' ' + tempValue + ')'
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rotation % 2 === 1) {
|
||||
// Swap width/height and x/y for 90deg or 270deg rotation
|
||||
if (box.left !== 0 || box.top !== 0) {
|
||||
tempValue = box.left;
|
||||
box.left = box.top;
|
||||
box.top = tempValue;
|
||||
}
|
||||
if (box.width !== box.height) {
|
||||
tempValue = box.width;
|
||||
box.width = box.height;
|
||||
box.height = tempValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (transformations.length) {
|
||||
body =
|
||||
'<g transform="' +
|
||||
transformations.join(' ') +
|
||||
'">' +
|
||||
body +
|
||||
'</g>';
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate dimensions
|
||||
let width, height;
|
||||
|
||||
if (customisations.width === null && customisations.height === null) {
|
||||
// Set height to '1em', calculate width
|
||||
height = '1em';
|
||||
width = calculateSize(height, box.width / box.height);
|
||||
} else if (
|
||||
customisations.width !== null &&
|
||||
customisations.height !== null
|
||||
) {
|
||||
// Values are set
|
||||
width = customisations.width;
|
||||
height = customisations.height;
|
||||
} else if (customisations.height !== null) {
|
||||
// Height is set
|
||||
height = customisations.height;
|
||||
width = calculateSize(height, box.width / box.height);
|
||||
} else {
|
||||
// Width is set
|
||||
width = customisations.width as number | string;
|
||||
height = calculateSize(width, box.height / box.width);
|
||||
}
|
||||
|
||||
// Check for 'auto'
|
||||
if (width === 'auto') {
|
||||
width = box.width;
|
||||
}
|
||||
if (height === 'auto') {
|
||||
height = box.height;
|
||||
}
|
||||
|
||||
// Convert to string
|
||||
width = typeof width === 'string' ? width : width + '';
|
||||
height = typeof height === 'string' ? height : height + '';
|
||||
|
||||
// Result
|
||||
const result: IconifyIconBuildResult = {
|
||||
attributes: {
|
||||
width,
|
||||
height,
|
||||
preserveAspectRatio: preserveAspectRatio(customisations),
|
||||
viewBox:
|
||||
box.left + ' ' + box.top + ' ' + box.width + ' ' + box.height,
|
||||
},
|
||||
body,
|
||||
};
|
||||
|
||||
if (customisations.inline) {
|
||||
result.inline = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import type { IconifyIconName } from './name';
|
||||
import { stringToIcon, validateIcon } from './name';
|
||||
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { stringToIcon, validateIcon } from '@iconify/utils/lib/icon/name';
|
||||
|
||||
/**
|
||||
* Convert icons list from string/icon mix to icons and validate them
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { IconStorage } from '../storage/storage';
|
||||
import { getStorage } from '../storage/storage';
|
||||
import type { IconifyIconName } from './name';
|
||||
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
|
||||
/**
|
||||
* Sorted icons list
|
||||
@ -20,9 +20,8 @@ export function sortIcons(icons: IconifyIconName[]): SortedIcons {
|
||||
missing: [],
|
||||
pending: [],
|
||||
};
|
||||
const storage: Record<string, Record<string, IconStorage>> = Object.create(
|
||||
null
|
||||
);
|
||||
const storage: Record<string, Record<string, IconStorage>> =
|
||||
Object.create(null);
|
||||
|
||||
// Sort icons alphabetically to prevent duplicates and make sure they are sorted in API queries
|
||||
icons.sort((a, b) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { IconifyLoadIcons } from './loader';
|
||||
import type { IconifyIconName } from '../icon/name';
|
||||
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
|
||||
/**
|
||||
* Function to check if icon is pending
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { IconifyIconName } from '../icon/name';
|
||||
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
|
||||
/**
|
||||
* Function to abort loading (usually just removes callback because loading is already in progress)
|
||||
|
@ -1,8 +1,8 @@
|
||||
import type { IconifyJSON, IconifyIcon } from '@iconify/types';
|
||||
import type { FullIconifyIcon } from '@iconify/utils/lib/icon';
|
||||
import { parseIconSet } from '../icon/icon-set';
|
||||
import type { IconifyIconName } from '../icon/name';
|
||||
import { stringToIcon, validateIcon } from '../icon/name';
|
||||
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { stringToIcon, validateIcon } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
getStorage,
|
||||
getIcon,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
import { stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import { stringToIcon } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
IconifyIconCustomisations,
|
||||
defaults,
|
||||
@ -9,7 +9,10 @@ import {
|
||||
storageFunctions,
|
||||
getIconData,
|
||||
} from '@iconify/core/lib/storage/functions';
|
||||
import { iconToSVG, IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import {
|
||||
iconToSVG,
|
||||
IconifyIconBuildResult,
|
||||
} from '@iconify/utils/lib/svg/build';
|
||||
import { renderIcon } from './modules/render';
|
||||
import {
|
||||
initObserver,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IconifyElement } from '../modules/element';
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { IconifyIconCustomisations } from '@iconify/utils/lib/customisations';
|
||||
|
||||
/**
|
||||
|
@ -1,13 +1,13 @@
|
||||
// Core
|
||||
import { IconifyJSON, IconifyIcon } from '@iconify/types';
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
IconifyVerticalIconAlignment,
|
||||
} from '@iconify/utils/lib/customisations';
|
||||
import { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
import {
|
||||
IconifyStorageFunctions,
|
||||
storageFunctions,
|
||||
|
@ -1,13 +1,13 @@
|
||||
// Core
|
||||
import { IconifyJSON, IconifyIcon } from '@iconify/types';
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
IconifyIconCustomisations,
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
IconifyVerticalIconAlignment,
|
||||
} from '@iconify/utils/lib/customisations';
|
||||
import { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
import {
|
||||
IconifyStorageFunctions,
|
||||
storageFunctions,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { IconifyIconCustomisations } from '@iconify/utils/lib/customisations';
|
||||
import { IconifyFinder } from '../finders/interface';
|
||||
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
IconifyIconName,
|
||||
stringToIcon,
|
||||
validateIcon,
|
||||
} from '@iconify/core/lib/icon/name';
|
||||
} from '@iconify/utils/lib/icon/name';
|
||||
import { IconifyIconCustomisations } from '@iconify/utils/lib/customisations';
|
||||
import { IconifyFinder } from '../finders/interface';
|
||||
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
mergeCustomisations,
|
||||
defaults,
|
||||
} from '@iconify/utils/lib/customisations';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
||||
import { PlaceholderElement } from './finder';
|
||||
import {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IconifyIconName } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
||||
import { getStorage, getIcon } from '@iconify/core/lib/storage/storage';
|
||||
import { coreModules } from '@iconify/core/lib/modules';
|
||||
import { FullIconifyIcon } from '@iconify/utils/lib/icon';
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import type { IconifyJSON, IconifyIcon } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/utils/lib/icon/name';
|
||||
import type {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -18,7 +18,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
import { fullIcon } from '@iconify/utils/lib/icon';
|
||||
|
||||
// Modules
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
alignmentFromString,
|
||||
} from '@iconify/utils/lib/customisations/shorthand';
|
||||
import { rotateFromString } from '@iconify/utils/lib/customisations/rotate';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
||||
import type { IconifyIconCustomisations, IconProps, IconRef } from './props';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/utils/lib/icon/name';
|
||||
import type {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -17,7 +17,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import type { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/utils/lib/icon';
|
||||
|
||||
// Modules
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
alignmentFromString,
|
||||
} from '@iconify/utils/lib/customisations/shorthand';
|
||||
import { rotateFromString } from '@iconify/utils/lib/customisations/rotate';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
||||
import type { IconProps } from './props';
|
||||
|
||||
|
8
packages/utils/package-lock.json
generated
8
packages/utils/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@iconify/json-tools",
|
||||
"version": "2.0.0-dev",
|
||||
"name": "@iconify/utils",
|
||||
"version": "1.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@iconify/json-tools",
|
||||
"version": "2.0.0-dev",
|
||||
"name": "@iconify/utils",
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iconify/types": "^1.0.6"
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "@iconify/utils",
|
||||
"description": "Common functions for working with Iconify icon sets used by various packages.",
|
||||
"author": "Vjacheslav Trushkin",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"license": "MIT",
|
||||
"bugs": "https://github.com/iconify/iconify/issues",
|
||||
"homepage": "https://iconify.design/",
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { matchName } from '.';
|
||||
|
||||
/**
|
||||
* Icon name
|
||||
*/
|
||||
@ -12,11 +14,6 @@ export interface IconifyIconName {
|
||||
*/
|
||||
export type IconifyIconSource = Omit<IconifyIconName, 'name'>;
|
||||
|
||||
/**
|
||||
* Expression to test part of icon name.
|
||||
*/
|
||||
const match = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
||||
|
||||
/**
|
||||
* Convert string to Icon object.
|
||||
*/
|
||||
@ -96,8 +93,9 @@ export const validateIcon = (
|
||||
}
|
||||
|
||||
return !!(
|
||||
(icon.provider === '' || icon.provider.match(match)) &&
|
||||
((allowSimpleName && icon.prefix === '') || icon.prefix.match(match)) &&
|
||||
icon.name.match(match)
|
||||
(icon.provider === '' || icon.provider.match(matchName)) &&
|
||||
((allowSimpleName && icon.prefix === '') ||
|
||||
icon.prefix.match(matchName)) &&
|
||||
icon.name.match(matchName)
|
||||
);
|
||||
};
|
@ -0,0 +1,237 @@
|
||||
import type { FullIconifyIcon } from '../icon';
|
||||
import type { FullIconCustomisations } from '../customisations';
|
||||
import { calculateSize } from '../svg/size';
|
||||
|
||||
/**
|
||||
* Get preserveAspectRatio value
|
||||
*/
|
||||
function preserveAspectRatio(props: FullIconCustomisations): string {
|
||||
let result = '';
|
||||
switch (props.hAlign) {
|
||||
case 'left':
|
||||
result += 'xMin';
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
result += 'xMax';
|
||||
break;
|
||||
|
||||
default:
|
||||
result += 'xMid';
|
||||
}
|
||||
switch (props.vAlign) {
|
||||
case 'top':
|
||||
result += 'YMin';
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
result += 'YMax';
|
||||
break;
|
||||
|
||||
default:
|
||||
result += 'YMid';
|
||||
}
|
||||
result += props.slice ? ' slice' : ' meet';
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for getSVGData() result
|
||||
*/
|
||||
export interface IconifyIconBuildResult {
|
||||
attributes: {
|
||||
// Attributes for <svg>
|
||||
width: string;
|
||||
height: string;
|
||||
preserveAspectRatio: string;
|
||||
viewBox: string;
|
||||
};
|
||||
// Content
|
||||
body: string;
|
||||
// True if 'vertical-align: -0.125em' or equivalent should be added by implementation
|
||||
inline?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for viewBox
|
||||
*/
|
||||
interface ViewBox {
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SVG attributes and content from icon + customisations
|
||||
*
|
||||
* Does not generate style to make it compatible with frameworks that use objects for style, such as React.
|
||||
* Instead, it generates 'inline' value. If true, rendering engine should add verticalAlign: -0.125em to icon.
|
||||
*
|
||||
* Customisations should be normalised by platform specific parser.
|
||||
* Result should be converted to <svg> by platform specific parser.
|
||||
* Use replaceIDs to generate unique IDs for body.
|
||||
*/
|
||||
export function iconToSVG(
|
||||
icon: FullIconifyIcon,
|
||||
customisations: FullIconCustomisations
|
||||
): IconifyIconBuildResult {
|
||||
// viewBox
|
||||
const box: ViewBox = {
|
||||
left: icon.left,
|
||||
top: icon.top,
|
||||
width: icon.width,
|
||||
height: icon.height,
|
||||
};
|
||||
|
||||
// Body
|
||||
let body = icon.body;
|
||||
|
||||
// Apply transformations
|
||||
[icon, customisations].forEach((props) => {
|
||||
const transformations: string[] = [];
|
||||
const hFlip = props.hFlip;
|
||||
const vFlip = props.vFlip;
|
||||
let rotation = props.rotate;
|
||||
|
||||
// Icon is flipped first, then rotated
|
||||
if (hFlip) {
|
||||
if (vFlip) {
|
||||
rotation += 2;
|
||||
} else {
|
||||
// Horizontal flip
|
||||
transformations.push(
|
||||
'translate(' +
|
||||
(box.width + box.left) +
|
||||
' ' +
|
||||
(0 - box.top) +
|
||||
')'
|
||||
);
|
||||
transformations.push('scale(-1 1)');
|
||||
box.top = box.left = 0;
|
||||
}
|
||||
} else if (vFlip) {
|
||||
// Vertical flip
|
||||
transformations.push(
|
||||
'translate(' +
|
||||
(0 - box.left) +
|
||||
' ' +
|
||||
(box.height + box.top) +
|
||||
')'
|
||||
);
|
||||
transformations.push('scale(1 -1)');
|
||||
box.top = box.left = 0;
|
||||
}
|
||||
|
||||
let tempValue: number;
|
||||
if (rotation < 0) {
|
||||
rotation -= Math.floor(rotation / 4) * 4;
|
||||
}
|
||||
rotation = rotation % 4;
|
||||
switch (rotation) {
|
||||
case 1:
|
||||
// 90deg
|
||||
tempValue = box.height / 2 + box.top;
|
||||
transformations.unshift(
|
||||
'rotate(90 ' + tempValue + ' ' + tempValue + ')'
|
||||
);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// 180deg
|
||||
transformations.unshift(
|
||||
'rotate(180 ' +
|
||||
(box.width / 2 + box.left) +
|
||||
' ' +
|
||||
(box.height / 2 + box.top) +
|
||||
')'
|
||||
);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// 270deg
|
||||
tempValue = box.width / 2 + box.left;
|
||||
transformations.unshift(
|
||||
'rotate(-90 ' + tempValue + ' ' + tempValue + ')'
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rotation % 2 === 1) {
|
||||
// Swap width/height and x/y for 90deg or 270deg rotation
|
||||
if (box.left !== 0 || box.top !== 0) {
|
||||
tempValue = box.left;
|
||||
box.left = box.top;
|
||||
box.top = tempValue;
|
||||
}
|
||||
if (box.width !== box.height) {
|
||||
tempValue = box.width;
|
||||
box.width = box.height;
|
||||
box.height = tempValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (transformations.length) {
|
||||
body =
|
||||
'<g transform="' +
|
||||
transformations.join(' ') +
|
||||
'">' +
|
||||
body +
|
||||
'</g>';
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate dimensions
|
||||
let width, height;
|
||||
|
||||
if (customisations.width === null && customisations.height === null) {
|
||||
// Set height to '1em', calculate width
|
||||
height = '1em';
|
||||
width = calculateSize(height, box.width / box.height);
|
||||
} else if (
|
||||
customisations.width !== null &&
|
||||
customisations.height !== null
|
||||
) {
|
||||
// Values are set
|
||||
width = customisations.width;
|
||||
height = customisations.height;
|
||||
} else if (customisations.height !== null) {
|
||||
// Height is set
|
||||
height = customisations.height;
|
||||
width = calculateSize(height, box.width / box.height);
|
||||
} else {
|
||||
// Width is set
|
||||
width = customisations.width as number | string;
|
||||
height = calculateSize(width, box.height / box.width);
|
||||
}
|
||||
|
||||
// Check for 'auto'
|
||||
if (width === 'auto') {
|
||||
width = box.width;
|
||||
}
|
||||
if (height === 'auto') {
|
||||
height = box.height;
|
||||
}
|
||||
|
||||
// Convert to string
|
||||
width = typeof width === 'string' ? width : width + '';
|
||||
height = typeof height === 'string' ? height : height + '';
|
||||
|
||||
// Result
|
||||
const result: IconifyIconBuildResult = {
|
||||
attributes: {
|
||||
width,
|
||||
height,
|
||||
preserveAspectRatio: preserveAspectRatio(customisations),
|
||||
viewBox:
|
||||
box.left + ' ' + box.top + ' ' + box.width + ' ' + box.height,
|
||||
},
|
||||
body,
|
||||
};
|
||||
|
||||
if (customisations.inline) {
|
||||
result.inline = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import type { IconifyIconName } from '../../lib/icon/name';
|
||||
import { stringToIcon, validateIcon } from '../../lib/icon/name';
|
||||
import type { IconifyIconName } from '../lib/icon/name';
|
||||
import { stringToIcon, validateIcon } from '../lib/icon/name';
|
||||
|
||||
describe('Testing icon name', () => {
|
||||
it('Simple icon names', () => {
|
@ -1,14 +1,11 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import type { IconifyIconBuildResult } from '../../lib/builder';
|
||||
import { iconToSVG } from '../../lib/builder';
|
||||
import type { FullIconifyIcon } from '@iconify/utils/lib/icon';
|
||||
import { fullIcon, iconDefaults } from '@iconify/utils/lib/icon';
|
||||
import type { FullIconCustomisations } from '@iconify/utils/lib/customisations';
|
||||
import {
|
||||
defaults,
|
||||
mergeCustomisations,
|
||||
} from '@iconify/utils/lib/customisations';
|
||||
import type { IconifyIconBuildResult } from '../lib/svg/build';
|
||||
import { iconToSVG } from '../lib/svg/build';
|
||||
import type { FullIconifyIcon } from '../lib/icon';
|
||||
import { fullIcon, iconDefaults } from '../lib/icon';
|
||||
import type { FullIconCustomisations } from '../lib/customisations';
|
||||
import { defaults, mergeCustomisations } from '../lib/customisations';
|
||||
|
||||
describe('Testing iconToSVG', () => {
|
||||
it('Empty icon', () => {
|
@ -11,7 +11,7 @@ import {
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -27,7 +27,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/utils/lib/icon';
|
||||
|
||||
// Modules
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
alignmentFromString,
|
||||
} from '@iconify/utils/lib/customisations/shorthand';
|
||||
import { rotateFromString } from '@iconify/utils/lib/customisations/rotate';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
||||
import { IconifyIconCustomisations, IconProps } from './props';
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { ExtendedVue } from 'vue/types/vue';
|
||||
import { IconifyJSON } from '@iconify/types';
|
||||
|
||||
// Core
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/core/lib/icon/name';
|
||||
import { IconifyIconName, stringToIcon } from '@iconify/utils/lib/icon/name';
|
||||
import {
|
||||
IconifyIconSize,
|
||||
IconifyHorizontalIconAlignment,
|
||||
@ -19,7 +19,7 @@ import {
|
||||
IconifyBuilderFunctions,
|
||||
builderFunctions,
|
||||
} from '@iconify/core/lib/builder/functions';
|
||||
import { IconifyIconBuildResult } from '@iconify/core/lib/builder';
|
||||
import { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
||||
import { fullIcon, IconifyIcon } from '@iconify/utils/lib/icon';
|
||||
|
||||
// Modules
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
alignmentFromString,
|
||||
} from '@iconify/utils/lib/customisations/shorthand';
|
||||
import { rotateFromString } from '@iconify/utils/lib/customisations/rotate';
|
||||
import { iconToSVG } from '@iconify/core/lib/builder';
|
||||
import { iconToSVG } from '@iconify/utils/lib/svg/build';
|
||||
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
||||
import { IconifyIconCustomisations, IconProps } from './props';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user