mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-09 01:25:01 +00:00
fix: types for css support
This commit is contained in:
+114
-65
@@ -1,7 +1,29 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { camelCase, parse, SvgAst } from './xml';
|
import {
|
||||||
|
AST,
|
||||||
|
camelCase,
|
||||||
|
err,
|
||||||
|
fetchText,
|
||||||
|
parse,
|
||||||
|
Styles,
|
||||||
|
SvgAst,
|
||||||
|
UriProps,
|
||||||
|
XmlProps,
|
||||||
|
} from './xml';
|
||||||
|
// @ts-ignore
|
||||||
import baseCssAdapter from 'css-select-base-adapter';
|
import baseCssAdapter from 'css-select-base-adapter';
|
||||||
import csstree, { List } from 'css-tree';
|
import csstree, {
|
||||||
|
Atrule,
|
||||||
|
CssNode,
|
||||||
|
Declaration,
|
||||||
|
DeclarationList,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
PseudoClassSelector,
|
||||||
|
Rule,
|
||||||
|
Selector,
|
||||||
|
SelectorList,
|
||||||
|
} from 'css-tree';
|
||||||
import cssSelect from 'css-select';
|
import cssSelect from 'css-select';
|
||||||
import stable from 'stable';
|
import stable from 'stable';
|
||||||
|
|
||||||
@@ -15,26 +37,26 @@ import stable from 'stable';
|
|||||||
const rnsvgCssSelectAdapterMin = {
|
const rnsvgCssSelectAdapterMin = {
|
||||||
// is the node a tag?
|
// is the node a tag?
|
||||||
// isTag: ( node:Node ) => isTag:Boolean
|
// isTag: ( node:Node ) => isTag:Boolean
|
||||||
isTag(node) {
|
isTag(node: AST) {
|
||||||
return node.tag;
|
return node.tag;
|
||||||
},
|
},
|
||||||
|
|
||||||
// get the parent of the node
|
// get the parent of the node
|
||||||
// getParent: ( node:Node ) => parentNode:Node
|
// getParent: ( node:Node ) => parentNode:Node
|
||||||
// returns null when no parent exists
|
// returns null when no parent exists
|
||||||
getParent(node) {
|
getParent(node: AST) {
|
||||||
return node.parent || null;
|
return node.parent || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// get the node's children
|
// get the node's children
|
||||||
// getChildren: ( node:Node ) => children:[Node]
|
// getChildren: ( node:Node ) => children:[Node]
|
||||||
getChildren(node) {
|
getChildren(node: AST) {
|
||||||
return node.children || [];
|
return node.children || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
// get the name of the tag
|
// get the name of the tag
|
||||||
// getName: ( elem:ElementNode ) => tagName:String
|
// getName: ( elem:ElementNode ) => tagName:String
|
||||||
getName(elemAst) {
|
getName(elemAst: AST) {
|
||||||
return elemAst.tag;
|
return elemAst.tag;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -48,8 +70,8 @@ const rnsvgCssSelectAdapterMin = {
|
|||||||
// get the attribute value
|
// get the attribute value
|
||||||
// getAttributeValue: ( elem:ElementNode, name:String ) => value:String
|
// getAttributeValue: ( elem:ElementNode, name:String ) => value:String
|
||||||
// returns null when attribute doesn't exist
|
// returns null when attribute doesn't exist
|
||||||
getAttributeValue(elem, name) {
|
getAttributeValue(elem: AST, name: string) {
|
||||||
return elem && elem.props.hasOwnProperty(name) ? elem.props[name] : null;
|
return elem.props.hasOwnProperty(name) ? elem.props[name] : null;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,7 +85,7 @@ const rnsvgCssSelectAdapter = baseCssAdapter(rnsvgCssSelectAdapterMin);
|
|||||||
* @param {String} selectors CSS selector(s) string
|
* @param {String} selectors CSS selector(s) string
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
function querySelectorAll(document, selectors) {
|
function querySelectorAll(document: AST, selectors: string) {
|
||||||
return cssSelect(selectors, document, cssSelectOpts);
|
return cssSelect(selectors, document, cssSelectOpts);
|
||||||
}
|
}
|
||||||
const cssSelectOpts = {
|
const cssSelectOpts = {
|
||||||
@@ -71,23 +93,37 @@ const cssSelectOpts = {
|
|||||||
adapter: rnsvgCssSelectAdapter,
|
adapter: rnsvgCssSelectAdapter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type FlatPseudoSelector = {
|
||||||
|
item: ListItem<CssNode>;
|
||||||
|
list: List<CssNode>;
|
||||||
|
};
|
||||||
|
type FlatPseudoSelectorList = FlatPseudoSelector[];
|
||||||
|
type FlatSelector = {
|
||||||
|
item: ListItem<CssNode>;
|
||||||
|
atrule: Atrule | null;
|
||||||
|
rule: CssNode;
|
||||||
|
pseudos: FlatPseudoSelectorList;
|
||||||
|
};
|
||||||
|
type FlatSelectorList = FlatSelector[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flatten a CSS AST to a selectors list.
|
* Flatten a CSS AST to a selectors list.
|
||||||
*
|
*
|
||||||
* @param {Object} cssAst css-tree AST to flatten
|
* @param {Object} cssAst css-tree AST to flatten
|
||||||
* @param {Array} selectors
|
* @param {Array} selectors
|
||||||
*/
|
*/
|
||||||
function flattenToSelectors(cssAst, selectors) {
|
function flattenToSelectors(cssAst: CssNode, selectors: FlatSelectorList) {
|
||||||
csstree.walk(cssAst, {
|
csstree.walk(cssAst, {
|
||||||
visit: 'Rule',
|
visit: 'Rule',
|
||||||
enter(rule) {
|
enter(rule: CssNode) {
|
||||||
const { type, prelude } = rule;
|
const { type, prelude } = rule as Rule;
|
||||||
if (type !== 'Rule') {
|
if (type !== 'Rule') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const atrule = this.atrule;
|
const atrule = this.atrule;
|
||||||
prelude.children.each(({ children }, item) => {
|
(prelude as SelectorList).children.each((node, item) => {
|
||||||
const pseudos = [];
|
const { children } = node as Selector;
|
||||||
|
const pseudos: FlatPseudoSelectorList = [];
|
||||||
selectors.push({
|
selectors.push({
|
||||||
item,
|
item,
|
||||||
atrule,
|
atrule,
|
||||||
@@ -116,11 +152,12 @@ function flattenToSelectors(cssAst, selectors) {
|
|||||||
* @param {Array} selectors to filter
|
* @param {Array} selectors to filter
|
||||||
* @return {Array} Filtered selectors that match the passed media queries
|
* @return {Array} Filtered selectors that match the passed media queries
|
||||||
*/
|
*/
|
||||||
function filterByMqs(selectors) {
|
function filterByMqs(selectors: FlatSelectorList) {
|
||||||
return selectors.filter(({ atrule }) => {
|
return selectors.filter(({ atrule }) => {
|
||||||
if (atrule === null) {
|
if (atrule === null) {
|
||||||
return ~useMqs.indexOf('');
|
return ~useMqs.indexOf('');
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
const { name, expression } = atrule;
|
const { name, expression } = atrule;
|
||||||
return ~useMqs.indexOf(
|
return ~useMqs.indexOf(
|
||||||
expression && expression.children.first().type === 'MediaQueryList'
|
expression && expression.children.first().type === 'MediaQueryList'
|
||||||
@@ -138,13 +175,13 @@ const useMqs = ['', 'screen'];
|
|||||||
* @param {Array} selectors to filter
|
* @param {Array} selectors to filter
|
||||||
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
|
* @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
|
||||||
*/
|
*/
|
||||||
function filterByPseudos(selectors) {
|
function filterByPseudos(selectors: FlatSelectorList) {
|
||||||
return selectors.filter(
|
return selectors.filter(
|
||||||
({ pseudos }) =>
|
({ pseudos }) =>
|
||||||
~usePseudos.indexOf(
|
~usePseudos.indexOf(
|
||||||
csstree.generate({
|
csstree.generate({
|
||||||
type: 'Selector',
|
type: 'Selector',
|
||||||
children: new List().fromArray(
|
children: new List<CssNode>().fromArray(
|
||||||
pseudos.map(pseudo => pseudo.item.data),
|
pseudos.map(pseudo => pseudo.item.data),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
@@ -160,18 +197,19 @@ const usePseudos = [''];
|
|||||||
* @param {Array} selectors to clean
|
* @param {Array} selectors to clean
|
||||||
* @return {Array} Selectors without pseudo-elements and/or -classes
|
* @return {Array} Selectors without pseudo-elements and/or -classes
|
||||||
*/
|
*/
|
||||||
function cleanPseudos(selectors) {
|
function cleanPseudos(selectors: FlatSelectorList) {
|
||||||
selectors.forEach(({ pseudos }) =>
|
selectors.forEach(({ pseudos }) =>
|
||||||
pseudos.forEach(pseudo => pseudo.list.remove(pseudo.item)),
|
pseudos.forEach(pseudo => pseudo.list.remove(pseudo.item)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function specificity(selector) {
|
type Specificity = [number, number, number];
|
||||||
|
function specificity(selector: Selector): Specificity {
|
||||||
let A = 0;
|
let A = 0;
|
||||||
let B = 0;
|
let B = 0;
|
||||||
let C = 0;
|
let C = 0;
|
||||||
|
|
||||||
selector.children.each(function walk(node) {
|
selector.children.each(function walk(node: CssNode) {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'SelectorList':
|
case 'SelectorList':
|
||||||
case 'Selector':
|
case 'Selector':
|
||||||
@@ -190,7 +228,8 @@ function specificity(selector) {
|
|||||||
case 'PseudoClassSelector':
|
case 'PseudoClassSelector':
|
||||||
switch (node.name.toLowerCase()) {
|
switch (node.name.toLowerCase()) {
|
||||||
case 'not':
|
case 'not':
|
||||||
node.children.each(walk);
|
const children = (node as PseudoClassSelector).children;
|
||||||
|
children && children.each(walk);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'before':
|
case 'before':
|
||||||
@@ -232,7 +271,10 @@ function specificity(selector) {
|
|||||||
* @param {Array} bSpecificity Specificity of selector B
|
* @param {Array} bSpecificity Specificity of selector B
|
||||||
* @return {Number} Score of selector specificity A compared to selector specificity B
|
* @return {Number} Score of selector specificity A compared to selector specificity B
|
||||||
*/
|
*/
|
||||||
function compareSpecificity(aSpecificity, bSpecificity) {
|
function compareSpecificity(
|
||||||
|
aSpecificity: Specificity,
|
||||||
|
bSpecificity: Specificity,
|
||||||
|
) {
|
||||||
for (let i = 0; i < 4; i += 1) {
|
for (let i = 0; i < 4; i += 1) {
|
||||||
if (aSpecificity[i] < bSpecificity[i]) {
|
if (aSpecificity[i] < bSpecificity[i]) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -250,9 +292,12 @@ function compareSpecificity(aSpecificity, bSpecificity) {
|
|||||||
* @param {Object} selectorB Simple selector B
|
* @param {Object} selectorB Simple selector B
|
||||||
* @return {Number} Score of selector A compared to selector B
|
* @return {Number} Score of selector A compared to selector B
|
||||||
*/
|
*/
|
||||||
function bySelectorSpecificity(selectorA, selectorB) {
|
function bySelectorSpecificity(
|
||||||
const aSpecificity = specificity(selectorA.item.data),
|
selectorA: FlatSelector,
|
||||||
bSpecificity = specificity(selectorB.item.data);
|
selectorB: FlatSelector,
|
||||||
|
) {
|
||||||
|
const aSpecificity = specificity(selectorA.item.data as Selector),
|
||||||
|
bSpecificity = specificity(selectorB.item.data as Selector);
|
||||||
return compareSpecificity(aSpecificity, bSpecificity);
|
return compareSpecificity(aSpecificity, bSpecificity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +307,7 @@ function bySelectorSpecificity(selectorA, selectorB) {
|
|||||||
* @param {Array} selectors to be sorted
|
* @param {Array} selectors to be sorted
|
||||||
* @return {Array} Stable sorted selectors
|
* @return {Array} Stable sorted selectors
|
||||||
*/
|
*/
|
||||||
function sortSelectors(selectors) {
|
function sortSelectors(selectors: FlatSelectorList) {
|
||||||
return stable(selectors, bySelectorSpecificity);
|
return stable(selectors, bySelectorSpecificity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,8 +315,13 @@ const declarationParseProps = {
|
|||||||
context: 'declarationList',
|
context: 'declarationList',
|
||||||
parseValue: false,
|
parseValue: false,
|
||||||
};
|
};
|
||||||
function CSSStyleDeclaration({ props: { style }, styles }) {
|
type CSSStyleDeclaration = {
|
||||||
|
style: Styles;
|
||||||
|
properties: Map<string, boolean | undefined>;
|
||||||
|
};
|
||||||
|
function CSSStyleDeclaration({ props, styles }: AST): CSSStyleDeclaration {
|
||||||
const properties = new Map();
|
const properties = new Map();
|
||||||
|
const style = props.style as Styles;
|
||||||
const styleDeclaration = {
|
const styleDeclaration = {
|
||||||
style,
|
style,
|
||||||
properties,
|
properties,
|
||||||
@@ -280,22 +330,25 @@ function CSSStyleDeclaration({ props: { style }, styles }) {
|
|||||||
return styleDeclaration;
|
return styleDeclaration;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
csstree
|
const declarations = csstree.parse(
|
||||||
.parse(styles, declarationParseProps)
|
styles,
|
||||||
.children.each(({ property, value, important }) => {
|
declarationParseProps,
|
||||||
try {
|
) as DeclarationList;
|
||||||
const name = property.trim();
|
declarations.children.each(node => {
|
||||||
properties.set(name, important);
|
try {
|
||||||
style[camelCase(name)] = csstree.generate(value).trim();
|
const { property, value, important } = node as Declaration;
|
||||||
} catch (styleError) {
|
const name = property.trim();
|
||||||
if (styleError.message !== 'Unknown node type: undefined') {
|
properties.set(name, important);
|
||||||
console.warn(
|
style[camelCase(name)] = csstree.generate(value).trim();
|
||||||
"Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " +
|
} catch (styleError) {
|
||||||
styleError,
|
if (styleError.message !== 'Unknown node type: undefined') {
|
||||||
);
|
console.warn(
|
||||||
}
|
"Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " +
|
||||||
|
styleError,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " +
|
"Warning: Parse error when parsing inline styles, style properties of this element cannot be used. The raw styles can still be get/set using .attr('style').value. Error details: " +
|
||||||
@@ -305,7 +358,7 @@ function CSSStyleDeclaration({ props: { style }, styles }) {
|
|||||||
return styleDeclaration;
|
return styleDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initStyle(selectedEl) {
|
function initStyle(selectedEl: AST) {
|
||||||
if (!selectedEl.style) {
|
if (!selectedEl.style) {
|
||||||
if (!selectedEl.props.style) {
|
if (!selectedEl.props.style) {
|
||||||
selectedEl.props.style = {};
|
selectedEl.props.style = {};
|
||||||
@@ -320,8 +373,8 @@ function initStyle(selectedEl) {
|
|||||||
* @param elemName
|
* @param elemName
|
||||||
* @return {?Object}
|
* @return {?Object}
|
||||||
*/
|
*/
|
||||||
function closestElem(node, elemName) {
|
function closestElem(node: AST, elemName: string) {
|
||||||
let elem = node;
|
let elem: AST | null = node;
|
||||||
while ((elem = elem.parent) && elem.tag !== elemName) {}
|
while ((elem = elem.parent) && elem.tag !== elemName) {}
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
@@ -346,9 +399,9 @@ const parseProps = {
|
|||||||
* @param {Object} document document element
|
* @param {Object} document document element
|
||||||
*
|
*
|
||||||
* @author strarsis <strarsis@gmail.com>
|
* @author strarsis <strarsis@gmail.com>
|
||||||
* @author modified by: msand <msand@abo.fim>
|
* @author modified by: msand <msand@abo.fi>
|
||||||
*/
|
*/
|
||||||
export function inlineStyles(document) {
|
export function inlineStyles(document: AST) {
|
||||||
// collect <style/>s
|
// collect <style/>s
|
||||||
const styleElements = querySelectorAll(document, 'style');
|
const styleElements = querySelectorAll(document, 'style');
|
||||||
|
|
||||||
@@ -357,7 +410,7 @@ export function inlineStyles(document) {
|
|||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectors = [];
|
const selectors: FlatSelectorList = [];
|
||||||
|
|
||||||
for (let element of styleElements) {
|
for (let element of styleElements) {
|
||||||
const { children } = element;
|
const { children } = element;
|
||||||
@@ -368,7 +421,8 @@ export function inlineStyles(document) {
|
|||||||
|
|
||||||
// collect <style/>s and their css ast
|
// collect <style/>s and their css ast
|
||||||
try {
|
try {
|
||||||
flattenToSelectors(csstree.parse(children, parseProps), selectors);
|
const styleString = children.join('');
|
||||||
|
flattenToSelectors(csstree.parse(styleString, parseProps), selectors);
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'Warning: Parse error of styles of <style/> element, skipped. Error details: ' +
|
'Warning: Parse error of styles of <style/> element, skipped. Error details: ' +
|
||||||
@@ -406,7 +460,8 @@ export function inlineStyles(document) {
|
|||||||
}
|
}
|
||||||
csstree.walk(rule, {
|
csstree.walk(rule, {
|
||||||
visit: 'Declaration',
|
visit: 'Declaration',
|
||||||
enter({ property, value, important }) {
|
enter(node: CssNode) {
|
||||||
|
const { property, value, important } = node as Declaration;
|
||||||
// existing inline styles have higher priority
|
// existing inline styles have higher priority
|
||||||
// no inline styles, external styles, external styles used
|
// no inline styles, external styles, external styles used
|
||||||
// inline styles, external styles same priority as inline styles, inline styles used
|
// inline styles, external styles same priority as inline styles, inline styles used
|
||||||
@@ -415,10 +470,10 @@ export function inlineStyles(document) {
|
|||||||
const camel = camelCase(name);
|
const camel = camelCase(name);
|
||||||
const val = csstree.generate(value).trim();
|
const val = csstree.generate(value).trim();
|
||||||
for (let element of matched) {
|
for (let element of matched) {
|
||||||
const { style, properties } = element.style;
|
const { style, properties } = element.style as CSSStyleDeclaration;
|
||||||
const current = properties.get(name);
|
const current = properties.get(name);
|
||||||
if (current === undefined || current < important) {
|
if (current === undefined || current < important) {
|
||||||
properties.set(name, important);
|
properties.set(name, important as boolean);
|
||||||
style[camel] = val;
|
style[camel] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -441,24 +496,18 @@ export function inlineStyles(document) {
|
|||||||
return document;
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SvgCss(props) {
|
export function SvgCss(props: XmlProps) {
|
||||||
const { xml, override } = props;
|
const { xml, override } = props;
|
||||||
const ast = useMemo(() => (xml !== null ? parse(xml, inlineStyles) : null), [
|
const ast = useMemo<AST | null>(
|
||||||
xml,
|
() => (xml !== null ? parse(xml, inlineStyles) : null),
|
||||||
]);
|
[xml],
|
||||||
|
);
|
||||||
return <SvgAst ast={ast} override={override || props} />;
|
return <SvgAst ast={ast} override={override || props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchText(uri) {
|
export function SvgCssUri(props: UriProps) {
|
||||||
const response = await fetch(uri);
|
|
||||||
return await response.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
const err = console.error.bind(console);
|
|
||||||
|
|
||||||
export function SvgCssUri(props) {
|
|
||||||
const { uri } = props;
|
const { uri } = props;
|
||||||
const [xml, setXml] = useState(null);
|
const [xml, setXml] = useState<string | null>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
uri
|
uri
|
||||||
? fetchText(uri)
|
? fetchText(uri)
|
||||||
+8
-5
@@ -61,10 +61,13 @@ function missingTag() {
|
|||||||
|
|
||||||
export interface AST {
|
export interface AST {
|
||||||
tag: string;
|
tag: string;
|
||||||
|
style?: unknown;
|
||||||
styles?: string;
|
styles?: string;
|
||||||
parent: AST | null;
|
parent: AST | null;
|
||||||
children: (AST | string)[] | (JSX.Element | string)[];
|
children: (AST | string)[] | (JSX.Element | string)[];
|
||||||
props: {};
|
props: {
|
||||||
|
[prop: string]: Styles | string | undefined;
|
||||||
|
};
|
||||||
Tag: ComponentType;
|
Tag: ComponentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,12 +99,12 @@ export function SvgXml(props: XmlProps) {
|
|||||||
return <SvgAst ast={ast} override={override || props} />;
|
return <SvgAst ast={ast} override={override || props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchText(uri: string) {
|
export async function fetchText(uri: string) {
|
||||||
const response = await fetch(uri);
|
const response = await fetch(uri);
|
||||||
return await response.text();
|
return await response.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
const err = console.error.bind(console);
|
export const err = console.error.bind(console);
|
||||||
|
|
||||||
export function SvgUri(props: UriProps) {
|
export function SvgUri(props: UriProps) {
|
||||||
const { uri } = props;
|
const { uri } = props;
|
||||||
@@ -177,7 +180,7 @@ const upperCase = (_match: string, letter: string) => letter.toUpperCase();
|
|||||||
export const camelCase = (phrase: string) =>
|
export const camelCase = (phrase: string) =>
|
||||||
phrase.replace(/[:\-]([a-z])/g, upperCase);
|
phrase.replace(/[:\-]([a-z])/g, upperCase);
|
||||||
|
|
||||||
type Styles = { [property: string]: string };
|
export type Styles = { [property: string]: string };
|
||||||
|
|
||||||
export function getStyle(string: string): Styles {
|
export function getStyle(string: string): Styles {
|
||||||
const style: Styles = {};
|
const style: Styles = {};
|
||||||
@@ -324,7 +327,7 @@ export function parse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tag = getName();
|
const tag = getName();
|
||||||
const props: { style?: Styles | string } = {};
|
const props: { [prop: string]: Styles | string | undefined } = {};
|
||||||
const element: AST = {
|
const element: AST = {
|
||||||
tag,
|
tag,
|
||||||
props,
|
props,
|
||||||
|
|||||||
Reference in New Issue
Block a user