@cyberalien/svg-utils 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/css/rules.d.ts +10 -0
- package/lib/css/rules.js +26 -0
- package/lib/css/stringify.d.ts +8 -2
- package/lib/css/stringify.js +16 -8
- package/lib/css/stylesheet.d.ts +0 -2
- package/lib/css/stylesheet.js +3 -3
- package/lib/css/types.d.ts +1 -1
- package/lib/helpers/reduce-motion.d.ts +2 -0
- package/lib/helpers/reduce-motion.js +3 -0
- package/lib/index.d.ts +10 -2
- package/lib/index.js +7 -2
- package/lib/svg-css/icon/css/basic.d.ts +13 -0
- package/lib/svg-css/icon/css/basic.js +26 -0
- package/lib/svg-css/icon/css/stateful.d.ts +14 -0
- package/lib/svg-css/icon/css/stateful.js +45 -0
- package/lib/svg-css/icon/types.d.ts +45 -0
- package/lib/svg-css/icon/types.js +1 -0
- package/lib/svg-css/states/cleanup-values.d.ts +6 -0
- package/lib/svg-css/states/cleanup-values.js +15 -0
- package/lib/svg-css/states/fallback/parse.d.ts +7 -0
- package/lib/svg-css/states/fallback/parse.js +46 -0
- package/lib/svg-css/states/fallback/stringify.d.ts +6 -0
- package/lib/svg-css/states/fallback/stringify.js +8 -0
- package/lib/svg-css/states/fallback/test.d.ts +9 -0
- package/lib/svg-css/states/fallback/test.js +21 -0
- package/lib/svg-css/states/fallback/types.d.ts +20 -0
- package/lib/svg-css/states/fallback/types.js +1 -0
- package/lib/svg-css/states/focus.d.ts +10 -0
- package/lib/svg-css/states/focus.js +14 -0
- package/lib/svg-css/states/generator.d.ts +19 -0
- package/lib/svg-css/states/generator.js +31 -0
- package/lib/svg-css/states/key.d.ts +6 -0
- package/lib/svg-css/states/key.js +22 -0
- package/lib/svg-css/states/object.d.ts +6 -0
- package/lib/svg-css/states/object.js +13 -0
- package/lib/svg-css/states/selector/helpers/iterate.d.ts +10 -0
- package/lib/svg-css/states/selector/helpers/iterate.js +71 -0
- package/lib/svg-css/states/selector/merge.d.ts +6 -0
- package/lib/svg-css/states/selector/merge.js +29 -0
- package/lib/svg-css/states/selector/parse.d.ts +13 -0
- package/lib/svg-css/states/selector/parse.js +74 -0
- package/lib/svg-css/states/selector/part/merge.d.ts +10 -0
- package/lib/svg-css/states/selector/part/merge.js +37 -0
- package/lib/svg-css/states/selector/part/split.d.ts +13 -0
- package/lib/svg-css/states/selector/part/split.js +60 -0
- package/lib/svg-css/states/selector/part/stringify.d.ts +9 -0
- package/lib/svg-css/states/selector/part/stringify.js +32 -0
- package/lib/svg-css/states/selector/split.d.ts +6 -0
- package/lib/svg-css/states/selector/split.js +29 -0
- package/lib/svg-css/states/selector/stringify.d.ts +8 -0
- package/lib/svg-css/states/selector/stringify.js +143 -0
- package/lib/svg-css/states/selector/sub/merge.d.ts +6 -0
- package/lib/svg-css/states/selector/sub/merge.js +36 -0
- package/lib/svg-css/states/selector/sub/split.d.ts +10 -0
- package/lib/svg-css/states/selector/sub/split.js +61 -0
- package/lib/svg-css/states/selector/sub/stringify.d.ts +6 -0
- package/lib/svg-css/states/selector/sub/stringify.js +17 -0
- package/lib/svg-css/states/selector/types.d.ts +37 -0
- package/lib/svg-css/states/selector/types.js +1 -0
- package/lib/svg-css/states/types.d.ts +9 -0
- package/lib/svg-css/states/types.js +1 -0
- package/lib/svg-css/states/value.d.ts +10 -0
- package/lib/svg-css/states/value.js +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CSSRules } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Split rules string into object
|
|
4
|
+
*/
|
|
5
|
+
declare function splitCSSRules(rules: CSSRules | string): CSSRules;
|
|
6
|
+
/**
|
|
7
|
+
* Merge rules
|
|
8
|
+
*/
|
|
9
|
+
declare function mergeCSSRules(rules: CSSRules | string, oldRules?: CSSRules | string): CSSRules;
|
|
10
|
+
export { mergeCSSRules, splitCSSRules };
|
package/lib/css/rules.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split rules string into object
|
|
3
|
+
*/
|
|
4
|
+
function splitCSSRules(rules) {
|
|
5
|
+
if (typeof rules === "string") {
|
|
6
|
+
const result = Object.create(null);
|
|
7
|
+
const parts = rules.split(";");
|
|
8
|
+
for (const part of parts) {
|
|
9
|
+
const [key, value] = part.split(":").map((s) => s.trim());
|
|
10
|
+
if (key && value) result[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
return rules;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Merge rules
|
|
18
|
+
*/
|
|
19
|
+
function mergeCSSRules(rules, oldRules) {
|
|
20
|
+
return {
|
|
21
|
+
...splitCSSRules(oldRules || {}),
|
|
22
|
+
...splitCSSRules(rules)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { mergeCSSRules, splitCSSRules };
|
package/lib/css/stringify.d.ts
CHANGED
|
@@ -7,8 +7,14 @@ declare function stringifyCSSRules(rules: CSSRules, depth?: number): string;
|
|
|
7
7
|
* Stringify CSS selector with rules
|
|
8
8
|
*/
|
|
9
9
|
declare function stringifyCSSSelector(selector: string, rules: string | CSSRules, depth?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Convert animation frames to CSS string
|
|
12
|
+
*
|
|
13
|
+
* Does not include @keyframes block, only the content
|
|
14
|
+
*/
|
|
15
|
+
declare function stringifyCSSAnimationFrames(keyframes: CSSKeyframes, depth?: number): string;
|
|
10
16
|
/**
|
|
11
17
|
* Stringify CSS keyframes
|
|
12
18
|
*/
|
|
13
|
-
declare function stringifyCSSKeyframes(animationName: string, keyframes: CSSKeyframes, depth?: number): string;
|
|
14
|
-
export { stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector };
|
|
19
|
+
declare function stringifyCSSKeyframes(animationName: string, keyframes: CSSKeyframes | string, depth?: number): string;
|
|
20
|
+
export { stringifyCSSAnimationFrames, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector };
|
package/lib/css/stringify.js
CHANGED
|
@@ -17,15 +17,18 @@ function stringifyCSSRules(rules, depth = 1) {
|
|
|
17
17
|
* Stringify CSS selector with rules
|
|
18
18
|
*/
|
|
19
19
|
function stringifyCSSSelector(selector, rules, depth = 0) {
|
|
20
|
-
const content = typeof rules === "string" ? rules : stringifyCSSRules(rules, depth + 1);
|
|
20
|
+
const content = typeof rules === "string" ? indent(depth + 1) + rules + "\n" : stringifyCSSRules(rules, depth + 1);
|
|
21
21
|
if (!content.length) return "";
|
|
22
22
|
const tab = indent(depth);
|
|
23
23
|
return `${tab}${selector} {\n${content}${tab}}\n`;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
26
|
+
* Convert animation frames to CSS string
|
|
27
|
+
*
|
|
28
|
+
* Does not include @keyframes block, only the content
|
|
27
29
|
*/
|
|
28
|
-
function
|
|
30
|
+
function stringifyCSSAnimationFrames(keyframes, depth = 0) {
|
|
31
|
+
const lines = [];
|
|
29
32
|
const prop = keyframes.prop;
|
|
30
33
|
const values = /* @__PURE__ */ new Map();
|
|
31
34
|
keyframes.frames.forEach((frame) => {
|
|
@@ -34,13 +37,18 @@ function stringifyCSSKeyframes(animationName, keyframes, depth = 0) {
|
|
|
34
37
|
if (item) item.push(frame.time);
|
|
35
38
|
else values.set(css, [frame.time]);
|
|
36
39
|
});
|
|
37
|
-
const lines = [];
|
|
38
|
-
lines.push(`${indent(depth)}@keyframes ${animationName} {\n`);
|
|
39
40
|
values.forEach((times, css) => {
|
|
40
41
|
lines.push(`${indent(depth + 1)}${times.map((time) => `${(time * 100).toFixed(2).replace(/\.?0+$/, "")}%`).join(", ")} {\n${css}${indent(depth + 1)}}\n`);
|
|
41
42
|
});
|
|
42
|
-
lines.
|
|
43
|
-
|
|
43
|
+
return lines.join("").trim();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Stringify CSS keyframes
|
|
47
|
+
*/
|
|
48
|
+
function stringifyCSSKeyframes(animationName, keyframes, depth = 0) {
|
|
49
|
+
const content = typeof keyframes === "string" ? keyframes : stringifyCSSAnimationFrames(keyframes, depth);
|
|
50
|
+
if (content.includes("@keyframes")) return content;
|
|
51
|
+
return `${indent(depth)}@keyframes ${animationName} {\n${indent(depth + 1)}${content}\n}\n`;
|
|
44
52
|
}
|
|
45
53
|
|
|
46
|
-
export { stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector };
|
|
54
|
+
export { stringifyCSSAnimationFrames, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector };
|
package/lib/css/stylesheet.d.ts
CHANGED
|
@@ -5,8 +5,6 @@ import { CSSGeneratedStylesheet, CSSRules } from "./types.js";
|
|
|
5
5
|
declare function createEmptyStylesheet(): CSSGeneratedStylesheet;
|
|
6
6
|
/**
|
|
7
7
|
* Add generated selector to stylesheet
|
|
8
|
-
*
|
|
9
|
-
* If item exists, it will be overwritten. Class names should be hashed to avoid conflicts, so this should not cause issues.
|
|
10
8
|
*/
|
|
11
9
|
declare function addGeneratedSelector(stylesheet: CSSGeneratedStylesheet, tree: string[], rules: CSSRules | string): void;
|
|
12
10
|
/**
|
package/lib/css/stylesheet.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { stringifyCSSKeyframes, stringifyCSSSelector } from "./stringify.js";
|
|
2
|
+
import { mergeCSSRules } from "./rules.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Create empty stylesheet
|
|
@@ -11,17 +12,16 @@ function createEmptyStylesheet() {
|
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* Add generated selector to stylesheet
|
|
14
|
-
*
|
|
15
|
-
* If item exists, it will be overwritten. Class names should be hashed to avoid conflicts, so this should not cause issues.
|
|
16
15
|
*/
|
|
17
16
|
function addGeneratedSelector(stylesheet, tree, rules) {
|
|
17
|
+
tree = tree.filter((item, index) => item.startsWith("@") ? tree.indexOf(item) === index : true);
|
|
18
18
|
let parent = stylesheet.selectors;
|
|
19
19
|
for (let i = 0; i < tree.length; i++) {
|
|
20
20
|
const selector = tree[i];
|
|
21
21
|
if (!parent[selector]) parent[selector] = {};
|
|
22
22
|
const parentItem = parent[selector];
|
|
23
23
|
if (i === tree.length - 1) {
|
|
24
|
-
parentItem.rules = rules;
|
|
24
|
+
parentItem.rules = mergeCSSRules(rules, parentItem.rules);
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
if (!parentItem.nested) parentItem.nested = Object.create(null);
|
package/lib/css/types.d.ts
CHANGED
|
@@ -28,6 +28,6 @@ interface CSSGeneratedSelector {
|
|
|
28
28
|
type CSSGeneratedSelectors = Record<string, CSSGeneratedSelector>;
|
|
29
29
|
interface CSSGeneratedStylesheet {
|
|
30
30
|
selectors: CSSGeneratedSelectors;
|
|
31
|
-
keyframes: Record<string, CSSKeyframes>;
|
|
31
|
+
keyframes: Record<string, CSSKeyframes | string>;
|
|
32
32
|
}
|
|
33
33
|
export { CSSGeneratedSelector, CSSGeneratedSelectors, CSSGeneratedStylesheet, CSSHashOptions, CSSKeyframe, CSSKeyframes, CSSRules };
|
package/lib/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { CSSGeneratedSelector, CSSGeneratedSelectors, CSSGeneratedStylesheet, CS
|
|
|
5
5
|
import { ParsedXMLNode, ParsedXMLTagElement, ParsedXMLTextElement, StringifyXMLOptions } from "./xml/types.js";
|
|
6
6
|
import { BaseConvertSVGContentOptions, ConvertSVGContentOptions, ConvertedSVGContent } from "./svg-css/types.js";
|
|
7
7
|
import { createCSSClassName } from "./css/hash.js";
|
|
8
|
-
import {
|
|
8
|
+
import { mergeCSSRules, splitCSSRules } from "./css/rules.js";
|
|
9
|
+
import { stringifyCSSAnimationFrames, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector } from "./css/stringify.js";
|
|
9
10
|
import { addGeneratedSelector, createEmptyStylesheet, stringifyStylesheet } from "./css/stylesheet.js";
|
|
10
11
|
import { createUniqueHashContext } from "./helpers/hash/context.js";
|
|
11
12
|
import { hashString } from "./helpers/hash/hash.js";
|
|
@@ -27,4 +28,11 @@ import { changeSVGIDs } from "./svg/ids/change.js";
|
|
|
27
28
|
import { createUniqueIDs } from "./svg/ids/unique.js";
|
|
28
29
|
import { convertSVGRootToCSS } from "./svg-css/root.js";
|
|
29
30
|
import { convertSVGContentToCSSRules } from "./svg-css/content.js";
|
|
30
|
-
|
|
31
|
+
import { IconFallbackAdvancedState, IconFallbackBooleanState, IconFallbackTemplate } from "./svg-css/states/fallback/types.js";
|
|
32
|
+
import { getIconFallback } from "./svg-css/states/fallback/stringify.js";
|
|
33
|
+
import { IconStatesAdvancedState, IconStatesAdvancedStateValues, IconStatesList, IconStatesSimpleState, IconStatesState } from "./svg-css/states/types.js";
|
|
34
|
+
import { getStatesFromKey } from "./svg-css/states/key.js";
|
|
35
|
+
import { getObjectFromStates } from "./svg-css/states/object.js";
|
|
36
|
+
import { getAdvancedStateDefaultValue, getStateValue } from "./svg-css/states/value.js";
|
|
37
|
+
import { SVGCSSIcon, SVGCSSIconRules, SVGCSSStatefulIcon, SVGCSSStatefulIconRules } from "./svg-css/icon/types.js";
|
|
38
|
+
export { BaseConvertSVGContentOptions, CSSGeneratedSelector, CSSGeneratedSelectors, CSSGeneratedStylesheet, CSSHashOptions, CSSKeyframe, CSSKeyframes, CSSRules, ChangeIDResult, ClassProp, ComparisonKey, ConvertSVGContentOptions, ConvertedSVGContent, HashContext, IconFallbackAdvancedState, IconFallbackBooleanState, IconFallbackTemplate, IconStatesAdvancedState, IconStatesAdvancedStateValues, IconStatesList, IconStatesSimpleState, IconStatesState, ParsedXMLNode, ParsedXMLTagElement, ParsedXMLTextElement, SVGCSSIcon, SVGCSSIconRules, SVGCSSStatefulIcon, SVGCSSStatefulIconRules, StringifyXMLOptions, UniqueHashOptions, UniqueHashPartialOptions, UniqueIDOptions, addGeneratedSelector, changeIDInString, changeSVGIDs, classProps, cloneObject, compareKeys, compareSets, compareValues, convertSVGContentToCSSRules, convertSVGRootToCSS, createCSSClassName, createEmptyStylesheet, createUniqueHashContext, createUniqueIDs, defaultClassProp, getAdvancedStateDefaultValue, getIconFallback, getObjectFromStates, getStateValue, getStatesFromKey, getUniqueHash, hashString, hashToString, iterateXMLContent, mergeCSSRules, parseXMLContent, removeDuplicateIDs, removeUnusedIDs, sortObject, splitCSSRules, splitClassName, stringifyCSSAnimationFrames, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector, stringifyStylesheet, stringifyXMLContent, toggleClassName, uniquePromise };
|
package/lib/index.js
CHANGED
|
@@ -11,7 +11,8 @@ import { iterateXMLContent } from "./xml/iterate.js";
|
|
|
11
11
|
import { parseXMLContent } from "./xml/parse.js";
|
|
12
12
|
import { stringifyXMLContent } from "./xml/stringify.js";
|
|
13
13
|
import { createCSSClassName } from "./css/hash.js";
|
|
14
|
-
import { stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector } from "./css/stringify.js";
|
|
14
|
+
import { stringifyCSSAnimationFrames, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector } from "./css/stringify.js";
|
|
15
|
+
import { mergeCSSRules, splitCSSRules } from "./css/rules.js";
|
|
15
16
|
import { addGeneratedSelector, createEmptyStylesheet, stringifyStylesheet } from "./css/stylesheet.js";
|
|
16
17
|
import { classProps, defaultClassProp } from "./classname/const.js";
|
|
17
18
|
import { splitClassName, toggleClassName } from "./classname/toggle.js";
|
|
@@ -22,5 +23,9 @@ import { changeSVGIDs } from "./svg/ids/change.js";
|
|
|
22
23
|
import { createUniqueIDs } from "./svg/ids/unique.js";
|
|
23
24
|
import { convertSVGRootToCSS } from "./svg-css/root.js";
|
|
24
25
|
import { convertSVGContentToCSSRules } from "./svg-css/content.js";
|
|
26
|
+
import { getIconFallback } from "./svg-css/states/fallback/stringify.js";
|
|
27
|
+
import { getStatesFromKey } from "./svg-css/states/key.js";
|
|
28
|
+
import { getAdvancedStateDefaultValue, getStateValue } from "./svg-css/states/value.js";
|
|
29
|
+
import { getObjectFromStates } from "./svg-css/states/object.js";
|
|
25
30
|
|
|
26
|
-
export { addGeneratedSelector, changeIDInString, changeSVGIDs, classProps, cloneObject, compareKeys, compareSets, compareValues, convertSVGContentToCSSRules, convertSVGRootToCSS, createCSSClassName, createEmptyStylesheet, createUniqueHashContext, createUniqueIDs, defaultClassProp, getUniqueHash, hashString, hashToString, iterateXMLContent, parseXMLContent, removeDuplicateIDs, removeUnusedIDs, sortObject, splitClassName, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector, stringifyStylesheet, stringifyXMLContent, toggleClassName, uniquePromise };
|
|
31
|
+
export { addGeneratedSelector, changeIDInString, changeSVGIDs, classProps, cloneObject, compareKeys, compareSets, compareValues, convertSVGContentToCSSRules, convertSVGRootToCSS, createCSSClassName, createEmptyStylesheet, createUniqueHashContext, createUniqueIDs, defaultClassProp, getAdvancedStateDefaultValue, getIconFallback, getObjectFromStates, getStateValue, getStatesFromKey, getUniqueHash, hashString, hashToString, iterateXMLContent, mergeCSSRules, parseXMLContent, removeDuplicateIDs, removeUnusedIDs, sortObject, splitCSSRules, splitClassName, stringifyCSSAnimationFrames, stringifyCSSKeyframes, stringifyCSSRules, stringifyCSSSelector, stringifyStylesheet, stringifyXMLContent, toggleClassName, uniquePromise };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CSSGeneratedStylesheet } from "../../../css/types.js";
|
|
2
|
+
import { SVGCSSIcon } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Add styles for icon to stylesheet
|
|
5
|
+
*
|
|
6
|
+
* If commonStylesheet is an object, all styles will be added to it and result
|
|
7
|
+
* will contain the same stylesheet for all classes.
|
|
8
|
+
*
|
|
9
|
+
* If commonStylesheet is not an object, styles will be separated into different
|
|
10
|
+
* stylesheets for classes and keyframes, which can be reused across icons.
|
|
11
|
+
*/
|
|
12
|
+
declare function renderSVGCSSIconStyle(icon: SVGCSSIcon, commonStylesheet?: CSSGeneratedStylesheet | ((selector: string) => CSSGeneratedStylesheet)): Record<string, CSSGeneratedStylesheet>;
|
|
13
|
+
export { renderSVGCSSIconStyle };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { addGeneratedSelector, createEmptyStylesheet } from "../../../css/stylesheet.js";
|
|
2
|
+
import { prefersReduceMotion } from "../../../helpers/reduce-motion.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Add styles for icon to stylesheet
|
|
6
|
+
*
|
|
7
|
+
* If commonStylesheet is an object, all styles will be added to it and result
|
|
8
|
+
* will contain the same stylesheet for all classes.
|
|
9
|
+
*
|
|
10
|
+
* If commonStylesheet is not an object, styles will be separated into different
|
|
11
|
+
* stylesheets for classes and keyframes, which can be reused across icons.
|
|
12
|
+
*/
|
|
13
|
+
function renderSVGCSSIconStyle(icon, commonStylesheet = createEmptyStylesheet) {
|
|
14
|
+
const stylesheets = Object.create(null);
|
|
15
|
+
const getStylesheet = (className) => {
|
|
16
|
+
if (typeof commonStylesheet === "object") return commonStylesheet;
|
|
17
|
+
if (!stylesheets[className]) stylesheets[className] = commonStylesheet(className);
|
|
18
|
+
return stylesheets[className];
|
|
19
|
+
};
|
|
20
|
+
for (const className in icon.classes) addGeneratedSelector(getStylesheet(className), [`.${className}`], icon.classes[className]);
|
|
21
|
+
for (const className in icon.animations) addGeneratedSelector(getStylesheet(className), [prefersReduceMotion, `.${className}`], icon.animations[className]);
|
|
22
|
+
for (const keyframeName in icon.keyframes) getStylesheet(keyframeName).keyframes[keyframeName] = icon.keyframes[keyframeName];
|
|
23
|
+
return stylesheets;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { renderSVGCSSIconStyle };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CSSGeneratedStylesheet } from "../../../css/types.js";
|
|
2
|
+
import { SVGCSSStatefulIcon } from "../types.js";
|
|
3
|
+
import { StatefulIconSelectorsContext } from "../../states/selector/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Add styles for stateful icon to stylesheet
|
|
6
|
+
*
|
|
7
|
+
* If commonStylesheet is an object, all styles will be added to it and result
|
|
8
|
+
* will contain the same stylesheet for all classes.
|
|
9
|
+
*
|
|
10
|
+
* If commonStylesheet is not an object, styles will be separated into different
|
|
11
|
+
* stylesheets for classes and keyframes, which can be reused across icons.
|
|
12
|
+
*/
|
|
13
|
+
declare function renderStatefulSVGCSSIconStyle(icon: SVGCSSStatefulIcon, context: StatefulIconSelectorsContext, commonStylesheet?: CSSGeneratedStylesheet | ((selector: string) => CSSGeneratedStylesheet)): Record<string, CSSGeneratedStylesheet>;
|
|
14
|
+
export { renderStatefulSVGCSSIconStyle };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { addGeneratedSelector, createEmptyStylesheet } from "../../../css/stylesheet.js";
|
|
2
|
+
import { prefersReduceMotion } from "../../../helpers/reduce-motion.js";
|
|
3
|
+
import { getSelectorsForStateValues } from "../../states/selector/parse.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Add styles for stateful icon to stylesheet
|
|
7
|
+
*
|
|
8
|
+
* If commonStylesheet is an object, all styles will be added to it and result
|
|
9
|
+
* will contain the same stylesheet for all classes.
|
|
10
|
+
*
|
|
11
|
+
* If commonStylesheet is not an object, styles will be separated into different
|
|
12
|
+
* stylesheets for classes and keyframes, which can be reused across icons.
|
|
13
|
+
*/
|
|
14
|
+
function renderStatefulSVGCSSIconStyle(icon, context, commonStylesheet = createEmptyStylesheet) {
|
|
15
|
+
const stylesheets = Object.create(null);
|
|
16
|
+
const getStylesheet = (className) => {
|
|
17
|
+
if (typeof commonStylesheet === "object") return commonStylesheet;
|
|
18
|
+
if (!stylesheets[className]) stylesheets[className] = commonStylesheet(className);
|
|
19
|
+
return stylesheets[className];
|
|
20
|
+
};
|
|
21
|
+
for (const className in icon.classes) addGeneratedSelector(getStylesheet(className), [`.${className}`], icon.classes[className]);
|
|
22
|
+
for (const className in icon.animations) addGeneratedSelector(getStylesheet(className), [prefersReduceMotion, `.${className}`], icon.animations[className]);
|
|
23
|
+
for (const keyframeName in icon.keyframes) getStylesheet(keyframeName).keyframes[keyframeName] = icon.keyframes[keyframeName];
|
|
24
|
+
for (const className in icon.statefulClasses) {
|
|
25
|
+
const baseClassName = `.${className}`;
|
|
26
|
+
const stylesheet = getStylesheet(className);
|
|
27
|
+
const classData = icon.statefulClasses[className];
|
|
28
|
+
if (classData.transition) addGeneratedSelector(getStylesheet(className), [prefersReduceMotion, baseClassName], classData.transition);
|
|
29
|
+
for (const stateKey in classData.stateRules) {
|
|
30
|
+
const selectors = getSelectorsForStateValues(context, stateKey);
|
|
31
|
+
if (selectors) for (const tree of selectors) addGeneratedSelector(stylesheet, [...tree, baseClassName], classData.stateRules[stateKey]);
|
|
32
|
+
}
|
|
33
|
+
for (const stateKey in classData.stateTransition) {
|
|
34
|
+
const selectors = getSelectorsForStateValues(context, stateKey);
|
|
35
|
+
if (selectors) for (const tree of selectors) addGeneratedSelector(stylesheet, [
|
|
36
|
+
prefersReduceMotion,
|
|
37
|
+
...tree,
|
|
38
|
+
baseClassName
|
|
39
|
+
], classData.stateTransition[stateKey]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return stylesheets;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { renderStatefulSVGCSSIconStyle };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { IconViewBox } from "../../svg/viewbox/types.js";
|
|
2
|
+
import { CSSKeyframes, CSSRules } from "../../css/types.js";
|
|
3
|
+
import { IconStatesList } from "../states/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Main properties
|
|
6
|
+
*/
|
|
7
|
+
interface MainProps {
|
|
8
|
+
viewBox: IconViewBox | string;
|
|
9
|
+
fallback?: string;
|
|
10
|
+
content: string;
|
|
11
|
+
}
|
|
12
|
+
interface StatefulMainProps extends MainProps {
|
|
13
|
+
states: IconStatesList;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* CSS data
|
|
17
|
+
*/
|
|
18
|
+
interface SVGCSSIconRules {
|
|
19
|
+
classes?: Record<string, CSSRules | string>;
|
|
20
|
+
animations?: Record<string, CSSRules | string>;
|
|
21
|
+
keyframes?: Record<string, CSSKeyframes | string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Extended class interface for stateful icons
|
|
25
|
+
*/
|
|
26
|
+
interface ExtendedSVGCSSIconClass {
|
|
27
|
+
stateRules?: Record<string, CSSRules | string>;
|
|
28
|
+
transition?: CSSRules | string;
|
|
29
|
+
stateTransition?: Record<string, CSSRules | string>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Stateful CSS data
|
|
33
|
+
*/
|
|
34
|
+
interface SVGCSSStatefulIconRules extends SVGCSSIconRules {
|
|
35
|
+
statefulClasses?: Record<string, ExtendedSVGCSSIconClass>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Icon data
|
|
39
|
+
*/
|
|
40
|
+
interface SVGCSSIcon extends MainProps, SVGCSSIconRules {}
|
|
41
|
+
/**
|
|
42
|
+
* Icon with states
|
|
43
|
+
*/
|
|
44
|
+
interface SVGCSSStatefulIcon extends StatefulMainProps, SVGCSSStatefulIconRules {}
|
|
45
|
+
export { SVGCSSIcon, SVGCSSIconRules, SVGCSSStatefulIcon, SVGCSSStatefulIconRules };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IconStatesList } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Clean up state values object
|
|
4
|
+
*/
|
|
5
|
+
declare function cleanupStateValues(states: IconStatesList, values: Record<string, boolean | string>, clone?: boolean): Record<string, string | boolean>;
|
|
6
|
+
export { cleanupStateValues };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getStateValue } from "./value.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Clean up state values object
|
|
5
|
+
*/
|
|
6
|
+
function cleanupStateValues(states, values, clone = false) {
|
|
7
|
+
const result = clone ? { ...values } : values;
|
|
8
|
+
for (const state of states) {
|
|
9
|
+
const stateName = typeof state === "string" ? state : state[0];
|
|
10
|
+
result[stateName] = getStateValue(state, result[stateName]);
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { cleanupStateValues };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IconFallbackTemplate } from "./types.js";
|
|
2
|
+
import { IconStatesList } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parse fallback template string into array of strings and states
|
|
5
|
+
*/
|
|
6
|
+
declare function parseIconFallbackTemplate(fallback: string, states: IconStatesList): IconFallbackTemplate | undefined;
|
|
7
|
+
export { parseIconFallbackTemplate };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function unwrap(value) {
|
|
2
|
+
if (value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Parse fallback template string into array of strings and states
|
|
7
|
+
*/
|
|
8
|
+
function parseIconFallbackTemplate(fallback, states) {
|
|
9
|
+
const chunks = [];
|
|
10
|
+
let startIndex = 0;
|
|
11
|
+
for (const match of fallback.matchAll(/{[^}]+}/g)) {
|
|
12
|
+
const matchText = match[0];
|
|
13
|
+
const matchIndex = match.index || 0;
|
|
14
|
+
if (matchIndex > startIndex) {
|
|
15
|
+
const prev = fallback.slice(startIndex, matchIndex);
|
|
16
|
+
if (prev) chunks.push(prev);
|
|
17
|
+
}
|
|
18
|
+
startIndex = matchIndex + matchText.length;
|
|
19
|
+
const textMatches = Array.from(matchText.matchAll(/[a-z0-9:'-]+/g));
|
|
20
|
+
if (!textMatches.length) return;
|
|
21
|
+
const separators = Array.from(matchText.matchAll(/[^a-z0-9:'-]/g));
|
|
22
|
+
if (separators.length !== textMatches.length + 1) return;
|
|
23
|
+
const stateName = textMatches[0][0].trim();
|
|
24
|
+
const state = states.find((s) => typeof s === "string" ? s === stateName : s[0] === stateName);
|
|
25
|
+
if (!state) return;
|
|
26
|
+
if (typeof state === "string") {
|
|
27
|
+
if (textMatches.length !== 3) return;
|
|
28
|
+
const trueValue = textMatches[1][0];
|
|
29
|
+
const falseValue = textMatches[2][0];
|
|
30
|
+
const firstSeparator = separators[1][0];
|
|
31
|
+
const secondSeparator = separators[2][0];
|
|
32
|
+
if (firstSeparator !== "?" || secondSeparator !== "|") return;
|
|
33
|
+
chunks.push({
|
|
34
|
+
state,
|
|
35
|
+
values: [unwrap(falseValue), unwrap(trueValue)]
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
if (textMatches.length > 1) return;
|
|
39
|
+
chunks.push({ state: stateName });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (startIndex < fallback.length) chunks.push(fallback.slice(startIndex));
|
|
43
|
+
return chunks;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { parseIconFallbackTemplate };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate fallback string from template and states
|
|
3
|
+
*/
|
|
4
|
+
function getIconFallback(template, values) {
|
|
5
|
+
return template.map((chunk) => typeof chunk === "string" ? chunk : "values" in chunk ? chunk.values[+!!values[chunk.state]] : values[chunk.state]).join("");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { getIconFallback };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IconFallbackTemplate } from "./types.js";
|
|
2
|
+
import { IconStatesList } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parse and test fallback template string
|
|
5
|
+
*
|
|
6
|
+
* This will make sure template is valid and does not contain invalid characters
|
|
7
|
+
*/
|
|
8
|
+
declare function parseAndTestIconFallbackTemplate(fallback: string, states: IconStatesList): IconFallbackTemplate | undefined;
|
|
9
|
+
export { parseAndTestIconFallbackTemplate };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { parseIconFallbackTemplate } from "./parse.js";
|
|
2
|
+
|
|
3
|
+
const match = /^[a-z0-9:-]*$/;
|
|
4
|
+
/**
|
|
5
|
+
* Parse and test fallback template string
|
|
6
|
+
*
|
|
7
|
+
* This will make sure template is valid and does not contain invalid characters
|
|
8
|
+
*/
|
|
9
|
+
function parseAndTestIconFallbackTemplate(fallback, states) {
|
|
10
|
+
const template = parseIconFallbackTemplate(fallback, states);
|
|
11
|
+
if (template) {
|
|
12
|
+
for (const chunk of template) if (typeof chunk === "string") {
|
|
13
|
+
if (!chunk.match(match)) return;
|
|
14
|
+
} else if ("values" in chunk) {
|
|
15
|
+
if (!chunk.values.every((v) => v.match(match))) return;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return template;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { parseAndTestIconFallbackTemplate };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback replacement for boolean state
|
|
3
|
+
*/
|
|
4
|
+
interface IconFallbackBooleanState {
|
|
5
|
+
state: string;
|
|
6
|
+
values: [string, string];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Fallback for named state
|
|
10
|
+
*
|
|
11
|
+
* Value should match state values
|
|
12
|
+
*/
|
|
13
|
+
interface IconFallbackAdvancedState {
|
|
14
|
+
state: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Template for fallback: mix of strings and states
|
|
18
|
+
*/
|
|
19
|
+
type IconFallbackTemplate = (string | IconFallbackBooleanState | IconFallbackAdvancedState)[];
|
|
20
|
+
export { IconFallbackAdvancedState, IconFallbackBooleanState, IconFallbackTemplate };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { IconStatesList, IconStatesState } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Check for focus state
|
|
4
|
+
*/
|
|
5
|
+
declare function isFocusState(state: IconStatesState | string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Filter out focus state from states list
|
|
8
|
+
*/
|
|
9
|
+
declare function filterFocusState(states: IconStatesList): IconStatesList;
|
|
10
|
+
export { filterFocusState, isFocusState };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check for focus state
|
|
3
|
+
*/
|
|
4
|
+
function isFocusState(state) {
|
|
5
|
+
return state === "focus";
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Filter out focus state from states list
|
|
9
|
+
*/
|
|
10
|
+
function filterFocusState(states) {
|
|
11
|
+
return states.filter((state) => !isFocusState(state));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { filterFocusState, isFocusState };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IconStatesList, IconStatesState } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate code for object from states
|
|
4
|
+
*
|
|
5
|
+
* Does not include starting { and ending }
|
|
6
|
+
* Last entry does not have a comma at the end
|
|
7
|
+
*/
|
|
8
|
+
declare function generateObjectFromStates(states: IconStatesList): string;
|
|
9
|
+
/**
|
|
10
|
+
* Generate code for TypeScript interface from state
|
|
11
|
+
*/
|
|
12
|
+
declare function getStateInterface(state: IconStatesState, optional?: boolean): string;
|
|
13
|
+
/**
|
|
14
|
+
* Generate code for TypeScript interface from states
|
|
15
|
+
*
|
|
16
|
+
* Does not include starting { and ending }
|
|
17
|
+
*/
|
|
18
|
+
declare function generateInterfaceFromStates(states: IconStatesList, optional?: boolean): string;
|
|
19
|
+
export { generateInterfaceFromStates, generateObjectFromStates, getStateInterface };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getAdvancedStateDefaultValue } from "./value.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate code for object from states
|
|
5
|
+
*
|
|
6
|
+
* Does not include starting { and ending }
|
|
7
|
+
* Last entry does not have a comma at the end
|
|
8
|
+
*/
|
|
9
|
+
function generateObjectFromStates(states) {
|
|
10
|
+
const lines = [];
|
|
11
|
+
for (const state of states) if (typeof state === "string") lines.push(`'${state}': false`);
|
|
12
|
+
else lines.push(`'${state[0]}': '${getAdvancedStateDefaultValue(state)}'`);
|
|
13
|
+
return lines.join(",\n ");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate code for TypeScript interface from state
|
|
17
|
+
*/
|
|
18
|
+
function getStateInterface(state, optional = true) {
|
|
19
|
+
const q = optional ? "?" : "";
|
|
20
|
+
return typeof state === "string" ? `'${state}'${q}: boolean;` : `'${state[0]}'${q}: ${state[1].map((value) => `'${value}'`).join(" | ")};`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generate code for TypeScript interface from states
|
|
24
|
+
*
|
|
25
|
+
* Does not include starting { and ending }
|
|
26
|
+
*/
|
|
27
|
+
function generateInterfaceFromStates(states, optional = true) {
|
|
28
|
+
return states.map((state) => getStateInterface(state, optional)).join("\n ");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { generateInterfaceFromStates, generateObjectFromStates, getStateInterface };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get state values from an underscore separated list of state values
|
|
3
|
+
*/
|
|
4
|
+
function getStatesFromKey(key, states) {
|
|
5
|
+
const obj = Object.create(null);
|
|
6
|
+
const parts = key.split("_");
|
|
7
|
+
for (const state of states) {
|
|
8
|
+
if (typeof state === "string") {
|
|
9
|
+
if (parts.includes(state)) obj[state] = true;
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const values = state[1];
|
|
13
|
+
const defaultValue = state[2] || values[0];
|
|
14
|
+
for (const value of values) if (value !== defaultValue && parts.includes(value)) {
|
|
15
|
+
obj[state[0]] = value;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { getStatesFromKey };
|