mirror of
https://github.com/iconify/iconify.git
synced 2024-11-09 23:00:56 +00:00
svg framework: add bg and mask modes, test changing modes
This commit is contained in:
parent
b08d1221e3
commit
40dd0aba48
@ -47,7 +47,8 @@ for (const prefix in propsToAddTo) {
|
||||
export function renderBackground(
|
||||
element: IconifyElement,
|
||||
props: IconifyElementProps,
|
||||
iconData: FullIconifyIcon
|
||||
iconData: FullIconifyIcon,
|
||||
useMask: boolean
|
||||
): IconifyElement {
|
||||
// Generate data to render
|
||||
const renderData = iconToSVG(iconData, {
|
||||
@ -74,14 +75,13 @@ export function renderBackground(
|
||||
);
|
||||
|
||||
// Update style
|
||||
const isMonotone = renderData.body.indexOf('currentColor') !== -1;
|
||||
const url = svgToURL(html);
|
||||
const newStyles: Record<string, string> = {
|
||||
'--svg': url,
|
||||
'width': renderAttribs.width,
|
||||
'height': renderAttribs.height,
|
||||
...commonProps,
|
||||
...(isMonotone ? monotoneProps : coloredProps),
|
||||
...(useMask ? monotoneProps : coloredProps),
|
||||
};
|
||||
if (renderData.inline) {
|
||||
newStyles['vertical-align'] = '-0.125em';
|
||||
|
@ -8,7 +8,7 @@ export function propsChanged(
|
||||
props1: IconifyElementProps,
|
||||
props2: IconifyElementProps
|
||||
): boolean {
|
||||
if (props1.name !== props2.name) {
|
||||
if (props1.name !== props2.name || props1.mode !== props2.mode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,13 @@ export const inlineClass = 'iconify-inline';
|
||||
|
||||
/**
|
||||
* Icon render mode
|
||||
*
|
||||
* 'style' = 'bg' or 'mask', depending on icon content
|
||||
* 'bg' = inline style using `background`
|
||||
* 'mask' = inline style using `mask`
|
||||
* 'inline' = inline SVG.
|
||||
*/
|
||||
export type IconRenderMode = 'style' | 'inline';
|
||||
export type IconRenderMode = 'style' | 'bg' | 'mask' | 'inline';
|
||||
|
||||
/**
|
||||
* Data used to verify if icon is the same
|
||||
|
@ -123,14 +123,24 @@ export function scanDOM(rootNode?: ObservedNode, addTempNode = false): void {
|
||||
pauseObservingNode(observedNode);
|
||||
}
|
||||
|
||||
if (
|
||||
element.tagName.toUpperCase() === 'SVG' ||
|
||||
props.mode !== 'style'
|
||||
) {
|
||||
renderInlineSVG(element, props, iconData);
|
||||
} else {
|
||||
renderBackground(element, props, iconData);
|
||||
if (element.tagName.toUpperCase() !== 'SVG') {
|
||||
// Check for one of style modes
|
||||
const mode = props.mode;
|
||||
const isMask: boolean | null =
|
||||
mode === 'mask' ||
|
||||
(mode === 'bg'
|
||||
? false
|
||||
: mode === 'style'
|
||||
? iconData.body.indexOf('currentColor') !== -1
|
||||
: null);
|
||||
|
||||
if (typeof isMask === 'boolean') {
|
||||
renderBackground(element, props, iconData, isMask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
renderInlineSVG(element, props, iconData);
|
||||
}
|
||||
|
||||
// Find all elements
|
||||
|
117
packages/iconify/tests/changing-modes-test.ts
Normal file
117
packages/iconify/tests/changing-modes-test.ts
Normal file
@ -0,0 +1,117 @@
|
||||
import { iconExists } from '@iconify/core/lib/storage/functions';
|
||||
import {
|
||||
fakeAPI,
|
||||
nextPrefix,
|
||||
setupDOM,
|
||||
waitDOMReady,
|
||||
resetState,
|
||||
mockAPIData,
|
||||
awaitUntil,
|
||||
nextTick,
|
||||
} from './helpers';
|
||||
import { addBodyNode } from '../src/observer/root';
|
||||
import { scanDOM } from '../src/scanner/index';
|
||||
import { elementDataProperty } from '../src/scanner/config';
|
||||
import { initObserver } from '../src/observer';
|
||||
|
||||
describe('Changing render modes', () => {
|
||||
const provider = nextPrefix();
|
||||
|
||||
beforeAll(() => {
|
||||
fakeAPI(provider);
|
||||
});
|
||||
|
||||
afterEach(resetState);
|
||||
|
||||
it('Various background modes', async () => {
|
||||
const prefix = nextPrefix();
|
||||
const iconName = `@${provider}:${prefix}:home`;
|
||||
|
||||
// Add icon with API
|
||||
expect(iconExists(iconName)).toBe(false);
|
||||
mockAPIData({
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
response: {
|
||||
prefix,
|
||||
icons: {
|
||||
home: {
|
||||
body: '<g />',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Setup DOM and wait for it to be ready
|
||||
setupDOM(
|
||||
`<span class="iconify" data-icon="${iconName}" data-mode="style"></span>`
|
||||
);
|
||||
await waitDOMReady();
|
||||
|
||||
// Observe body
|
||||
addBodyNode();
|
||||
initObserver(scanDOM);
|
||||
|
||||
// Check HTML and data
|
||||
expect(document.body.innerHTML).toBe(
|
||||
`<span class="iconify" data-icon="${iconName}" data-mode="style"></span>`
|
||||
);
|
||||
|
||||
// Wait for re-render
|
||||
const placeholder = document.body.childNodes[0] as HTMLSpanElement;
|
||||
const style = placeholder.style;
|
||||
|
||||
await awaitUntil(() => !!style.getPropertyValue('--svg'));
|
||||
|
||||
// Check HTML
|
||||
expect(document.body.innerHTML).toBe(
|
||||
`<span class="iconify iconify--${provider} iconify--${prefix}" data-icon="${iconName}" data-mode="style" style="--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' preserveAspectRatio='xMidYMid meet' viewBox='0 0 16 16'%3E%3Cg /%3E%3C/svg%3E"); width: 1em; height: 1em; display: inline-block; background-color: transparent; background-repeat: no-repeat; background-size: 100% 100%;"></span>`
|
||||
);
|
||||
|
||||
let data = placeholder[elementDataProperty];
|
||||
expect(data.addedStyles.indexOf('background-image') !== -1).toBe(true);
|
||||
expect(data.addedStyles.indexOf('mask-image') !== -1).toBe(false);
|
||||
expect(style.getPropertyValue('mask-image')).toBe('');
|
||||
|
||||
// Render as mask
|
||||
placeholder.setAttribute('data-mode', 'mask');
|
||||
await awaitUntil(() => !!style.getPropertyValue('mask-image'));
|
||||
expect(document.body.innerHTML).toBe(
|
||||
`<span class="iconify iconify--${provider} iconify--${prefix}" data-icon="${iconName}" data-mode="mask" style="--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' preserveAspectRatio='xMidYMid meet' viewBox='0 0 16 16'%3E%3Cg /%3E%3C/svg%3E"); width: 1em; height: 1em; display: inline-block; background-color: currentColor; mask-image: var(--svg); mask-repeat: no-repeat; mask-size: 100% 100%;"></span>`
|
||||
);
|
||||
|
||||
data = placeholder[elementDataProperty];
|
||||
expect(data.addedStyles.indexOf('background-image') !== -1).toBe(false);
|
||||
expect(data.addedStyles.indexOf('mask-image') !== -1).toBe(true);
|
||||
expect(style.getPropertyValue('background-image')).toBe('');
|
||||
|
||||
// Re-render as background
|
||||
placeholder.setAttribute('data-mode', 'bg');
|
||||
await awaitUntil(() => !style.getPropertyValue('mask-image'));
|
||||
expect(document.body.innerHTML).toBe(
|
||||
`<span class="iconify iconify--${provider} iconify--${prefix}" data-icon="${iconName}" data-mode="bg" style="--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' preserveAspectRatio='xMidYMid meet' viewBox='0 0 16 16'%3E%3Cg /%3E%3C/svg%3E"); width: 1em; height: 1em; display: inline-block; background-color: transparent; background-repeat: no-repeat; background-size: 100% 100%;"></span>`
|
||||
);
|
||||
|
||||
data = placeholder[elementDataProperty];
|
||||
expect(data.addedStyles.indexOf('background-image') !== -1).toBe(true);
|
||||
expect(data.addedStyles.indexOf('mask-image') !== -1).toBe(false);
|
||||
expect(style.getPropertyValue('mask-image')).toBe('');
|
||||
|
||||
// Re-render as SVG
|
||||
placeholder.setAttribute('data-mode', 'inline');
|
||||
await awaitUntil(() => document.body.childNodes[0] !== placeholder);
|
||||
expect(document.body.innerHTML).toBe(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16" data-icon="${iconName}" data-mode="inline" style="" class="iconify iconify--${provider} iconify--${prefix}"><g></g></svg>`
|
||||
);
|
||||
const svgData = document.body.childNodes[0][elementDataProperty];
|
||||
expect(svgData.mode).toBe('inline');
|
||||
|
||||
// Change to style (should not work!)
|
||||
placeholder.setAttribute('data-mode', 'bg');
|
||||
await awaitUntil(() => svgData.mode !== 'bg');
|
||||
expect(document.body.innerHTML).toBe(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16" data-icon="${iconName}" data-mode="inline" style="" class="iconify iconify--${provider} iconify--${prefix}"><g></g></svg>`
|
||||
);
|
||||
});
|
||||
});
|
@ -36,10 +36,15 @@ describe('Testing rendering nodes as background', () => {
|
||||
|
||||
// Get node and render it
|
||||
const { node, props } = items[0];
|
||||
const result = renderBackground(node, props, {
|
||||
...iconDefaults,
|
||||
...data,
|
||||
});
|
||||
const result = renderBackground(
|
||||
node,
|
||||
props,
|
||||
{
|
||||
...iconDefaults,
|
||||
...data,
|
||||
},
|
||||
data.body.indexOf('currentColor') !== -1
|
||||
);
|
||||
|
||||
// Make sure node did not change
|
||||
expect(result).toBe(node);
|
||||
|
Loading…
Reference in New Issue
Block a user