完成世界书、骰子、apiconfig页面处理

This commit is contained in:
2026-04-30 01:35:10 +08:00
parent a3e3711b2b
commit ba9b925c32
4602 changed files with 785225 additions and 23 deletions

View File

@@ -0,0 +1,44 @@
interface RGBColor {
type: 'rgb';
r: number;
g: number;
b: number;
alpha: number;
}
interface HSLColor {
type: 'hsl';
h: number;
s: number;
l: number;
alpha: number;
}
interface LABColor {
type: 'lab';
l: number;
a: number;
b: number;
alpha: number;
}
interface LCHColor {
type: 'lch';
l: number;
c: number;
h: number;
alpha: number;
}
interface FunctionColor {
type: 'function';
func: string;
value: string;
}
interface TransparentColor {
type: 'transparent';
}
interface NoColor {
type: 'none';
}
interface CurrentColor {
type: 'current';
}
type Color = RGBColor | HSLColor | LABColor | LCHColor | FunctionColor | TransparentColor | NoColor | CurrentColor;
export { Color, CurrentColor, FunctionColor, HSLColor, LABColor, LCHColor, NoColor, RGBColor, TransparentColor };

View File

@@ -0,0 +1 @@
export { };

40
frontend/node_modules/@iconify/utils/lib/css/format.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
const format = {
selectorStart: {
compressed: "{",
compact: " {",
expanded: " {"
},
selectorEnd: {
compressed: "}",
compact: "; }\n",
expanded: ";\n}\n"
},
rule: {
compressed: "{key}:",
compact: " {key}: ",
expanded: "\n {key}: "
}
};
/**
* Format data
*
* Key is selector, value is list of rules
*/
function formatCSS(data, mode = "expanded") {
const results = [];
for (let i = 0; i < data.length; i++) {
const { selector, rules } = data[i];
let entry = (selector instanceof Array ? selector.join(mode === "compressed" ? "," : ", ") : selector) + format.selectorStart[mode];
let firstRule = true;
for (const key in rules) {
if (!firstRule) entry += ";";
entry += format.rule[mode].replace("{key}", key) + rules[key];
firstRule = false;
}
entry += format.selectorEnd[mode];
results.push(entry);
}
return results.join(mode === "compressed" ? "" : "\n");
}
export { formatCSS };

View File

@@ -0,0 +1,5 @@
/**
* Get boolean customisation value from attribute
*/
declare function toBoolean(name: string, value: unknown, defaultValue: boolean): boolean;
export { toBoolean };

View File

@@ -0,0 +1,18 @@
const separator = /[\s,]+/;
/**
* Apply "flip" string to icon customisations
*/
function flipFromString(custom, flip) {
flip.split(separator).forEach((str) => {
switch (str.trim()) {
case "horizontal":
custom.hFlip = true;
break;
case "vertical":
custom.vFlip = true;
break;
}
});
}
export { flipFromString };

View File

@@ -0,0 +1,31 @@
/**
* Get rotation value
*/
function rotateFromString(value, defaultValue = 0) {
const units = value.replace(/^-?[0-9.]*/, "");
function cleanup(value$1) {
while (value$1 < 0) value$1 += 4;
return value$1 % 4;
}
if (units === "") {
const num = parseInt(value);
return isNaN(num) ? 0 : cleanup(num);
} else if (units !== value) {
let split = 0;
switch (units) {
case "%":
split = 25;
break;
case "deg": split = 90;
}
if (split) {
let num = parseFloat(value.slice(0, value.length - units.length));
if (isNaN(num)) return 0;
num = num / split;
return num % 1 === 0 ? cleanup(num) : 0;
}
}
return defaultValue;
}
export { rotateFromString };

View File

@@ -0,0 +1,32 @@
/** Joiner in emoji sequences */
declare const joinerEmoji = 8205;
/** Emoji as icon */
declare const vs16Emoji = 65039;
/** Keycap, preceeded by mandatory VS16 for full emoji */
declare const keycapEmoji = 8419;
/**
* Variations, UTF-32
*
* First value in array is minimum, second value is maximum+1
*/
type EmojiComponentType = 'skin-tone' | 'hair-style';
type Range = [number, number];
declare const emojiComponents: Record<EmojiComponentType, Range>;
/**
* Minimum UTF-32 number
*/
declare const minUTF32 = 65536;
/**
* Codes for UTF-32 characters presented as UTF-16
*
* startUTF32Pair1 <= code < startUTF32Pair2 -> code for first character in pair
* startUTF32Pair2 <= code < endUTF32Pair -> code for second character in pair
*/
declare const startUTF32Pair1 = 55296;
declare const startUTF32Pair2 = 56320;
declare const endUTF32Pair = 57344;
/**
* Emoji version as string
*/
declare const emojiVersion = "17.0";
export { EmojiComponentType, emojiComponents, emojiVersion, endUTF32Pair, joinerEmoji, keycapEmoji, minUTF32, startUTF32Pair1, startUTF32Pair2, vs16Emoji };

View File

@@ -0,0 +1,32 @@
import { IconifyJSON } from "@iconify/types";
/** Parsed icon */
interface PreparedEmojiIcon {
/** Icon name */
icon: string;
/** Emoji sequence as string */
sequence: string;
}
/**
* Parse
*/
interface PreparedEmojiResult {
/** List of icons */
icons: PreparedEmojiIcon[];
/** Regular expression */
regex: string;
}
/**
* Prepare emoji for icons list
*
* Test data should be fetched from 'https://unicode.org/Public/emoji/17.0/emoji-test.txt'
* It is used to detect missing emojis and optimise regular expression
*/
declare function prepareEmojiForIconsList(icons: Record<string, string>, rawTestData?: string): PreparedEmojiResult;
/**
* Prepare emoji for an icon set
*
* Test data should be fetched from 'https://unicode.org/Public/emoji/15.1/emoji-test.txt'
* It is used to detect missing emojis and optimise regular expression
*/
declare function prepareEmojiForIconSet(iconSet: IconifyJSON, rawTestData?: string): PreparedEmojiResult;
export { PreparedEmojiIcon, PreparedEmojiResult, prepareEmojiForIconSet, prepareEmojiForIconsList };

View File

@@ -0,0 +1,74 @@
/**
* Regex in item
*/
interface BaseEmojiItemRegex {
type: 'utf16' | 'sequence' | 'set' | 'optional';
regex: string;
group: boolean;
length: number;
}
interface EmojiItemRegexWithNumbers {
numbers?: number[];
}
interface UTF16EmojiItemRegex extends BaseEmojiItemRegex, Required<EmojiItemRegexWithNumbers> {
type: 'utf16';
group: true;
}
type SequenceEmojiItemRegexItem = UTF16EmojiItemRegex | SetEmojiItemRegex | OptionalEmojiItemRegex;
interface SequenceEmojiItemRegex extends BaseEmojiItemRegex, EmojiItemRegexWithNumbers {
type: 'sequence';
items: SequenceEmojiItemRegexItem[];
}
type SetEmojiItemRegexItem = UTF16EmojiItemRegex | SequenceEmojiItemRegex | OptionalEmojiItemRegex;
interface SetEmojiItemRegex extends BaseEmojiItemRegex, EmojiItemRegexWithNumbers {
type: 'set';
sets: SetEmojiItemRegexItem[];
}
type OptionalEmojiItemRegexItem = UTF16EmojiItemRegex | SequenceEmojiItemRegex | SetEmojiItemRegex;
interface OptionalEmojiItemRegex extends BaseEmojiItemRegex {
type: 'optional';
item: OptionalEmojiItemRegexItem;
group: true;
}
type EmojiItemRegex = UTF16EmojiItemRegex | SequenceEmojiItemRegex | SetEmojiItemRegex | OptionalEmojiItemRegex;
/**
* Wrap regex in group
*/
declare function wrapRegexInGroup(regex: string): string;
/**
* Update UTF16 item, return regex
*/
declare function updateUTF16EmojiRegexItem(item: UTF16EmojiItemRegex): string;
/**
* Create UTF-16 regex
*/
declare function createUTF16EmojiRegexItem(numbers: number[]): UTF16EmojiItemRegex;
/**
* Update sequence regex. Does not update group
*/
declare function updateSequenceEmojiRegexItem(item: SequenceEmojiItemRegex): string;
/**
* Create sequence regex
*/
declare function createSequenceEmojiRegexItem(sequence: EmojiItemRegex[], numbers?: number[]): SequenceEmojiItemRegex;
/**
* Update set regex and group
*/
declare function updateSetEmojiRegexItem(item: SetEmojiItemRegex): string;
/**
* Create set regex
*/
declare function createSetEmojiRegexItem(set: EmojiItemRegex[]): SetEmojiItemRegex;
/**
* Update optional regex
*/
declare function updateOptionalEmojiRegexItem(item: OptionalEmojiItemRegex): string;
/**
* Create optional item
*/
declare function createOptionalEmojiRegexItem(item: EmojiItemRegex): OptionalEmojiItemRegex;
/**
* Clone item
*/
declare function cloneEmojiRegexItem<T extends BaseEmojiItemRegex>(item: T, shallow?: boolean): T;
export { EmojiItemRegex, OptionalEmojiItemRegex, SequenceEmojiItemRegex, SetEmojiItemRegex, SetEmojiItemRegexItem, UTF16EmojiItemRegex, cloneEmojiRegexItem, createOptionalEmojiRegexItem, createSequenceEmojiRegexItem, createSetEmojiRegexItem, createUTF16EmojiRegexItem, updateOptionalEmojiRegexItem, updateSequenceEmojiRegexItem, updateSetEmojiRegexItem, updateUTF16EmojiRegexItem, wrapRegexInGroup };

View File

@@ -0,0 +1,204 @@
/**
* Convert number to string
*/
function toString(number) {
if (number < 255) {
if (number > 32 && number < 127) {
const char = String.fromCharCode(number);
if (number > 47 && number < 58 || number > 64 && number < 91 || number > 94 && number < 123) return char;
return "\\" + char;
}
return "\\x" + (number < 16 ? "0" : "") + number.toString(16).toUpperCase();
}
return "\\u" + number.toString(16).toUpperCase();
}
/**
* Typescript stuff
*/
function assertNever(v) {}
/**
* Wrap regex in group
*/
function wrapRegexInGroup(regex) {
return "(?:" + regex + ")";
}
/**
* Update UTF16 item, return regex
*/
function updateUTF16EmojiRegexItem(item) {
const numbers = item.numbers;
if (numbers.length === 1) {
const num = numbers[0];
return item.regex = toString(num);
}
numbers.sort((a, b) => a - b);
const chars = [];
let range = null;
const addRange = () => {
if (range) {
const { start, last, numbers: numbers$1 } = range;
range = null;
if (last > start + 1) chars.push(toString(start) + "-" + toString(last));
else for (let i = 0; i < numbers$1.length; i++) chars.push(toString(numbers$1[i]));
}
};
for (let i = 0; i < numbers.length; i++) {
const num = numbers[i];
if (range) {
if (range.last === num) continue;
if (range.last === num - 1) {
range.numbers.push(num);
range.last = num;
continue;
}
}
addRange();
range = {
start: num,
last: num,
numbers: [num]
};
}
addRange();
if (!chars.length) throw new Error("Unexpected empty range");
return item.regex = "[" + chars.join("") + "]";
}
/**
* Create UTF-16 regex
*/
function createUTF16EmojiRegexItem(numbers) {
const result = {
type: "utf16",
regex: "",
numbers,
length: 1,
group: true
};
updateUTF16EmojiRegexItem(result);
return result;
}
/**
* Update sequence regex. Does not update group
*/
function updateSequenceEmojiRegexItem(item) {
return item.regex = item.items.map((childItem) => {
if (!childItem.group && childItem.type === "set") return wrapRegexInGroup(childItem.regex);
return childItem.regex;
}).join("");
}
/**
* Create sequence regex
*/
function createSequenceEmojiRegexItem(sequence, numbers) {
let items = [];
sequence.forEach((item) => {
if (item.type === "sequence") items = items.concat(item.items);
else items.push(item);
});
if (!items.length) throw new Error("Empty sequence");
const result = {
type: "sequence",
items,
regex: "",
length: items.reduce((length, item) => item.length + length, 0),
group: false
};
if (sequence.length === 1) {
const firstItem = sequence[0];
result.group = firstItem.group;
if (firstItem.type !== "optional") {
const numbers$1 = firstItem.numbers;
if (numbers$1) result.numbers = numbers$1;
}
}
if (numbers) result.numbers = numbers;
updateSequenceEmojiRegexItem(result);
return result;
}
/**
* Update set regex and group
*/
function updateSetEmojiRegexItem(item) {
if (item.sets.length === 1) {
const firstItem = item.sets[0];
item.group = firstItem.group;
return item.regex = firstItem.regex;
}
item.group = false;
return item.regex = item.sets.map((childItem) => childItem.regex).join("|");
}
/**
* Create set regex
*/
function createSetEmojiRegexItem(set) {
let sets = [];
let numbers = [];
set.forEach((item) => {
if (item.type === "set") sets = sets.concat(item.sets);
else sets.push(item);
if (numbers) if (item.type === "optional" || !item.numbers) numbers = null;
else numbers = [...numbers, ...item.numbers];
});
sets.sort((a, b) => {
if (a.length === b.length) return a.regex.localeCompare(b.regex);
return b.length - a.length;
});
const result = {
type: "set",
sets,
regex: "",
length: sets.reduce((length, item) => length ? Math.min(length, item.length) : item.length, 0),
group: false
};
if (numbers) result.numbers = numbers;
if (set.length === 1) result.group = set[0].group;
updateSetEmojiRegexItem(result);
return result;
}
/**
* Update optional regex
*/
function updateOptionalEmojiRegexItem(item) {
const childItem = item.item;
return item.regex = (childItem.group ? childItem.regex : wrapRegexInGroup(childItem.regex)) + "?";
}
/**
* Create optional item
*/
function createOptionalEmojiRegexItem(item) {
if (item.type === "optional") return item;
const result = {
type: "optional",
item,
regex: "",
length: item.length,
group: true
};
updateOptionalEmojiRegexItem(result);
return result;
}
/**
* Clone item
*/
function cloneEmojiRegexItem(item, shallow = false) {
const result = { ...item };
if (result.type !== "optional" && result.numbers) result.numbers = [...result.numbers];
switch (result.type) {
case "utf16": break;
case "sequence":
if (shallow) result.items = [...result.items];
else result.items = result.items.map((item$1) => cloneEmojiRegexItem(item$1, false));
break;
case "set":
if (shallow) result.sets = [...result.sets];
else result.sets = result.sets.map((item$1) => cloneEmojiRegexItem(item$1, false));
break;
case "optional":
if (!shallow) result.item = cloneEmojiRegexItem(result.item, false);
break;
default: assertNever(result);
}
return result;
}
export { cloneEmojiRegexItem, createOptionalEmojiRegexItem, createSequenceEmojiRegexItem, createSetEmojiRegexItem, createUTF16EmojiRegexItem, updateOptionalEmojiRegexItem, updateSequenceEmojiRegexItem, updateSetEmojiRegexItem, updateUTF16EmojiRegexItem, wrapRegexInGroup };

View File

@@ -0,0 +1,20 @@
/**
* Create optimised regex
*/
declare function createOptimisedRegexForEmojiSequences(sequences: number[][]): string;
/**
* Create optimised regex for emojis
*
* First parameter is array of emojis, entry can be either list of
* code points or emoji sequence as a string
*
* Examples of acceptable strings (case insensitive):
* '1F636 200D 1F32B FE0F' - space separated UTF32 sequence
* '1f636-200d-1f32b-fe0f' - dash separated UTF32 sequence
* 'd83d-de36-200d-d83c-df2b-fe0f' - dash separated UTF16 sequence
* '\\uD83D\\uDE36\\u200D\\uD83C\\uDF2B\\uFE0F' - UTF16 sequence escaped with '\\u'
*
* All examples above refer to the same emoji and will generate the same regex result
*/
declare function createOptimisedRegex(emojis: (string | number[])[]): string;
export { createOptimisedRegex, createOptimisedRegexForEmojiSequences };

View File

@@ -0,0 +1,14 @@
import { EmojiItemRegex, OptionalEmojiItemRegex, SequenceEmojiItemRegex, SetEmojiItemRegex, UTF16EmojiItemRegex } from "./base.js";
/**
* Create regex item for set of numbers
*/
declare function createEmojiRegexItemForNumbers(numbers: number[]): UTF16EmojiItemRegex | SequenceEmojiItemRegex | SetEmojiItemRegex;
/**
* Create sequence of numbers
*/
declare function createRegexForNumbersSequence(numbers: number[], optionalVariations?: boolean): SequenceEmojiItemRegex | UTF16EmojiItemRegex | OptionalEmojiItemRegex;
/**
* Attempt to optimise numbers in a set
*/
declare function optimiseNumbersSet(set: SetEmojiItemRegex): EmojiItemRegex;
export { createEmojiRegexItemForNumbers, createRegexForNumbersSequence, optimiseNumbersSet };

View File

@@ -0,0 +1,18 @@
import { EmojiItemRegex } from "./base.js";
/**
* Tree item
*/
interface TreeItem {
regex: EmojiItemRegex;
end?: true;
children?: TreeItem[];
}
/**
* Create tree
*/
declare function createEmojisTree(sequences: number[][]): TreeItem[];
/**
* Parse tree
*/
declare function parseEmojiTree(items: TreeItem[]): EmojiItemRegex;
export { createEmojisTree, parseEmojiTree };

View File

@@ -0,0 +1,81 @@
import { joinerEmoji } from "../data.js";
import { convertEmojiSequenceToUTF32 } from "../convert.js";
import { splitEmojiSequences } from "../cleanup.js";
import { createOptionalEmojiRegexItem, createSequenceEmojiRegexItem, createSetEmojiRegexItem, createUTF16EmojiRegexItem } from "./base.js";
import { createRegexForNumbersSequence } from "./numbers.js";
import { mergeSimilarItemsInSet } from "./similar.js";
/**
* Create tree
*/
function createEmojisTree(sequences) {
const root = [];
for (let i = 0; i < sequences.length; i++) {
const split = splitEmojiSequences(convertEmojiSequenceToUTF32(sequences[i]));
let parent = root;
for (let j = 0; j < split.length; j++) {
const regex = createRegexForNumbersSequence(split[j]);
let item;
const match = parent.find((item$1) => item$1.regex.regex === regex.regex);
if (!match) {
item = { regex };
parent.push(item);
} else item = match;
if (j === split.length - 1) {
item.end = true;
break;
}
parent = item.children || (item.children = []);
}
}
return root;
}
/**
* Parse tree
*/
function parseEmojiTree(items) {
function mergeParsedChildren(items$1) {
const parsedItems = [];
const mapWithoutEnd = Object.create(null);
const mapWithEnd = Object.create(null);
for (let i = 0; i < items$1.length; i++) {
const item = items$1[i];
const children = item.children;
if (children) {
const fullItem = item;
const target = item.end ? mapWithEnd : mapWithoutEnd;
const regex = children.regex;
if (!target[regex]) target[regex] = [fullItem];
else target[regex].push(fullItem);
} else parsedItems.push(item.regex);
}
[mapWithEnd, mapWithoutEnd].forEach((source) => {
for (const regex in source) {
const items$2 = source[regex];
const firstItem = items$2[0];
let childSequence = [createUTF16EmojiRegexItem([joinerEmoji]), firstItem.children];
if (firstItem.end) childSequence = [createOptionalEmojiRegexItem(createSequenceEmojiRegexItem(childSequence))];
let mergedRegex;
if (items$2.length === 1) mergedRegex = firstItem.regex;
else mergedRegex = mergeSimilarItemsInSet(createSetEmojiRegexItem(items$2.map((item) => item.regex)));
const sequence = createSequenceEmojiRegexItem([mergedRegex, ...childSequence]);
parsedItems.push(sequence);
}
});
if (parsedItems.length === 1) return parsedItems[0];
return mergeSimilarItemsInSet(createSetEmojiRegexItem(parsedItems));
}
function parseItemChildren(item) {
const result = {
regex: item.regex,
end: !!item.end
};
const children = item.children;
if (!children) return result;
result.children = mergeParsedChildren(children.map(parseItemChildren));
return result;
}
return mergeParsedChildren(items.map(parseItemChildren));
}
export { createEmojisTree, parseEmojiTree };

View File

@@ -0,0 +1,14 @@
import { EmojiRegexMatch } from "./find.js";
/**
* Callback for replacing emoji in text
*
* Returns text to replace emoji with, undefined to skip replacement
*/
type FindAndReplaceEmojisInTextCallback = (match: EmojiRegexMatch, prev: string) => string | undefined;
/**
* Find and replace emojis in text
*
* Returns null if nothing was replaced
*/
declare function findAndReplaceEmojisInText(regexp: string | RegExp | (string | RegExp)[], content: string, callback: FindAndReplaceEmojisInTextCallback): string | null;
export { FindAndReplaceEmojisInTextCallback, findAndReplaceEmojisInText };

View File

@@ -0,0 +1,41 @@
import { EmojiComponentType } from "../data.js";
import { EmojiTestData, EmojiTestDataItem } from "./parse.js";
interface EmojiTestDataComponentsMap {
converted: Map<number, string>;
items: Map<string | number, EmojiTestDataItem>;
names: Map<string | number, string>;
types: Record<string, EmojiComponentType>;
keywords: Record<string, string>;
}
/**
* Map components from test data
*/
declare function mapEmojiTestDataComponents(testSequences: EmojiTestData): EmojiTestDataComponentsMap;
/**
* Sequence with components
*/
type EmojiSequenceWithComponents = (EmojiComponentType | number)[];
/**
* Convert to string
*/
declare function emojiSequenceWithComponentsToString(sequence: EmojiSequenceWithComponents): string;
/**
* Entry in sequence
*/
interface EmojiSequenceComponentEntry {
index: number;
type: EmojiComponentType;
}
/**
* Find variations in sequence
*/
declare function findEmojiComponentsInSequence(sequence: number[]): EmojiSequenceComponentEntry[];
/**
* Component values
*/
type EmojiSequenceComponentValues = Partial<Record<EmojiComponentType, number[]>>;
/**
* Replace components in sequence
*/
declare function replaceEmojiComponentsInCombinedSequence(sequence: EmojiSequenceWithComponents, values: EmojiSequenceComponentValues): number[];
export { EmojiSequenceComponentEntry, EmojiSequenceComponentValues, EmojiSequenceWithComponents, EmojiTestDataComponentsMap, emojiSequenceWithComponentsToString, findEmojiComponentsInSequence, mapEmojiTestDataComponents, replaceEmojiComponentsInCombinedSequence };

View File

@@ -0,0 +1,21 @@
import { BaseEmojiTestDataItem, EmojiTestData, EmojiTestDataItem } from "./parse.js";
import { EmojiSequenceWithComponents, EmojiTestDataComponentsMap } from "./components.js";
import { SplitEmojiName } from "./name.js";
/**
* Similar test data items as one item
*/
interface CombinedEmojiTestDataItem extends BaseEmojiTestDataItem {
name: SplitEmojiName;
sequenceKey: string;
sequence: EmojiSequenceWithComponents;
}
type SimilarEmojiTestData = Record<string, CombinedEmojiTestDataItem>;
/**
* Find components in item, generate CombinedEmojiTestDataItem
*/
declare function findComponentsInEmojiTestItem(item: EmojiTestDataItem, componentsData: EmojiTestDataComponentsMap): CombinedEmojiTestDataItem;
/**
* Combine similar items in one iteratable item
*/
declare function combineSimilarEmojiTestData(data: EmojiTestData, componentsData?: EmojiTestDataComponentsMap): SimilarEmojiTestData;
export { CombinedEmojiTestDataItem, SimilarEmojiTestData, combineSimilarEmojiTestData, findComponentsInEmojiTestItem };

View File

@@ -0,0 +1,26 @@
import { IconifyInfo } from "@iconify/types";
/**
* Item provided by API or loaded from collections.json, slightly different from IconifyInfo
*/
interface LegacyIconifyInfo {
name: string;
total?: number;
version?: string;
author?: string;
url?: string;
license?: string;
licenseURL?: string;
licenseSPDX?: string;
samples?: string[];
height?: number | number[];
displayHeight?: number;
samplesHeight?: number;
category?: string;
palette?: 'Colorless' | 'Colorful';
hidden?: boolean;
}
/**
* Convert data to valid CollectionInfo
*/
declare function convertIconSetInfo(data: unknown, expectedPrefix?: string): IconifyInfo | null;
export { LegacyIconifyInfo, convertIconSetInfo };

View File

@@ -0,0 +1,126 @@
const minDisplayHeight = 16;
const maxDisplayHeight = 24;
/**
* Check if displayHeight value is valid, returns 0 on failure
*/
function validateDisplayHeight(value) {
while (value < minDisplayHeight) value *= 2;
while (value > maxDisplayHeight) value /= 2;
return value === Math.round(value) && value >= minDisplayHeight && value <= maxDisplayHeight ? value : 0;
}
/**
* Convert data to valid CollectionInfo
*/
function convertIconSetInfo(data, expectedPrefix = "") {
if (typeof data !== "object" || data === null) return null;
const source = data;
const getSourceNestedString = (field, key, defaultValue = "") => {
if (typeof source[field] !== "object") return defaultValue;
const obj = source[field];
return typeof obj[key] === "string" ? obj[key] : defaultValue;
};
let name;
if (typeof source.name === "string") name = source.name;
else if (typeof source.title === "string") name = source.title;
else return null;
if (expectedPrefix !== "" && typeof source.prefix === "string" && source.prefix !== expectedPrefix) return null;
const info = { name };
switch (typeof source.total) {
case "number":
info.total = source.total;
break;
case "string": {
const num = parseInt(source.total);
if (num > 0) info.total = num;
break;
}
}
if (typeof source.version === "string") info.version = source.version;
info.author = { name: getSourceNestedString("author", "name", typeof source.author === "string" ? source.author : "") };
if (typeof source.author === "object") {
const sourceAuthor = source.author;
if (typeof sourceAuthor.url === "string") info.author.url = sourceAuthor.url;
}
info.license = { title: getSourceNestedString("license", "title", typeof source.license === "string" ? source.license : "") };
if (typeof source.license === "object") {
const sourceLicense = source.license;
if (typeof sourceLicense.spdx === "string") info.license.spdx = sourceLicense.spdx;
if (typeof sourceLicense.url === "string") info.license.url = sourceLicense.url;
}
if (source.samples instanceof Array) {
const samples = [];
source.samples.forEach((item) => {
if (typeof item === "string" && !samples.includes(item)) samples.push(item);
});
if (samples.length) info.samples = samples;
}
if (typeof source.height === "number" || typeof source.height === "string") {
const num = parseInt(source.height);
if (num > 0) info.height = num;
}
if (source.height instanceof Array) {
source.height.forEach((item) => {
const num = parseInt(item);
if (num > 0) {
if (!(info.height instanceof Array)) info.height = [];
info.height.push(num);
}
});
switch (info.height.length) {
case 0:
delete info.height;
break;
case 1: info.height = info.height[0];
}
}
if (typeof info.height === "number") {
const displayHeight = validateDisplayHeight(info.height);
if (displayHeight && displayHeight !== info.height) info.displayHeight = displayHeight;
}
["samplesHeight", "displayHeight"].forEach((prop) => {
const value = source[prop];
if (typeof value === "number" || typeof value === "string") {
const displayHeight = validateDisplayHeight(parseInt(value));
if (displayHeight) info.displayHeight = displayHeight;
}
});
if (typeof source.category === "string") info.category = source.category;
if (source.tags instanceof Array) info.tags = source.tags;
switch (typeof source.palette) {
case "boolean":
info.palette = source.palette;
break;
case "string":
switch (source.palette.toLowerCase()) {
case "colorless":
case "false":
info.palette = false;
break;
case "colorful":
case "true": info.palette = true;
}
break;
}
if (source.hidden === true) info.hidden = true;
Object.keys(source).forEach((key) => {
const value = source[key];
if (typeof value !== "string") return;
switch (key) {
case "url":
case "uri":
info.author.url = value;
break;
case "licenseURL":
case "licenseURI":
info.license.url = value;
break;
case "licenseID":
case "licenseSPDX":
info.license.spdx = value;
break;
}
});
return info;
}
export { convertIconSetInfo };

View File

@@ -0,0 +1,8 @@
import { IconifyJSON } from "@iconify/types";
/**
* Expand minified icon set
*
* Opposite of minifyIconSet() from ./minify.ts
*/
declare function expandIconSet(data: IconifyJSON): void;
export { expandIconSet };

View File

@@ -0,0 +1,10 @@
import { ExtendedIconifyIcon, IconifyJSON } from "@iconify/types";
/**
* Get icon data, using prepared aliases tree
*/
declare function internalGetIconData(data: IconifyJSON, name: string, tree: string[]): ExtendedIconifyIcon;
/**
* Get data for icon
*/
declare function getIconData(data: IconifyJSON, name: string): ExtendedIconifyIcon | null;
export { getIconData, internalGetIconData };

View File

@@ -0,0 +1,38 @@
import { defaultIconDimensions } from "../icon/defaults.js";
import { getIconsTree } from "./tree.js";
/**
* Optional properties that must be copied when copying icon set
*/
const propsToCopy = Object.keys(defaultIconDimensions).concat(["provider"]);
/**
* Extract icons from icon set
*/
function getIcons(data, names, not_found) {
const icons = Object.create(null);
const aliases = Object.create(null);
const result = {
prefix: data.prefix,
icons
};
const sourceIcons = data.icons;
const sourceAliases = data.aliases || Object.create(null);
if (data.lastModified) result.lastModified = data.lastModified;
const tree = getIconsTree(data, names);
let empty = true;
for (const name in tree) if (!tree[name]) {
if (not_found && names.indexOf(name) !== -1) (result.not_found || (result.not_found = [])).push(name);
} else if (sourceIcons[name]) {
icons[name] = { ...sourceIcons[name] };
empty = false;
} else {
aliases[name] = { ...sourceAliases[name] };
result.aliases = aliases;
}
propsToCopy.forEach((attr) => {
if (attr in data) result[attr] = data[attr];
});
return empty && not_found !== true ? null : result;
}
export { getIcons, propsToCopy };

View File

@@ -0,0 +1,43 @@
import { IconifyJSON } from "@iconify/types";
/**
* Minify icon set
*
* Function finds common values for few numeric properties, such as 'width' and 'height' (see defaultIconDimensions keys for list of properties),
* removes entries from icons and sets default entry in root of icon set object.
*
* For example, this:
* {
* icons: {
* foo: {
* body: '<g />',
* width: 24
* },
* bar: {
* body: '<g />',
* width: 24
* },
* baz: {
* body: '<g />',
* width: 16
* }
* }
* }
* is changed to this:
* {
* icons: {
* foo: {
* body: '<g />'
* },
* bar: {
* body: '<g />'
* },
* baz: {
* body: '<g />',
* width: 16
* }
* },
* width: 24
* }
*/
declare function minifyIconSet(data: IconifyJSON): void;
export { minifyIconSet };

View File

@@ -0,0 +1,19 @@
import { ExtendedIconifyIcon, IconifyJSON } from "@iconify/types";
/**
* Callback to call for each icon.
*
* If data === null, icon is missing.
*/
type SplitIconSetCallback = (name: string, data: ExtendedIconifyIcon | null) => unknown;
type SplitIconSetAsyncCallback = (name: string, data: ExtendedIconifyIcon | null) => Promise<unknown>;
/**
* Extract icons from an icon set
*
* Returns list of icons that were found in icon set
*/
declare function parseIconSet(data: IconifyJSON, callback: SplitIconSetCallback): string[];
/**
* Async version of parseIconSet()
*/
declare function parseIconSetAsync(data: IconifyJSON, callback: SplitIconSetAsyncCallback): Promise<string[]>;
export { SplitIconSetAsyncCallback, SplitIconSetCallback, parseIconSet, parseIconSetAsync };

View File

@@ -0,0 +1,48 @@
import { getIconsTree } from "./tree.js";
import { internalGetIconData } from "./get-icon.js";
/**
* Extract icons from an icon set
*
* Returns list of icons that were found in icon set
*/
function parseIconSet(data, callback) {
const names = [];
if (typeof data !== "object" || typeof data.icons !== "object") return names;
if (data.not_found instanceof Array) data.not_found.forEach((name) => {
callback(name, null);
names.push(name);
});
const tree = getIconsTree(data);
for (const name in tree) {
const item = tree[name];
if (item) {
callback(name, internalGetIconData(data, name, item));
names.push(name);
}
}
return names;
}
/**
* Async version of parseIconSet()
*/
async function parseIconSetAsync(data, callback) {
const names = [];
if (typeof data !== "object" || typeof data.icons !== "object") return names;
if (data.not_found instanceof Array) for (let i = 0; i < data.not_found.length; i++) {
const name = data.not_found[i];
await callback(name, null);
names.push(name);
}
const tree = getIconsTree(data);
for (const name in tree) {
const item = tree[name];
if (item) {
await callback(name, internalGetIconData(data, name, item));
names.push(name);
}
}
return names;
}
export { parseIconSet, parseIconSetAsync };

View File

@@ -0,0 +1,26 @@
/** Default values for dimensions */
const defaultIconDimensions = Object.freeze({
left: 0,
top: 0,
width: 16,
height: 16
});
/** Default values for transformations */
const defaultIconTransformations = Object.freeze({
rotate: 0,
vFlip: false,
hFlip: false
});
/** Default values for all optional IconifyIcon properties */
const defaultIconProps = Object.freeze({
...defaultIconDimensions,
...defaultIconTransformations
});
/** Default values for all properties used in ExtendedIconifyIcon */
const defaultExtendedIconProps = Object.freeze({
...defaultIconProps,
body: "",
hidden: false
});
export { defaultExtendedIconProps, defaultIconDimensions, defaultIconProps, defaultIconTransformations };

18
frontend/node_modules/@iconify/utils/lib/icon/merge.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
import { defaultExtendedIconProps, defaultIconTransformations } from "./defaults.js";
import { mergeIconTransformations } from "./transformations.js";
/**
* Merge icon and alias
*
* Can also be used to merge default values and icon
*/
function mergeIconData(parent, child) {
const result = mergeIconTransformations(parent, child);
for (const key in defaultExtendedIconProps) if (key in defaultIconTransformations) {
if (key in parent && !(key in result)) result[key] = defaultIconTransformations[key];
} else if (key in child) result[key] = child[key];
else if (key in parent) result[key] = parent[key];
return result;
}
export { mergeIconData };

View File

@@ -0,0 +1,11 @@
import { SVGViewBox } from "../svg/viewbox.js";
import { IconifyIcon } from "@iconify/types";
/**
* Make icon square
*/
declare function makeIconSquare(icon: Required<IconifyIcon>): Required<IconifyIcon>;
/**
* Make icon viewBox square
*/
declare function makeViewBoxSquare(viewBox: SVGViewBox): SVGViewBox;
export { makeIconSquare, makeViewBoxSquare };

View File

@@ -0,0 +1,34 @@
/**
* Make icon square
*/
function makeIconSquare(icon) {
if (icon.width !== icon.height) {
const max = Math.max(icon.width, icon.height);
return {
...icon,
width: max,
height: max,
left: icon.left - (max - icon.width) / 2,
top: icon.top - (max - icon.height) / 2
};
}
return icon;
}
/**
* Make icon viewBox square
*/
function makeViewBoxSquare(viewBox) {
const [left, top, width, height] = viewBox;
if (width !== height) {
const max = Math.max(width, height);
return [
left - (max - width) / 2,
top - (max - height) / 2,
max,
max
];
}
return viewBox;
}
export { makeIconSquare, makeViewBoxSquare };

53
frontend/node_modules/@iconify/utils/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
import { defaultExtendedIconProps, defaultIconDimensions, defaultIconProps, defaultIconTransformations } from "./icon/defaults.js";
import { defaultIconCustomisations, defaultIconSizeCustomisations } from "./customisations/defaults.js";
import { mergeCustomisations } from "./customisations/merge.js";
import { toBoolean } from "./customisations/bool.js";
import { flipFromString } from "./customisations/flip.js";
import { rotateFromString } from "./customisations/rotate.js";
import { matchIconName, stringToIcon, validateIconName } from "./icon/name.js";
import { mergeIconTransformations } from "./icon/transformations.js";
import { mergeIconData } from "./icon/merge.js";
import { makeIconSquare } from "./icon/square.js";
import { getIconsTree } from "./icon-set/tree.js";
import { getIconData } from "./icon-set/get-icon.js";
import { parseIconSet, parseIconSetAsync } from "./icon-set/parse.js";
import { validateIconSet } from "./icon-set/validate.js";
import { quicklyValidateIconSet } from "./icon-set/validate-basic.js";
import { expandIconSet } from "./icon-set/expand.js";
import { minifyIconSet } from "./icon-set/minify.js";
import { getIcons } from "./icon-set/get-icons.js";
import { convertIconSetInfo } from "./icon-set/convert-info.js";
import { calculateSize } from "./svg/size.js";
import { mergeDefsAndContent, splitSVGDefs, wrapSVGContent } from "./svg/defs.js";
import { iconToSVG } from "./svg/build.js";
import { clearIDCache, replaceIDs } from "./svg/id.js";
import { svgToData, svgToURL } from "./svg/url.js";
import { encodeSvgForCss } from "./svg/encode-svg-for-css.js";
import { trimSVG } from "./svg/trim.js";
import { prettifySVG } from "./svg/pretty.js";
import { iconToHTML } from "./svg/html.js";
import { cleanUpInnerHTML } from "./svg/inner-html.js";
import { getSVGViewBox } from "./svg/viewbox.js";
import { buildParsedSVG, convertParsedSVG, parseSVGContent } from "./svg/parse.js";
import { colorKeywords } from "./colors/keywords.js";
import { colorToString, compareColors, stringToColor } from "./colors/index.js";
import { getIconCSS, getIconContentCSS } from "./css/icon.js";
import { getIconsCSS, getIconsContentCSS } from "./css/icons.js";
import { mergeIconProps } from "./loader/utils.js";
import { getCustomIcon } from "./loader/custom.js";
import { searchForIcon } from "./loader/modern.js";
import { loadIcon } from "./loader/loader.js";
import { convertEmojiSequenceToUTF16, convertEmojiSequenceToUTF32, getEmojiCodePoint, getEmojiUnicode, isUTF32SplitNumber, mergeUTF32Numbers, splitUTF32Number } from "./emoji/convert.js";
import { getEmojiSequenceFromString, getUnqualifiedEmojiSequence } from "./emoji/cleanup.js";
import { getEmojiSequenceKeyword, getEmojiSequenceString, getEmojiUnicodeString } from "./emoji/format.js";
import { parseEmojiTestFile } from "./emoji/test/parse.js";
import { getQualifiedEmojiVariations } from "./emoji/test/variations.js";
import { findMissingEmojis } from "./emoji/test/missing.js";
import { createOptimisedRegex, createOptimisedRegexForEmojiSequences } from "./emoji/regex/create.js";
import { prepareEmojiForIconSet, prepareEmojiForIconsList } from "./emoji/parse.js";
import { findAndReplaceEmojisInText } from "./emoji/replace/replace.js";
import { camelToKebab, camelize, pascalize, snakelize } from "./misc/strings.js";
import { commonObjectProps, compareObjects, unmergeObjects } from "./misc/objects.js";
import { sanitiseTitleAttribute } from "./misc/title.js";
export { buildParsedSVG, calculateSize, camelToKebab, camelize, cleanUpInnerHTML, clearIDCache, colorKeywords, colorToString, commonObjectProps, compareColors, compareObjects, convertEmojiSequenceToUTF16, convertEmojiSequenceToUTF32, convertIconSetInfo, convertParsedSVG, createOptimisedRegex, createOptimisedRegexForEmojiSequences, defaultExtendedIconProps, defaultIconCustomisations, defaultIconDimensions, defaultIconProps, defaultIconSizeCustomisations, defaultIconTransformations, encodeSvgForCss, expandIconSet, findAndReplaceEmojisInText, findMissingEmojis, flipFromString, getCustomIcon, getEmojiCodePoint, getEmojiSequenceFromString, getEmojiSequenceKeyword, getEmojiSequenceString, getEmojiUnicode, getEmojiUnicodeString, getIconCSS, getIconContentCSS, getIconData, getIcons, getIconsCSS, getIconsContentCSS, getIconsTree, getQualifiedEmojiVariations, getSVGViewBox, getUnqualifiedEmojiSequence, iconToHTML, iconToSVG, isUTF32SplitNumber, loadIcon, makeIconSquare, matchIconName, mergeCustomisations, mergeDefsAndContent, mergeIconData, mergeIconProps, mergeIconTransformations, mergeUTF32Numbers, minifyIconSet, parseEmojiTestFile, parseIconSet, parseIconSetAsync, parseSVGContent, pascalize, prepareEmojiForIconSet, prepareEmojiForIconsList, prettifySVG, quicklyValidateIconSet, replaceIDs, rotateFromString, sanitiseTitleAttribute, searchForIcon, snakelize, splitSVGDefs, splitUTF32Number, stringToColor, stringToIcon, svgToData, svgToURL, toBoolean, trimSVG, unmergeObjects, validateIconName, validateIconSet, wrapSVGContent };

View File

@@ -0,0 +1,6 @@
import { CustomIconLoader, IconifyLoaderOptions, InlineCollection } from "./types.js";
/**
* Get custom icon from inline collection or using loader
*/
declare function getCustomIcon(custom: CustomIconLoader | InlineCollection, collection: string, icon: string, options?: IconifyLoaderOptions): Promise<string | undefined>;
export { getCustomIcon };

View File

@@ -0,0 +1,32 @@
import { trimSVG } from "../svg/trim.js";
import { mergeIconProps } from "./utils.js";
/**
* Get custom icon from inline collection or using loader
*/
async function getCustomIcon(custom, collection, icon, options) {
let result;
try {
if (typeof custom === "function") result = await custom(icon);
else {
const inline = custom[icon];
result = typeof inline === "function" ? await inline() : inline;
}
} catch (err) {
console.warn(`Failed to load custom icon "${icon}" in "${collection}":`, err);
return;
}
if (result) {
const cleanupIdx = result.indexOf("<svg");
if (cleanupIdx > 0) result = result.slice(cleanupIdx);
const { transform } = options?.customizations ?? {};
result = typeof transform === "function" ? await transform(result, collection, icon) : result;
if (!result.startsWith("<svg")) {
console.warn(`Custom icon "${icon}" in "${collection}" is not a valid SVG`);
return result;
}
return await mergeIconProps(options?.customizations?.trimCustomSvg === true ? trimSVG(result) : result, collection, icon, options, void 0);
}
}
export { getCustomIcon };

View File

@@ -0,0 +1,28 @@
import { warnOnce } from "./warn.js";
import { installPackage } from "@antfu/install-pkg";
import { styleText } from "node:util";
let pending;
const tasks = {};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function tryInstallPkg(name, autoInstall) {
if (pending) await pending;
if (!tasks[name]) {
console.log(styleText("cyan", `Installing ${name}...`));
if (typeof autoInstall === "function") tasks[name] = pending = autoInstall(name).then(() => sleep(300)).finally(() => {
pending = void 0;
});
else tasks[name] = pending = installPackage(name, {
dev: true,
preferOffline: true
}).then(() => sleep(300)).catch((e) => {
warnOnce(`Failed to install ${name}`);
console.error(e);
}).finally(() => {
pending = void 0;
});
}
return tasks[name];
}
export { tryInstallPkg };

View File

@@ -0,0 +1,3 @@
import { UniversalIconLoader } from "./types.js";
declare const loadIcon: UniversalIconLoader;
export { loadIcon };

View File

@@ -0,0 +1,28 @@
import { getCustomIcon } from "./custom.js";
import { searchForIcon } from "./modern.js";
const loadIcon = async (collection, icon, options) => {
const custom = options?.customCollections?.[collection];
if (custom) if (typeof custom === "function") {
let result;
try {
result = await custom(icon);
} catch (err) {
console.warn(`Failed to load custom icon "${icon}" in "${collection}":`, err);
return;
}
if (result) {
if (typeof result === "string") return await getCustomIcon(() => result, collection, icon, options);
if ("icons" in result) {
const ids = [
icon,
icon.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(),
icon.replace(/([a-z])(\d+)/g, "$1-$2")
];
return await searchForIcon(result, collection, ids, options);
}
}
} else return await getCustomIcon(custom, collection, icon, options);
};
export { loadIcon };

View File

@@ -0,0 +1,42 @@
import { defaultIconCustomisations } from "../customisations/defaults.js";
import { getIconData } from "../icon-set/get-icon.js";
import { calculateSize } from "../svg/size.js";
import { iconToSVG, isUnsetKeyword } from "../svg/build.js";
import { mergeIconProps } from "./utils.js";
async function searchForIcon(iconSet, collection, ids, options) {
let iconData;
const { customize } = options?.customizations ?? {};
for (const id of ids) {
iconData = getIconData(iconSet, id);
if (iconData) {
let defaultCustomizations = { ...defaultIconCustomisations };
if (typeof customize === "function") {
iconData = Object.assign({}, iconData);
defaultCustomizations = customize(defaultCustomizations, iconData, `${collection}:${id}`) ?? defaultCustomizations;
}
const { attributes: { width, height, ...restAttributes }, body } = iconToSVG(iconData, defaultCustomizations);
const scale = options?.scale;
return await mergeIconProps(`<svg >${body}</svg>`, collection, id, options, () => {
return { ...restAttributes };
}, (props) => {
const check = (prop, defaultValue) => {
const propValue = props[prop];
let value;
if (!isUnsetKeyword(propValue)) {
if (propValue) return;
if (typeof scale === "number") {
if (scale) value = calculateSize(defaultValue ?? "1em", scale);
} else value = defaultValue;
}
if (!value) delete props[prop];
else props[prop] = value;
};
check("width", width);
check("height", height);
});
}
}
}
export { searchForIcon };

View File

@@ -0,0 +1,12 @@
import { resolvePath } from "mlly";
/**
* Resolve path to package
*/
async function resolvePathAsync(packageName, cwd) {
try {
return await resolvePath(packageName, { url: cwd });
} catch {}
}
export { resolvePathAsync };

View File

@@ -0,0 +1,63 @@
import { calculateSize } from "../svg/size.js";
import { isUnsetKeyword } from "../svg/build.js";
const svgWidthRegex = /\swidth\s*=\s*["']([\w.]+)["']/;
const svgHeightRegex = /\sheight\s*=\s*["']([\w.]+)["']/;
const svgTagRegex = /<svg\s+/;
function configureSvgSize(svg, props, scale) {
const svgNode = svg.slice(0, svg.indexOf(">"));
const check = (prop, regex) => {
const result = regex.exec(svgNode);
const isSet = result != null;
const propValue = props[prop];
if (!propValue && !isUnsetKeyword(propValue)) {
if (typeof scale === "number") {
if (scale > 0) props[prop] = calculateSize(result?.[1] ?? "1em", scale);
} else if (result) props[prop] = result[1];
}
return isSet;
};
return [check("width", svgWidthRegex), check("height", svgHeightRegex)];
}
async function mergeIconProps(svg, collection, icon, options, propsProvider, afterCustomizations) {
const { scale, addXmlNs = false } = options ?? {};
const { additionalProps = {}, iconCustomizer } = options?.customizations ?? {};
const props = await propsProvider?.() ?? {};
await iconCustomizer?.(collection, icon, props);
Object.keys(additionalProps).forEach((p) => {
const v = additionalProps[p];
if (v !== void 0 && v !== null) props[p] = v;
});
afterCustomizations?.(props);
const [widthOnSvg, heightOnSvg] = configureSvgSize(svg, props, scale);
if (addXmlNs) {
if (!svg.includes("xmlns=") && !props["xmlns"]) props["xmlns"] = "http://www.w3.org/2000/svg";
if (!svg.includes("xmlns:xlink=") && svg.includes("xlink:") && !props["xmlns:xlink"]) props["xmlns:xlink"] = "http://www.w3.org/1999/xlink";
}
const propsToAdd = Object.keys(props).map((p) => p === "width" && widthOnSvg || p === "height" && heightOnSvg ? null : `${p}="${props[p]}"`).filter((p) => p != null);
if (propsToAdd.length) svg = svg.replace(svgTagRegex, `<svg ${propsToAdd.join(" ")} `);
if (options) {
const { defaultStyle, defaultClass } = options;
if (defaultClass && !svg.includes("class=")) svg = svg.replace(svgTagRegex, `<svg class="${defaultClass}" `);
if (defaultStyle && !svg.includes("style=")) svg = svg.replace(svgTagRegex, `<svg style="${defaultStyle}" `);
}
const usedProps = options?.usedProps;
if (usedProps) {
Object.keys(additionalProps).forEach((p) => {
const v = props[p];
if (v !== void 0 && v !== null) usedProps[p] = v;
});
if (typeof props.width !== "undefined" && props.width !== null) usedProps.width = props.width;
if (typeof props.height !== "undefined" && props.height !== null) usedProps.height = props.height;
}
return svg;
}
function getPossibleIconNames(icon) {
return [
icon,
icon.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(),
icon.replace(/([a-z])(\d+)/g, "$1-$2")
];
}
export { getPossibleIconNames, mergeIconProps };

View File

@@ -0,0 +1,2 @@
declare function warnOnce(msg: string): void;
export { warnOnce };

View File

@@ -0,0 +1,61 @@
/** Completely free, no limits */
const freeLicense = {
attribution: false,
commercial: true
};
/** Requires same license for derived works */
const freeSameLicense = {
attribution: false,
commercial: true,
sameLicense: true
};
/** Requires attribution */
const attribLicense = {
attribution: true,
commercial: true
};
/** Requires attribution and same license for derived works */
const attribSameLicense = {
attribution: true,
commercial: true,
sameLicense: true
};
/** Requires attribution and non-commercial use */
const attribNonCommercialLicense = {
attribution: true,
commercial: false
};
/** Requires attribution, non-commercial use and same license for derived works */
const attribNonCommercialSameLicense = {
attribution: true,
commercial: false,
sameLicense: true
};
/**
* Data for open source licenses used by icon sets in `@iconify/json` package and smaller packages
*
* Key is SPDX license identifier
*/
const licensesData = {
"Apache-2.0": freeLicense,
"MIT": freeLicense,
"MPL-2.0": freeLicense,
"CC0-1.0": freeLicense,
"CC-BY-3.0": attribLicense,
"CC-BY-SA-3.0": attribSameLicense,
"CC-BY-4.0": attribLicense,
"CC-BY-SA-4.0": attribSameLicense,
"CC-BY-NC-4.0": attribNonCommercialLicense,
"CC-BY-NC-SA-4.0": attribNonCommercialSameLicense,
"ISC": freeLicense,
"OFL-1.1": freeLicense,
"GPL-2.0-only": freeSameLicense,
"GPL-2.0-or-later": freeSameLicense,
"GPL-3.0": freeSameLicense,
"GPL-3.0-or-later": freeSameLicense,
"Unlicense": freeLicense,
"BSD-2-Clause": freeLicense,
"BSD-3-Clause": freeLicense
};
export { licensesData };

View File

@@ -0,0 +1,17 @@
/**
* Convert string to camelCase
*/
declare function camelize(str: string): string;
/**
* Convert string to PascaleCase
*/
declare function pascalize(str: string): string;
/**
* Convert camelCase string to kebab-case
*/
declare function camelToKebab(key: string): string;
/**
* Convert camelCase string to snake-case
*/
declare function snakelize(str: string): string;
export { camelToKebab, camelize, pascalize, snakelize };

View File

@@ -0,0 +1,27 @@
/**
* Convert string to camelCase
*/
function camelize(str) {
return str.replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase());
}
/**
* Convert string to PascaleCase
*/
function pascalize(str) {
const camel = camelize(str);
return camel.slice(0, 1).toUpperCase() + camel.slice(1);
}
/**
* Convert camelCase string to kebab-case
*/
function camelToKebab(key) {
return key.replace(/:/g, "-").replace(/([A-Z])/g, " $1").trim().split(/\s+/g).join("-").toLowerCase();
}
/**
* Convert camelCase string to snake-case
*/
function snakelize(str) {
return camelToKebab(str).replace(/-/g, "_");
}
export { camelToKebab, camelize, pascalize, snakelize };

View File

@@ -0,0 +1,7 @@
/**
* Sanitises title, removing any unwanted characters that might break XML.
*
* This is a very basic funciton, not full parser.
*/
declare function sanitiseTitleAttribute(content: string): string;
export { sanitiseTitleAttribute };

View File

@@ -0,0 +1,5 @@
/**
* Generate <svg>
*/
declare function iconToHTML(body: string, attributes: Record<string, string>): string;
export { iconToHTML };

55
frontend/node_modules/@iconify/utils/lib/svg/pretty.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
/**
* Tags to skip
*/
const skipTags = ["script", "style"];
/**
* Prettify SVG
*/
function prettifySVG(content, tab = " ", depth = 0) {
let result = "";
let level = 0;
content = content.replace(/(\s)*\/>/g, " />");
while (content.length > 0) {
const openIndex = content.indexOf("<");
let closeIndex = content.indexOf(">");
if (openIndex === -1 && closeIndex === -1) return result;
if (openIndex === -1 || closeIndex === -1 || closeIndex < openIndex) return null;
const text = content.slice(0, openIndex);
const trimmedText = text.trim();
if (trimmedText.length) if (text.trimStart() !== text && text.trimEnd() !== text) result += trimmedText + "\n" + tab.repeat(level + depth);
else result = result.trim() + text;
content = content.slice(openIndex);
closeIndex -= openIndex;
const lastChar = content.slice(closeIndex - 1, closeIndex);
const isClosing = content.slice(0, 2) === "</";
let isSelfClosing = lastChar === "/" || lastChar === "?";
if (isClosing && isSelfClosing) return null;
const tagName = content.slice(isClosing ? 2 : 1).split(/[\s>]/).shift();
const ignoreTagContent = !isSelfClosing && !isClosing && skipTags.includes(tagName);
if (!ignoreTagContent) {
const nextOpenIndex = content.indexOf("<", 1);
if (nextOpenIndex !== -1 && nextOpenIndex < closeIndex) return null;
}
if (isClosing && tab.length) {
if (result.slice(0 - tab.length) === tab) result = result.slice(0, result.length - tab.length);
}
result += content.slice(0, closeIndex + 1);
content = content.slice(closeIndex + 1);
if (ignoreTagContent) {
const closingIndex = content.indexOf("</" + tagName);
const closingEnd = content.indexOf(">", closingIndex);
if (closingIndex < 0 || closingEnd < 0) return null;
result += content.slice(0, closingEnd + 1);
content = content.slice(closingEnd + 1);
isSelfClosing = true;
}
if (isClosing) {
level--;
if (level < 0) return null;
} else if (!isSelfClosing) level++;
result += "\n" + tab.repeat(level + depth);
}
return level === 0 ? result : null;
}
export { prettifySVG };

16
frontend/node_modules/@iconify/utils/lib/svg/url.d.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/**
* Encode SVG for use in url()
*
* Short alternative to encodeURIComponent() that encodes only stuff used in SVG, generating
* smaller code.
*/
declare function encodeSVGforURL(svg: string): string;
/**
* Generate data: URL from SVG
*/
declare function svgToData(svg: string): string;
/**
* Generate url() from SVG
*/
declare function svgToURL(svg: string): string;
export { encodeSVGforURL, svgToData, svgToURL };