diff --git a/.eslintrc.yml b/.eslintrc.yml index 4e250f0e..48a29c6e 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -75,7 +75,7 @@ rules: line-comment-position: [error, {position: above, applyDefaultIgnorePatterns: false}] lines-around-comment: [warn, {beforeBlockComment: true}] max-depth: [error] - max-len: [error, 120] + max-len: [error, 120, {ignoreTemplateLiterals: true, ignoreRegExpLiterals: true, ignoreUrls: true}] max-nested-callbacks: [error, 4] new-cap: [error] no-array-constructor: [error] @@ -102,7 +102,6 @@ rules: switch-colon-spacing: [error] unicode-bom: [error] wrap-regex: [error] - sort-imports: [error] # Typescript '@typescript-eslint/no-explicit-any': off diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4f4aa45f..13473888 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -23,7 +23,7 @@ jobs: run: yarn eslint:check - name: Jest tests - run: yarn jest:test + run: yarn jest:test+coverage - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/index.html b/index.html index 51975c7d..d91649cc 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,7 @@ Stylify! `; + addBundleStats({ + resourcePath: this.resourcePath, + css: css + }); } return source; diff --git a/packages/profiler/src/Extensions/BuildsAnalyzer.tsx b/packages/profiler/src/Extensions/BuildsAnalyzer.tsx deleted file mode 100644 index 94a1393c..00000000 --- a/packages/profiler/src/Extensions/BuildsAnalyzer.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { Component } from 'preact'; -import { ProfilerExtensionPropsInterface } from '..'; - -export class BuildsAnalyzerExtension extends Component { - - private openCodeInNewWindow = null; - - public state: Record = { - cssInBase64: null, - totalRepaintTime: 0, - actualSize: 0, - builds: [], - buildsListVisible: false - } - - constructor(props: ProfilerExtensionPropsInterface) { - super(); - - this.openCodeInNewWindow = props.config.openCodeInNewWindow; - document.addEventListener('stylify:runtime:repainted', (event: any) => { - const { css, content, repaintTime, compilationResult } = event.detail; - const builds = this.state.builds; - const buildSize = this.state.actualSize === 0 - ? css.length - : css.length - this.state.actualSize; - - if (buildSize === 0) { - return; - } - - builds.push({ - content: content, - size: buildSize, - repaintTime: repaintTime, - details: compilationResult.lastBuildInfo - }); - - this.setState({ - totalRepaintTime: this.state.totalRepaintTime + repaintTime, - actualSize: this.state.actualSize + buildSize, - builds: builds - }); - }); - - } - - public getGeneratedCssFromPage(): string { - const stylifyCssElement = document.querySelector('#stylify-css'); - return stylifyCssElement ? stylifyCssElement.innerHTML : ''; - } - - public convertSizeToKb(size: number, precision = 1): string { - return (size / 1000).toFixed(precision) + ' Kb'; - } - - public convertTimeToSeconds(time: number, precision = 1): string { - return time.toFixed(precision) + ' ms'; - } - - public toggleBuildsListVisibility = (): void => { - this.setState({ - buildsListVisible: !this.state.buildsListVisible - }); - } - - public openProcessedContentInNewWindow(content: string): void { - const div = document.createElement('div'); - div.innerHTML = decodeURIComponent(content); - this.openCodeInNewWindow(div.innerHTML, null, 'processed selectors'); - } - - public openGeneratedCssInNewWindow = (): void => { - this.openCodeInNewWindow(this.getGeneratedCssFromPage(), 'css', 'generated css'); - } - - /* eslint-disable max-len */ - public render() { - return ( - - ); - } - -} diff --git a/packages/profiler/src/Extensions/CacheInfo.tsx b/packages/profiler/src/Extensions/CacheInfo.tsx deleted file mode 100644 index dee80c12..00000000 --- a/packages/profiler/src/Extensions/CacheInfo.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { Component } from 'preact'; -import { ProfilerExtensionPropsInterface } from '..'; - -export class CacheInfoExtension extends Component { - - private stylify = null; - - private openCodeInNewWindow = null; - - public state: Record = { - cacheInfoVisible: false, - cacheList: [] - } - - constructor(props: ProfilerExtensionPropsInterface) { - super(); - - this.stylify = props.config.stylify; - this.openCodeInNewWindow = props.config.openCodeInNewWindow; - - document.addEventListener('stylify:runtime:hydrated', (event: any) => { - this.state.cacheList.push(this.stringifyCache(event.detail.cache)); - - this.setState({ - cacheList: this.state.cacheList - }); - }); - } - - public toggleCacheInfoVisibility = (): void => { - this.setState({ - cacheInfoVisible: !this.state.cacheInfoVisible - }); - } - - public convertSizeToKb(size: number, precision = 1): string { - return (size / 1000).toFixed(precision); - } - - public openActualCacheInNewWindow = (): void => { - this.openCodeInNewWindow(this.stringifyCache(this.stylify.runtime.compilationResult.serialize()), 'json'); - } - - private stringifyCache = (cache: Record): string => { - return JSON.stringify(cache, null, 4); - } - - /* eslint-disable max-len */ - public render() { - return ( - - ); - } - -} diff --git a/packages/profiler/src/Extensions/CompilerExtension.tsx b/packages/profiler/src/Extensions/CompilerExtension.tsx new file mode 100644 index 00000000..a1b119ce --- /dev/null +++ b/packages/profiler/src/Extensions/CompilerExtension.tsx @@ -0,0 +1,377 @@ + +import { Card, CardTitle, HideableElement, TableWrapper, utils } from '..'; +import type { ComponentsInterface, PlainSelectorInterface } from '@stylify/stylify'; +import { Component } from 'preact'; +import { JSXInternal } from 'preact/src/jsx'; +import type { ProfilerExtensionPropsInterface } from '../Toolbar'; + +interface ExpandableStateInterface { + mangleSelectors: boolean, + dev: false, + colorTypeVariables: Record, + unitTypeVariables: Record, + otherTypeVariables: Record, + plainSelectors: Record, + macros: Record, + components: Record, + helpers: Record, + screens: Record +} + +export class CompilerExtension extends Component { + + public static title = 'Compiler'; + + public static icon = ` + + + + `; + + constructor() { + super(); + + this.state = { + ...{ + mangleSelectors: false, + dev: false, + colorTypeVariables: {}, + unitTypeVariables: {}, + otherTypeVariables: {}, + plainSelectors: {}, + macros: {}, + components: {}, + helpers: {}, + screens: {} + }, + ...this.getConfigurationData() + }; + + window.addEventListener('load', () => { + this.setState(this.getConfigurationData()); + }); + } + + private getConfigurationData() { + let variables = {}; + let plainSelectors = {}; + let macros = {}; + let components = {}; + let helpers = {}; + let screens = {}; + const runtime = utils.getStylifyRuntime(); + + if (runtime) { + variables = { + ...variables, + ...runtime.compiler.variables + }; + plainSelectors = { + ...plainSelectors, + ...runtime.compiler.plainSelectors + }; + macros = { + ...macros, + ...runtime.compiler.macros + }; + components = { + ...components, + ...runtime.compiler.components + }; + helpers = { + ...helpers, + ...runtime.compiler.helpers + }; + screens = { + ...screens, + ...runtime.compiler.screens + }; + } + + const profilerDataFromPage = utils.getProfilerDataFromPage('compiler'); + if (profilerDataFromPage) { + variables = { + ...variables, + ...profilerDataFromPage.variables + }; + plainSelectors = { + ...plainSelectors, + ...profilerDataFromPage.plainSelectors + }; + macros = { + ...macros, + ...profilerDataFromPage.macros + }; + components = { + ...components, + ...profilerDataFromPage.components + }; + helpers = { + ...helpers, + ...profilerDataFromPage.helpers + }; + screens = { + ...screens, + ...profilerDataFromPage.screens + }; + } + + const colorTypeVariables = {}; + const unitTypeVariables = {}; + const otherTypeVariables = {}; + + for (const variableName in variables) { + const variableValue = variables[variableName]; + const variableTypeCheckElement = new Option().style; + variableTypeCheckElement.color = variableValue; + variableTypeCheckElement.width = variableValue; + + if (variableTypeCheckElement.color !== '') { + colorTypeVariables[variableName] = variableValue; + continue; + } + + if (variableTypeCheckElement.width !== '') { + unitTypeVariables[variableName] = variableValue; + continue; + } + + otherTypeVariables[variableName] = variableValue; + } + + return { + colorTypeVariables: colorTypeVariables, + unitTypeVariables: unitTypeVariables, + otherTypeVariables: otherTypeVariables, + plainSelectors: plainSelectors, + macros: macros, + components: components, + helpers: helpers, + screens: screens + }; + } + + /* eslint-disable max-len */ + public render(): JSXInternal.Element { + return ( + <> + + {`Variables (${Object.keys({...this.state.colorTypeVariables, ...this.state.unitTypeVariables, ...this.state.otherTypeVariables}).length})`} + + +

{`Colors (${Object.keys(this.state.colorTypeVariables).length})`}

+ + + + + + + + + + + {Object.keys(this.state.colorTypeVariables).sort().map((variableName) => { + return ( + + + + + + ); + })} + +
NamePreviewValue
{variableName} +
*/ + style={`background-color:${this.state.colorTypeVariables[variableName]}`} + /* */ + >
+
{this.state.colorTypeVariables[variableName]}
+
+
+ + +

{`Units (${Object.keys(this.state.unitTypeVariables).length})`}

+ + + + + + + + + + {Object.keys(this.state.unitTypeVariables).sort().map((variableName) => { + return ( + + + + + ); + })} + +
NameValue
{variableName}{this.state.unitTypeVariables[variableName]}
+
+
+ + +

{`Other (${Object.keys(this.state.otherTypeVariables).length})`}

+ + + + + + + + + + {Object.keys(this.state.otherTypeVariables).sort().map((variableName) => { + return ( + + + + + ); + })} + +
NameValue
{variableName}{this.state.otherTypeVariables[variableName]}
+
+
+ + No variables configured. + +
+ + + {`Screens (${Object.keys(this.state.screens).length})`} + + + + + + + + + + {Object.keys(this.state.screens).map((screenName) => { + return ( + + + + + ); + })} + +
NameValue
{screenName} + {typeof this.state.screens[screenName] === 'function' ? this.state.screens[screenName].toString() : this.state.screens[screenName]} +
+
+ + No screens defined. + +
+ + + {`Selectors macros (${Object.keys(this.state.macros).length})`} +
+ {Object.keys(this.state.macros).sort().map((macroRegExp) => { + return ( +
+									{macroRegExp}{this.state.macros[macroRegExp].toString().replaceAll(/ {2}|\t\t/ig, ' ')}
+								
+ ); + })} +
+ + No selectors macros configured. + +
+ + + {`Plain selectors (${Object.keys(this.state.plainSelectors).length})`} + + + + + + + + + + {Object.keys(this.state.plainSelectors).sort().map((plainSelector) => { + return ( + + + + + ); + })} + +
NameSelectors dependencies
{plainSelector}{this.state.plainSelectors[plainSelector].selectors.join(' ')}
+
+ + No plain selectors configured. + +
+ + + {`Components (${Object.keys(this.state.components).length})`} + + + + + + + + + + {Object.keys(this.state.components).sort().map((componentName) => { + return ( + + + + + ); + })} + +
NameSelectors dependencies
{componentName}{this.state.components[componentName].selectors.join(' ')}
+
+ + No components configured. + +
+ + + {`Helpers (${Object.keys(this.state.helpers).length})`} + + + + + + + + + + {Object.keys(this.state.helpers).sort().map((helperName) => { + return ( + + + + + ); + })} + +
NameCallback
{helperName} +
{this.state.helpers[helperName].toString().replaceAll(/ {2}|\t\t/ig, ' ')}
+
+
+ + No helpers configured. + +
+ + ); + } + +} diff --git a/packages/profiler/src/Extensions/ConfigurationsVisualizer.tsx b/packages/profiler/src/Extensions/ConfigurationsVisualizer.tsx deleted file mode 100644 index 55974ca4..00000000 --- a/packages/profiler/src/Extensions/ConfigurationsVisualizer.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import type { Compiler } from '@stylify/stylify'; -import { Component } from 'preact'; -import { ProfilerExtensionPropsInterface } from '..'; - -export class ConfigurationsVisualizerExtension extends Component { - - public state: Record = { - components: {}, - componentsListVisible: false, - - macros: {}, - macrosListVisible: false, - - variables: {}, - variablesListVisible: false - }; - - constructor(props: ProfilerExtensionPropsInterface) { - super(); - - this.updateCompilerConfigs(props.config.stylify.compiler); - - document.addEventListener('stylify:compiler:configured', (event: any): void => { - this.updateCompilerConfigs(event.detail.compiler); - }); - } - - private updateCompilerConfigs = (compiler: Compiler): void => { - this.setState({ - components: compiler.components, - helpers: compiler.helpers, - macros: compiler.macros, - variables: compiler.variables - }); - } - - private toggleDetailVisibility = (name: string): void => { - this.setState({ - [`${name}Visible`]: !this.state[`${name}Visible`] - }); - } - - /* eslint-disable max-len */ - public render() { - return ( - <> -
- this.toggleDetailVisibility('macrosList')}> - - {Object.keys(this.state.macros).length} - -
- - - - - - - - {Object.keys(this.state.macros).map((macroRegExp) => { - return ( - - - - ); - })} - -
Macro
-
{macroRegExp}{this.state.macros[macroRegExp].toString().replaceAll(/ {2}|\t\t/ig, ' ')}
-
-
-
- -
- this.toggleDetailVisibility('variablesList')}> - - {Object.keys(this.state.variables).length} - -
- - - - - - - - - {Object.keys(this.state.variables).map((variableName) => { - return ( - - - - - ); - })} - -
NameValue
{variableName}{this.state.variables[variableName]}
-
-
- -
- this.toggleDetailVisibility('componentsList')}> - - {Object.keys(this.state.components).length} - -
- - - - - - - - - {Object.keys(this.state.components).map((componentName) => { - return ( - - - - - ); - })} - -
NameClasses
{componentName}{this.state.components[componentName].selectors.join(' ')}
-
-
- -
- this.toggleDetailVisibility('helpersList')}> - - {Object.keys(this.state.helpers).length} - -
- - - - - - - - {Object.keys(this.state.helpers).map((helperName) => { - return ( - - - - ); - })} - -
Helper
-
{this.state.helpers[helperName].toString().replaceAll(/ {2}|\t\t/ig, ' ')}
-
-
-
- - ); - } - -} diff --git a/packages/profiler/src/Extensions/DomNodesCounter.tsx b/packages/profiler/src/Extensions/DomNodesCounter.tsx deleted file mode 100644 index 7b533004..00000000 --- a/packages/profiler/src/Extensions/DomNodesCounter.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Component } from 'preact'; - -export class DomNodesCounterExtension extends Component { - - private profilerElement: HTMLElement = document.querySelector('#stylify-profiler'); - - public state: Record = { - recommendedDomNodesCount: 1500, - totalDomNodesCount: 0 - } - - constructor() { - super(); - - document.addEventListener('DOMContentLoaded', (): void => { - this.updateDomNodesCount(); - }); - - const observer = new MutationObserver((): void => { - this.updateDomNodesCount(); - }); - - observer.observe(document.documentElement, { - attributeFilter: ['class'], - childList: true, - subtree: true - }); - } - - private updateDomNodesCount = (): void => { - const count = document.getElementsByTagName('*').length - this.profilerElement.getElementsByTagName('*').length; - this.setState({ totalDomNodesCount: count }); - } - - /* eslint-disable max-len */ - public render() { - return ( -
-
- - this.state.recommendedDomNodesCount ? 'color:red' : '' } profiler-extension__button-label`}>{this.state.totalDomNodesCount} -
-
- ); - } - -} diff --git a/packages/profiler/src/Extensions/RuntimeExtension.tsx b/packages/profiler/src/Extensions/RuntimeExtension.tsx new file mode 100644 index 00000000..c57565db --- /dev/null +++ b/packages/profiler/src/Extensions/RuntimeExtension.tsx @@ -0,0 +1,235 @@ +import { + Card, + CardTitle, + HideableElement, + InlineCard, + InlineCardIcon, + InlineCardTitle, + InlineCardsWrapper, + utils +} from '..'; +import type { + CssRecord, + SerializedCompilationResultInterface +} from '@stylify/stylify'; +import { Component } from 'preact'; +import { JSXInternal } from 'preact/src/jsx'; +import type { ProfilerExtensionPropsInterface } from '..'; + +interface ExpandableStateInterface { + version: number, + dev: boolean, + repaintTimeout: number, + loadedCache: string[], + // Compilation result + processedSelectors: Record, + processedComponents: Record, + cache: SerializedCompilationResultInterface +} + +export class RuntimeExtension extends Component { + + public static title = 'Runtime'; + + public static icon = ` + + + + `; + + constructor() { + super(); + + this.state = { + ...{ + // Runtime + version: null, + dev: false, + repaintTimeout: 0, + loadedCache: [], + // Compilation result + processedSelectors: {}, + processedComponents: {}, + cache: {} + }, + ...this.getRuntimeInfo() + }; + } + + public componentDidMount(): void { + document.addEventListener('stylify:ready', (): void => { + this.setState(this.getRuntimeInfo()); + }); + + document.addEventListener('stylify:repainted', (): void => { + this.setState(this.getRuntimeInfo()); + }); + } + + private getRuntimeInfo(): Record { + const runtime = utils.getStylifyRuntime(); + + if (!runtime) { + return {}; + } + + const loadedCache = []; + const processedSelectors = {}; + const processedComponents = {}; + let cache = {}; + + if (runtime.compilationResult) { + cache = runtime.compilationResult.serialize(); + for (const selector in runtime.compilationResult.selectorsList) { + processedSelectors[selector] = runtime.compilationResult.selectorsList[selector].cache; + } + + for (const component in runtime.compilationResult.componentsList) { + processedComponents[component] = runtime.compilationResult.componentsList[component]; + } + + for (const cacheElement of document.querySelectorAll('.stylify-runtime-cache')) { + loadedCache.push(cacheElement.innerHTML.trim()); + } + } + + return { + version: runtime.version, + dev: runtime.dev, + repaintTimeout: runtime.repaintTimeout, + loadedCache: loadedCache, + processedSelectors: processedSelectors, + processedComponents: processedComponents, + cache: cache + }; + } + + /* eslint-disable max-len */ + public render(): JSXInternal.Element { + return ( + <> + + + +
+ Runtime +
+ + {`Version ${this.state.version}`} + + + Not detected. + +
+
+
+ + +
+ Repaint timeout +
+ {`${this.state.repaintTimeout} ms`} +
+
+
+ + +
+ Environment +
+ {this.state.dev ? 'Development' : 'Production'} +
+
+
+ + +
+ Actual cache +
+ {`Size: ${utils.convertSizeToKb(JSON.stringify(this.state.cache).length)}`} | Export Cache +
+
+
+
+ + + {`Processed selectors (${Object.keys(this.state.processedSelectors).length})`} +
+ + + + + + + + + {Object.keys(this.state.processedSelectors).sort().map((selector: string) => { + return ( + + + + + ); + })} + +
SelectorCSS
{selector} +
{this.state.processedSelectors[selector]}
+
+
+ + No selectors were processed. + +
+ + + {`Processed components (${Object.keys(this.state.processedComponents).length})`} +
+ + + + + + + + + {Object.keys(this.state.processedComponents).sort().map((component: string) => { + return ( + + + + + ); + })} + +
ComponentCSS
{component} +
{this.state.processedComponents[component]}
+
+
+ + No components were processed. + +
+ + + {`Loaded cache (${this.state.loadedCache.length})`} + + {this.state.loadedCache.map((loadedCache: string, index) => { + return ( +
+

+ {`Size ${utils.convertSizeToKb(loadedCache.length)}`} | Export Cache +

+
{loadedCache}
+
+ ); + })} +
+ + No cache was loaded. + +
+ + ); + } + +} diff --git a/packages/profiler/src/Extensions/SummaryExtension.tsx b/packages/profiler/src/Extensions/SummaryExtension.tsx new file mode 100644 index 00000000..187441e8 --- /dev/null +++ b/packages/profiler/src/Extensions/SummaryExtension.tsx @@ -0,0 +1,169 @@ +import { + HideableElement, + InlineCard, + InlineCardButtonsWrapper, + InlineCardIcon, + InlineCardTitle, + InlineCardsWrapper, + utils +} from '..'; +import { Component } from 'preact'; +import { JSXInternal } from 'preact/src/jsx'; +import type { ProfilerExtensionPropsInterface } from '..'; + +interface ExpandableStateInterface { + recommendedDomNodesCount: number, + recommendedCssSize: number, + totalDomNodesCount: number, + cssSize: number, + cacheElementsCount: number, + runtimeVersion: string +} + +export class SummaryExtension extends Component { + + public static title = 'Summary'; + + public static icon = ` + + + + `; + + private profilerElement: HTMLElement = document.querySelector('#stylify-profiler'); + + public config: ProfilerExtensionPropsInterface = null; + + constructor(props) { + super(); + + this.config = props.config as ProfilerExtensionPropsInterface; + + const getNewStateInfo = (): Partial => { + return { + runtimeVersion: this.getRuntimeVersion(), + totalDomNodesCount: this.getDomNodesCount(), + cssSize: this.getCssSize(), + cacheElementsCount: this.getCacheElementsCount() + }; + }; + + this.state = { + ...{ + recommendedDomNodesCount: 1500, + recommendedCssSize: 50000, + totalDomNodesCount: 0, + cssSize: 0, + cacheElementsCount: 0, + runtimeVersion: null + }, + ...getNewStateInfo() + }; + + document.addEventListener('stylify:ready', (): void => { + this.setState(getNewStateInfo()); + }); + + document.addEventListener('stylify:repainted', (): void => { + this.setState(getNewStateInfo()); + }); + } + + private getRuntimeVersion(): string|null { + const runtime = utils.getStylifyRuntime(); + return runtime ? runtime.version as string : null; + } + + private getCacheElementsCount = (): number => { + return document.querySelectorAll('.stylify-runtime-cache').length; + } + + private getStylifyCssElementContent = () => { + const cssElement = document.querySelector('#stylify-css'); + return cssElement ? cssElement.innerHTML.trim() : null; + } + + private getCssSize = (): number => { + const cssElementContent = this.getStylifyCssElementContent(); + + if (cssElementContent === null) { + return 0; + } + + return cssElementContent.length; + }; + + private getDomNodesCount = (): number => { + const domNodesCount = document.getElementsByTagName('*').length; + return this.profilerElement + ? domNodesCount - this.profilerElement.getElementsByTagName('*').length + : domNodesCount; + } + + private openGeneratedCssInNewWindow = () => { + utils.openCodeInNewWindow(this.getStylifyCssElementContent(), 'css', 'generated css'); + }; + + /* eslint-disable max-len */ + public render(): JSXInternal.Element { + return ( + <> + + + +
+ CSS inside #stylify-css + Stylify CSS element not found. + + 50000 ? 'color:red' : 'color:green' }`}>{utils.convertSizeToKb(this.state.cssSize)} + {` (recommended limit ${utils.convertSizeToKb(this.state.recommendedCssSize)})`} + + +
+
+ + +
+ Runtime +
+ + {`Version ${this.state.runtimeVersion}`} + + this.config.toggleTab('compiler')}>Show Compiler config | this.config.toggleTab('runtime')}>Show Runtime info + + + Not detected. +
+
+
+ + +
+ DOM nodes count +
+ this.state.recommendedDomNodesCount ? 'color:red' : 'color:green' }`}>{this.state.totalDomNodesCount} + {` (recommended limit ${this.state.recommendedDomNodesCount})`} +
+
+
+ + +
+ Cache elements count + Not detected + + {this.state.cacheElementsCount} + + this.config.toggleTab('runtime')}>Show cache + + +
+
+
+ + ); + } + +} diff --git a/packages/profiler/src/Extensions/index.ts b/packages/profiler/src/Extensions/index.ts index c6cd04f1..45de065e 100644 --- a/packages/profiler/src/Extensions/index.ts +++ b/packages/profiler/src/Extensions/index.ts @@ -1,4 +1,3 @@ -export * from './BuildsAnalyzer'; -export * from './CacheInfo'; -export * from './ConfigurationsVisualizer'; -export * from './DomNodesCounter'; +export * from './RuntimeExtension'; +export * from './CompilerExtension'; +export * from './SummaryExtension'; diff --git a/packages/profiler/src/Profiler.ts b/packages/profiler/src/Profiler.ts index 4be16161..1cd9f69f 100644 --- a/packages/profiler/src/Profiler.ts +++ b/packages/profiler/src/Profiler.ts @@ -1,80 +1,58 @@ import './profiler.scss'; -import { - BuildsAnalyzerExtension, - CacheInfoExtension, - ConfigurationsVisualizerExtension, - DomNodesCounterExtension -} from './Extensions'; -import { addProfilerExtension, initProfilerToolbar } from './Toolbar'; -import type { Runtime } from '@stylify/stylify'; +import * as preact from 'preact'; +import { initProfilerToolbar } from '.'; declare global { interface Window { title: string; - Stylify: Runtime } } -export interface ProfilerExtensionPropsInterface { - config: { - stylify: Runtime, - openCodeInNewWindow: CallableFunction - } +export interface ProfilerConfigInterface { + extensions?: any[] } +export type AddExtensionType = (extension: any) => void; + +export { preact }; + export class Profiler { public static readonly WINDOW_IS_DEFINED = typeof window !== 'undefined'; - private readonly PRISM_VERSION = '1.23.0'; + // Dynamically added inside Toolbar.tsx + public addExtension: AddExtensionType = null; - private readonly PRISM_CDN_URL = `https://cdnjs.cloudflare.com/ajax/libs/prism/${this.PRISM_VERSION}`; + private config: ProfilerConfigInterface = { + extensions: [] + }; + + constructor(config: ProfilerConfigInterface = {}) { + this.config = { + ...this.config, + ...config + }; - constructor() { this.init(); } public init(): void { - this.addProfilerExtension(BuildsAnalyzerExtension); - this.addProfilerExtension(CacheInfoExtension); - this.addProfilerExtension(ConfigurationsVisualizerExtension); - this.addProfilerExtension(DomNodesCounterExtension); - if (!Profiler.WINDOW_IS_DEFINED) { return null; } - document.addEventListener('stylify:ready', (event: any) => { - initProfilerToolbar({ - stylify: event.detail, - openCodeInNewWindow: this.openCodeInNewWindow - }); - }); - } - - public addProfilerExtension(profilerExtension: any): void { - addProfilerExtension(profilerExtension); - } + const toolbarConfig = { + extensions: this.config.extensions, + profiler: this + }; - private openCodeInNewWindow = (code: string, language: string = null, windowTitle: string = null) => { - const codeWindow = window.open(''); - language = language || 'markup'; - codeWindow.title = 'Stylify: ' + (windowTitle || 'profiler preview'); - if (language === 'markup') { - code = code.replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); + if (['complete', 'loaded', 'interactive'].includes(document.readyState)) { + initProfilerToolbar(toolbarConfig); + } else { + document.addEventListener('DOMContentLoaded', () => { + initProfilerToolbar(toolbarConfig); + }); } - - codeWindow.document.write(` - - - -
${code}
- `); - codeWindow.document.close(); } } diff --git a/packages/profiler/src/Toolbar.tsx b/packages/profiler/src/Toolbar.tsx index 6c85cc40..b478692d 100644 --- a/packages/profiler/src/Toolbar.tsx +++ b/packages/profiler/src/Toolbar.tsx @@ -1,142 +1,81 @@ -/* - @stylify-components[{ - 'profiler-extension': ` - box-sizing:border-box - border-left:1px__solid__#555 - align-items:center - display:flex - min-height:100% - position:relative - hover:background:#333 - `, - 'profiler-extension__button': ` - box-sizing:border-box - height:20px - padding:0__8px - display:flex - align-items:center - justify-content:center - font-size:12px - cursor:pointer - user-select:none - `, - 'profiler-extension__button--active': 'background-color:#333', - 'profiler-extension__dropdown': ` - box-sizing:border-box - position:absolute - bottom:100% - left:0 - max-height:50vh - overflow:auto - min-width:100% - background:#000 - padding:8px - `, - 'profiler-extension__link': ` - box-sizing:border-box - text-decoration:none - color:#00b2e5 - margin-right:8px - white-space:nowrap - display:inline-block - cursor:pointer - `, - 'profiler-extension__button-icon': ` - width:12px - height:12px - margin-right:8px - display:inline-block - font-weight:bold - color:#aaa - `, - 'profiler-extension__button-label': 'line-height:1' - }] - @stylify-pregenerate[ - border-top:1px__solid__#444 - background-color:#333 - bottom:0 - color:#fff - content-visibility:hidden - content-visibility:visible - display:block - display:none - font-family:arial - font-size:12px - line-height:20px - margin-left:8px - margin:0__8px - max-width:800px - overflow-x:auto - padding-top:8px - position:fixed - text-align:left - visibility:hidden - visibility:visible - width:auto - word-spacing:24px - profiler-extension - profiler-extension__button - profiler-extension__button--active - profiler-extension__dropdown - profiler-extension__link - profiler-extension__button-icon - profiler-extension__button-label - ] -*/ -import { Component, render } from 'preact'; -import type { Runtime } from '@stylify/stylify'; - -export interface ToolbarInitConfig { - stylify: Runtime - openCodeInNewWindow: CallableFunction +import { CompilerExtension, RuntimeExtension, SummaryExtension } from './Extensions'; +import { Component, h, render } from 'preact'; +import type { Profiler } from '.'; + +export interface ProfilerExtensionPropsInterface { + toggleTab: (extensionName: string) => void +} + +export interface ProfilerExtensionInterface { + title: string, + icon?: string } -const extensions = {}; -let extensionsConfig = {}; +export interface ProfilerToolbarConfigInterface { + extensions: any[], + profiler: Profiler +} -const ToolbarExtension = ({ extensionName }) => { - const TagName = extensions[extensionName]; - return ; +type ExpandableState = { + profilerVisible: boolean, + profilerNavigationVisible: boolean, + selectedTab: string|null, + extensions: Record }; -const initProfilerToolbar = (profilerConfig: ToolbarInitConfig): void => { - extensionsConfig = profilerConfig; +class ProfilerToolbar extends Component { - let profilerToolbarElement = document.querySelector(`#${ProfilerToolbar.TOOLBAR_ELEMENT_ID}`); + public static readonly TOOLBAR_ELEMENT_ID = 'stylify-profiler'; - if (!profilerToolbarElement) { - profilerToolbarElement = document.createElement('div'); - profilerToolbarElement.id = ProfilerToolbar.TOOLBAR_ELEMENT_ID; - profilerToolbarElement.classList.add('stylify-ignore'); + private readonly LOCAL_STORAGE_ID = 'stylify-profiler' - document.body.append(profilerToolbarElement); - } + private extensionsConfig: ProfilerExtensionPropsInterface = null; - render(, profilerToolbarElement, profilerToolbarElement); -}; + public constructor({ config }) { + super(); -const addProfilerExtension = (component: any): void => { - extensions[component.name] = component; -}; + config.profiler.addExtension = (extension: string) => { + this.addExtension(extension, true); + }; -class ProfilerToolbar extends Component { + const configFromLocalStorage = this.getConfigFromLocalStorage(); - public static readonly TOOLBAR_ELEMENT_ID = 'stylify-profiler'; + this.state = { + ...{ + extensions: {}, + profilerVisible: false, + profilerNavigationVisible: false, + selectedTab: null + }, + ...configFromLocalStorage ? configFromLocalStorage : {} + }; - private readonly LOCAL_STORAGE_ID = 'stylify-profiler;' + this.addExtension(SummaryExtension); + this.addExtension(CompilerExtension); + this.addExtension(RuntimeExtension); - public state: Record = { - extensions: extensions, - extensionsVisible: true - } + for (const extension of config.extensions) { + this.addExtension(extension); + } - public constructor() { - super(); + this.extensionsConfig = { + toggleTab: (extensionName: string) => { + return this.toggleTabVisibility(`${extensionName}Extension`); + } + }; + } - const configFromLocalStorage = this.getConfigFromLocalStorage(); + public addExtension(component: any, updateState = false): void { + const extensionName = component.name.toLowerCase(); - if (configFromLocalStorage) { - this.state.extensionsVisible = configFromLocalStorage.extensionsVisible; + if (updateState) { + const extensions = this.state.extensions; + extensions[extensionName] = component; + this.setState({ + extensions: extensions + }); + } else { + this.state.extensions[extensionName] = component; } } @@ -145,7 +84,8 @@ class ProfilerToolbar extends Component { if (!localStorageConfig) { localStorage.setItem(this.LOCAL_STORAGE_ID, JSON.stringify({ - extensionsVisible: this.state.extensionsVisible + profilerVisible: false, + selectedTab: null })); } @@ -153,33 +93,180 @@ class ProfilerToolbar extends Component { } private updateConfigInLocalStorage = (config: Record = {}): void => { - localStorage.setItem( - this.LOCAL_STORAGE_ID, JSON.stringify(Object.assign(this.getConfigFromLocalStorage(), config)) - ); + localStorage.setItem(this.LOCAL_STORAGE_ID, JSON.stringify({...this.getConfigFromLocalStorage(), ...config})); + } + + private toggleProfilerVisibility = () => { + const profilerVisible = !this.state.profilerVisible; + + this.setState({ + profilerVisible: profilerVisible + }); + + this.updateConfigInLocalStorage({ + profilerVisible: profilerVisible + }); } - private toggleExtensionsVisibility = () => { - const extensionsVisible = !this.state.extensionsVisible; + private toggleProfilerNavigationVisibility = () => { + const profilerNavigationVisible = !this.state.profilerNavigationVisible; this.setState({ - extensionsVisible: extensionsVisible + profilerNavigationVisible: profilerNavigationVisible }); + } + + private toggleTabVisibility = (selectedTab: string) => { + this.setState({ + selectedTab: selectedTab.toLowerCase() + }); + this.updateConfigInLocalStorage({ - extensionsVisible: extensionsVisible + selectedTab: selectedTab }); } + private getSelectedTabComponent(): ProfilerExtensionInterface { + return this.state.extensions[ + this.state.selectedTab ? this.state.selectedTab : Object.keys(this.state.extensions)[0] + ] as ProfilerExtensionInterface; + } + + private getSelectedTabContent = () => { + const ProfilerExtension = this.getSelectedTabComponent() as any; + return ; + } + + private isTabSelected = (extensionName: string) => { + return this.state.selectedTab !== null && this.state.selectedTab.toLowerCase() === extensionName.toLowerCase(); + } + /* eslint-disable max-len */ public render() { return (
-
- - Stylify - -
- {Object.keys(this.state.extensions).map((extensionName) => { - return ; - })} + +
+
+ + + + + + + + +
+ +
+
+

{this.getSelectedTabComponent().title}

+
{this.getSelectedTabContent()}
+
+
+ Copyright © 2021-{new Date().getFullYear()} Vladimír Macháček + | +
+ Stylify.dev +
@@ -188,7 +275,16 @@ class ProfilerToolbar extends Component { /* eslint-enable max-len */ } -export { - addProfilerExtension, - initProfilerToolbar +export const initProfilerToolbar = (config: ProfilerToolbarConfigInterface): void => { + let profilerToolbarElement = document.querySelector(`#${ProfilerToolbar.TOOLBAR_ELEMENT_ID}`); + + if (!profilerToolbarElement) { + profilerToolbarElement = document.createElement('div'); + profilerToolbarElement.id = ProfilerToolbar.TOOLBAR_ELEMENT_ID; + profilerToolbarElement.classList.add('stylify-ignore'); + + document.body.append(profilerToolbarElement); + } + + render(, profilerToolbarElement, profilerToolbarElement); }; diff --git a/packages/profiler/src/Utils.ts b/packages/profiler/src/Utils.ts new file mode 100644 index 00000000..f510f20a --- /dev/null +++ b/packages/profiler/src/Utils.ts @@ -0,0 +1,72 @@ +import type { Runtime } from '@stylify/stylify'; + +class Utils { + + private readonly PRISM_VERSION = '1.23.0'; + + private readonly PRISM_CDN_URL = `https://cdnjs.cloudflare.com/ajax/libs/prism/${this.PRISM_VERSION}`; + + private stylify: Runtime = null; + + private profilerDataFromPage: Record> = null; + + constructor() { + document.addEventListener('stylify:ready', (event: any): void => { + this.stylify = event.detail; + }); + } + + public getProfilerDataFromPage(extensionName: string): Record|null { + if (!this.profilerDataFromPage) { + document.querySelectorAll('.stylify-profiler-data').forEach((element) => { + this.profilerDataFromPage = {...this.profilerDataFromPage, ...JSON.parse(element.innerHTML)}; + }); + } + + return this.profilerDataFromPage && this.profilerDataFromPage[extensionName + 'Extension'] + ? this.profilerDataFromPage[extensionName + 'Extension'] + : null; + } + + public getStylifyRuntime(): Runtime|null { + let stylify = this.stylify; + + if (!stylify) { + stylify = globalThis.Stylify; + } + + return stylify || null; + } + + public convertSizeToKb(size: number, precision = 1): string { + return `${(size / 1000).toFixed(precision)} Kb`; + } + + public convertTimeToSeconds(time: number, precision = 1): string { + return time.toFixed(precision) + ' ms'; + } + + public openCodeInNewWindow = (code: string, language: string = null, windowTitle: string = null): void => { + const codeWindow = window.open(''); + language = language || 'markup'; + codeWindow.title = 'Stylify: ' + (windowTitle || 'profiler preview'); + if (language === 'markup') { + code = code.replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + codeWindow.document.write(` + + + +
${code}
+ `); + codeWindow.document.close(); + } + +} + +export const utils = new Utils; diff --git a/packages/profiler/src/assets/icons/fonts/stylify-profiler.woff b/packages/profiler/src/assets/icons/fonts/stylify-profiler.woff index 81b2cee8..2dbe6abc 100644 Binary files a/packages/profiler/src/assets/icons/fonts/stylify-profiler.woff and b/packages/profiler/src/assets/icons/fonts/stylify-profiler.woff differ diff --git a/packages/profiler/src/assets/icons/selection.json b/packages/profiler/src/assets/icons/selection.json index 68193041..44ee800f 100644 --- a/packages/profiler/src/assets/icons/selection.json +++ b/packages/profiler/src/assets/icons/selection.json @@ -1 +1 @@ -{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M512 133.035l331.264 165.632-331.264 165.632-331.264-165.632zM492.928 47.189l-426.667 213.333c-21.077 10.539-29.611 36.139-19.072 57.216 4.309 8.661 11.136 15.189 19.072 19.072l426.667 213.333c12.459 6.229 26.453 5.803 38.144 0l426.667-213.333c21.077-10.539 29.611-36.181 19.072-57.259-4.309-8.619-11.179-15.147-19.072-19.072l-426.667-213.333c-12.459-6.229-26.453-5.803-38.144 0zM66.261 763.477l426.667 213.333c12.459 6.229 26.453 5.803 38.144 0l426.667-213.333c21.077-10.539 29.611-36.181 19.072-57.259s-36.181-29.611-57.259-19.072l-407.552 203.819-407.595-203.776c-21.077-10.539-46.72-2.005-57.259 19.072s-2.005 46.72 19.072 57.259zM66.261 550.144l426.667 213.333c12.459 6.229 26.453 5.803 38.144 0l426.667-213.333c21.077-10.539 29.611-36.181 19.072-57.259s-36.181-29.611-57.259-19.072l-407.552 203.819-407.595-203.776c-21.077-10.539-46.72-2.005-57.259 19.072s-2.005 46.72 19.072 57.259z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["layers"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59656,"name":"layers"},"setIdx":0,"setId":3,"iconIdx":0},{"icon":{"paths":["M392.491 580.224c42.325 56.619 103.68 90.709 168.448 100.053s133.248-6.059 189.867-48.384c10.197-7.637 19.84-16 27.947-24.235l127.787-127.787c49.621-51.371 73.472-117.376 72.363-182.827s-27.264-130.603-78.123-179.669c-50.005-48.299-114.688-72.192-179.157-71.808-63.659 0.341-127.317 24.363-176.512 71.808l-73.856 73.429c-16.725 16.597-16.811 43.648-0.171 60.331s43.648 16.811 60.331 0.171l72.917-72.491c32.853-31.659 75.221-47.659 117.76-47.915 43.051-0.256 86.016 15.659 119.381 47.872 33.92 32.768 51.328 76.075 52.096 119.808s-15.147 87.637-47.36 121.003l-128.213 128.213c-4.864 4.949-11.221 10.539-18.261 15.787-37.76 28.245-83.285 38.485-126.592 32.256s-84.096-28.928-112.299-66.688c-14.123-18.859-40.832-22.741-59.733-8.619s-22.741 40.832-8.619 59.733zM631.509 443.776c-42.325-56.619-103.68-90.709-168.448-100.053s-133.291 6.059-189.909 48.384c-10.197 7.637-19.797 16-27.947 24.235l-127.787 127.787c-49.621 51.371-73.472 117.376-72.363 182.827s27.264 130.603 78.123 179.669c50.005 48.299 114.688 72.192 179.157 71.808 63.659-0.341 127.317-24.363 176.512-71.808l73.515-73.515c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-72.363 72.448c-32.853 31.659-75.221 47.659-117.76 47.915-43.051 0.256-86.016-15.659-119.381-47.872-33.92-32.768-51.328-76.075-52.096-119.808s15.147-87.637 47.36-121.003l128.213-128.213c4.864-4.949 11.221-10.539 18.261-15.787 37.76-28.245 83.285-38.485 126.592-32.256s84.096 28.928 112.299 66.688c14.123 18.859 40.832 22.741 59.733 8.619s22.741-40.832 8.619-59.733z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["link"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":24,"code":59655,"name":"link"},"setIdx":1,"setId":2,"iconIdx":0},{"icon":{"paths":["M213.333 85.333c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v597.333c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h597.333c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-597.333c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504zM853.333 341.333h-682.667v-128c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h597.333c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165zM341.333 426.667v426.667h-128c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-384zM426.667 853.333v-426.667h426.667v384c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["layout"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":1,"name":"layout","prevSize":24,"code":59648},"setIdx":1,"setId":2,"iconIdx":1},{"icon":{"paths":["M657.365 298.368l160.853-160.256c3.456-3.371 6.485-7.68 8.747-12.629 9.685-21.504 0.085-46.763-21.376-56.405-11.221-5.035-22.699-9.387-34.432-13.056-67.499-20.992-142.507-18.261-211.755 13.099-75.136 34.005-129.408 95.317-156.331 166.784-23.637 62.592-26.325 133.291-3.712 200.405l-275.072 275.072c-25.984 25.984-38.997 60.16-38.997 94.165s13.013 68.181 38.997 94.165 60.16 38.997 94.165 38.997 68.181-13.013 94.165-38.997l275.115-275.115c2.133 0.725 4.267 1.408 6.443 2.091 67.499 20.992 142.507 18.261 211.755-13.099 75.136-34.005 129.408-95.317 156.331-166.784s26.624-153.344-7.381-228.48c-1.92-4.395-4.864-8.747-8.704-12.587-16.683-16.683-43.691-16.683-60.331 0l-160.256 160.853zM596.736 238.933c-16.341 16.64-24.448 38.4-24.405 59.989 0.085 21.419 8.192 42.965 24.363 59.477l68.565 68.608c16.981 16.64 38.699 24.747 60.288 24.704 21.419-0.085 42.965-8.192 59.477-24.363l109.824-109.824c3.84 33.963-0.64 67.968-12.416 99.243-19.285 51.157-57.984 94.805-111.659 119.125-49.493 22.4-102.912 24.363-151.253 9.344-8.405-2.603-16.683-5.76-24.704-9.387-16.512-7.424-35.285-3.499-47.701 8.747l-294.827 294.827c-9.344 9.344-21.504 13.995-33.835 13.995s-24.491-4.651-33.835-13.995-13.995-21.504-13.995-33.835 4.651-24.491 13.995-33.835l294.827-294.827c12.843-12.843 15.787-31.829 8.704-47.744-24.277-53.675-24.533-112.043-5.248-163.2s57.984-94.805 111.659-119.125c36.352-16.469 74.88-21.888 111.915-17.621z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["tool"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":2,"name":"tool","prevSize":24,"code":59649},"setIdx":1,"setId":2,"iconIdx":2},{"icon":{"paths":["M469.333 469.333h-64c-29.483 0-56.064-11.904-75.435-31.232s-31.232-45.952-31.232-75.435 11.904-56.064 31.232-75.435 45.952-31.232 75.435-31.232h64zM554.667 554.667h64c29.483 0 56.064 11.904 75.435 31.232s31.232 45.952 31.232 75.435-11.904 56.064-31.232 75.435-45.952 31.232-75.435 31.232h-64zM725.333 170.667h-170.667v-128c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v128h-64c-52.992 0-101.077 21.547-135.765 56.235s-56.235 82.773-56.235 135.765 21.547 101.077 56.235 135.765 82.773 56.235 135.765 56.235h64v213.333h-213.333c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h213.333v128c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-128h64c52.992 0 101.077-21.547 135.765-56.235s56.235-82.773 56.235-135.765-21.547-101.077-56.235-135.765-82.773-56.235-135.765-56.235h-64v-213.333h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["dollar-sign"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":3,"name":"dollar-sign","prevSize":24,"code":59650},"setIdx":1,"setId":2,"iconIdx":3},{"icon":{"paths":["M487.339 298.667l94.848-164.267c77.867 14.379 147.499 52.267 201.344 106.069 17.749 17.749 33.792 37.248 47.829 58.197h-221.611zM314.88 426.667l-94.805-164.139c6.528-7.637 13.312-14.976 20.395-22.059 64-64 150.4-105.472 246.4-111.659l-110.592 191.573zM339.541 640h-189.696c-14.165-40.021-21.845-83.115-21.845-128 0-61.013 14.208-118.656 39.509-169.899l110.933 192.171zM745.515 489.728l-61.056-105.728h189.696c14.165 40.021 21.845 83.115 21.845 128 0 61.013-14.208 118.656-39.509 169.899l-109.909-190.379zM537.088 895.189l172.032-297.856 94.805 164.181c-6.528 7.595-13.312 14.976-20.395 22.016-64 64-150.4 105.472-246.4 111.659zM456.533 978.091c1.963 0.341 3.925 0.597 5.931 0.64 16.256 1.707 32.811 2.603 49.536 2.603 129.579 0 246.997-52.565 331.861-137.472 15.616-15.616 30.123-32.299 43.392-49.963 1.792-2.005 3.371-4.139 4.693-6.357 56.235-77.355 89.387-172.629 89.387-275.541 0-65.664-13.525-128.213-37.888-185.003-0.683-1.877-1.451-3.669-2.347-5.376-23.595-53.077-56.747-100.992-97.237-141.483-72.576-72.576-168.96-121.557-276.395-134.229-1.963-0.341-3.925-0.597-5.931-0.64-16.256-1.707-32.811-2.603-49.536-2.603-129.579 0-246.997 52.565-331.861 137.472-15.616 15.573-30.123 32.299-43.392 49.963-1.792 2.005-3.371 4.139-4.736 6.357-56.192 77.355-89.344 172.629-89.344 275.541 0 65.664 13.525 128.213 37.888 185.003 0.683 1.877 1.451 3.669 2.347 5.376 23.595 53.077 56.747 100.992 97.237 141.483 72.576 72.576 168.96 121.557 276.395 134.229zM536.661 725.333l-94.848 164.267c-77.867-14.379-147.499-52.267-201.344-106.069-17.749-17.749-33.792-37.248-47.829-58.197h221.611zM659.84 512l-73.899 128h-147.883l-73.899-128 73.899-128h147.883z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["aperture"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":4,"name":"aperture","prevSize":24,"code":59651},"setIdx":1,"setId":2,"iconIdx":4},{"icon":{"paths":["M981.333 512c0-129.579-52.565-246.997-137.472-331.861s-202.283-137.472-331.861-137.472-246.997 52.565-331.861 137.472-137.472 202.283-137.472 331.861 52.565 246.997 137.472 331.861 202.283 137.472 331.861 137.472 246.997-52.565 331.861-137.472 137.472-202.283 137.472-331.861zM896 512c0 106.069-42.923 201.984-112.469 271.531s-165.461 112.469-271.531 112.469-201.984-42.923-271.531-112.469-112.469-165.461-112.469-271.531 42.923-201.984 112.469-271.531 165.461-112.469 271.531-112.469 201.984 42.923 271.531 112.469 112.469 165.461 112.469 271.531zM469.333 256v256c0 16.597 9.472 31.019 23.595 38.144l170.667 85.333c21.077 10.539 46.72 2.005 57.259-19.072s2.005-46.72-19.072-57.259l-147.115-73.515v-229.632c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["clock"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":5,"name":"clock","prevSize":24,"code":59652},"setIdx":1,"setId":2,"iconIdx":5},{"icon":{"paths":["M170.667 384h682.667v469.333h-682.667zM42.667 85.333c-23.552 0-42.667 19.115-42.667 42.667v213.333c0 23.552 19.115 42.667 42.667 42.667h42.667v512c0 23.552 19.115 42.667 42.667 42.667h768c23.552 0 42.667-19.115 42.667-42.667v-512h42.667c23.552 0 42.667-19.115 42.667-42.667v-213.333c0-23.552-19.115-42.667-42.667-42.667zM85.333 170.667h853.333v128h-853.333zM426.667 554.667h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-170.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["archive"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":6,"name":"archive","prevSize":24,"code":59653},"setIdx":1,"setId":2,"iconIdx":6},{"icon":{"paths":["M189.995 398.251c31.445-88.875 95.872-156.544 174.763-194.219s172.032-45.184 260.864-13.739c50.603 17.92 94.123 46.421 127.275 80.213l120.747 113.493h-148.309c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h255.872c0.213 0 0.384 0 0.597 0 5.845-0.043 11.435-1.323 16.469-3.499 5.077-2.176 9.771-5.376 13.824-9.6 0.512-0.555 1.024-1.109 1.536-1.664 3.2-3.712 5.675-7.808 7.381-12.16s2.731-9.003 2.944-13.909c0.043-0.64 0.043-1.237 0.043-1.835v-256c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v157.397l-124.843-117.291c-42.325-43.093-96.896-78.635-159.701-100.864-111.061-39.296-227.627-29.824-326.101 17.152s-179.157 131.669-218.453 242.731c-7.893 22.187 3.755 46.549 25.941 54.443s46.592-3.755 54.443-25.984zM85.333 695.979l126.080 118.485c82.304 82.389 191.573 124.075 300.715 124.117s218.411-41.6 301.739-124.885c47.104-47.104 81.109-102.699 100.736-159.787 7.68-22.272-4.181-46.549-26.496-54.229s-46.549 4.181-54.229 26.496c-15.403 44.8-42.368 89.216-80.341 127.189-66.688 66.645-153.984 99.925-241.365 99.925s-174.677-33.365-242.304-100.949l-119.467-112.341h148.267c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-255.872c-0.213 0-0.384 0-0.597 0-5.845 0.043-11.435 1.323-16.469 3.499-5.077 2.176-9.771 5.376-13.824 9.6-0.512 0.555-1.024 1.109-1.536 1.664-3.2 3.712-5.675 7.808-7.381 12.16s-2.731 9.003-2.944 13.909c-0.043 0.64-0.043 1.237-0.043 1.835v256c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["refresh-cw"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":7,"name":"refresh-cw","prevSize":24,"code":59654},"setIdx":1,"setId":2,"iconIdx":7}],"height":1024,"metadata":{"name":"stylify-profiler"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"sp-icon-","metadata":{"fontFamily":"stylify-profiler","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"noie8":true,"ie7":false,"showSelector":true,"selector":"class","classSelector":".sp-icon","showMetrics":false,"showMetadata":false,"showVersion":false,"cssVars":false,"cssVarsFormat":"scss"},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon"},"historySize":50,"showCodes":true,"gridSize":16}} \ No newline at end of file +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M938.667 469.333h-170.667c-18.731 0-34.645 12.075-40.491 29.184l-87.509 262.571-215.509-646.571c-7.467-22.357-31.616-34.432-53.973-27.008-13.227 4.395-22.827 14.635-27.008 27.008l-118.272 354.816h-139.904c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h170.667c18.048-0.128 34.56-11.392 40.491-29.184l87.509-262.571 215.509 646.571c4.181 12.373 13.781 22.571 26.965 26.965 22.357 7.467 46.507-4.651 53.973-26.965l118.315-354.816h139.904c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["activity"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":4,"prevSize":24,"code":59662,"name":"activity"},"setIdx":0,"setId":4,"iconIdx":0},{"icon":{"paths":["M981.333 512c0-129.579-52.565-246.997-137.472-331.861s-202.283-137.472-331.861-137.472-246.997 52.565-331.861 137.472-137.472 202.283-137.472 331.861 52.565 246.997 137.472 331.861 202.283 137.472 331.861 137.472 246.997-52.565 331.861-137.472 137.472-202.283 137.472-331.861zM896 512c0 106.069-42.923 201.984-112.469 271.531s-165.461 112.469-271.531 112.469-201.984-42.923-271.531-112.469-112.469-165.461-112.469-271.531 42.923-201.984 112.469-271.531 165.461-112.469 271.531-112.469 201.984 42.923 271.531 112.469 112.469 165.461 112.469 271.531z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["circle"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":3,"prevSize":24,"code":59661,"name":"circle"},"setIdx":0,"setId":4,"iconIdx":1},{"icon":{"paths":["M981.333 512c0-129.579-52.565-246.997-137.472-331.861s-202.283-137.472-331.861-137.472-246.997 52.565-331.861 137.472-137.472 202.283-137.472 331.861 52.565 246.997 137.472 331.861 202.283 137.472 331.861 137.472 246.997-52.565 331.861-137.472 137.472-202.283 137.472-331.861zM896 512c0 106.069-42.923 201.984-112.469 271.531s-165.461 112.469-271.531 112.469-201.984-42.923-271.531-112.469-112.469-165.461-112.469-271.531 42.923-201.984 112.469-271.531 165.461-112.469 271.531-112.469 201.984 42.923 271.531 112.469 112.469 165.461 112.469 271.531zM469.333 256v256c0 16.597 9.472 31.019 23.595 38.144l170.667 85.333c21.077 10.539 46.72 2.005 57.259-19.072s2.005-46.72-19.072-57.259l-147.115-73.515v-229.632c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["clock"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":2,"name":"clock","prevSize":24,"code":59658},"setIdx":0,"setId":4,"iconIdx":2},{"icon":{"paths":["M128 554.667h768c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-768c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM128 298.667h768c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-768c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667zM128 810.667h768c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-768c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["menu"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":1,"name":"menu","prevSize":24,"code":59659},"setIdx":0,"setId":4,"iconIdx":3},{"icon":{"paths":["M225.835 286.165l225.835 225.835-225.835 225.835c-16.683 16.683-16.683 43.691 0 60.331s43.691 16.683 60.331 0l225.835-225.835 225.835 225.835c16.683 16.683 43.691 16.683 60.331 0s16.683-43.691 0-60.331l-225.835-225.835 225.835-225.835c16.683-16.683 16.683-43.691 0-60.331s-43.691-16.683-60.331 0l-225.835 225.835-225.835-225.835c-16.683-16.683-43.691-16.683-60.331 0s-16.683 43.691 0 60.331z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["x"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"name":"x","prevSize":24,"code":59660},"setIdx":0,"setId":4,"iconIdx":4},{"icon":{"paths":["M908.672 602.325c24.875-25.003 37.291-57.685 37.291-90.24 0.043-32.597-12.373-65.365-37.291-90.453l-366.507-366.507c-7.723-7.68-18.389-12.459-30.165-12.459h-426.667c-23.552 0-42.667 19.115-42.667 42.667v426.667c0 10.923 4.181 21.845 12.501 30.208l366.592 366.165c25.003 24.96 57.856 37.461 90.539 37.419s65.536-12.544 90.453-37.504zM848.341 541.995l-305.92 305.92c-8.363 8.363-19.2 12.544-30.165 12.544s-21.845-4.139-30.165-12.459l-354.091-353.707v-366.293h366.336l354.005 354.005c8.192 8.235 12.331 19.072 12.331 30.037 0 10.923-4.139 21.717-12.331 29.952zM298.667 341.333c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667-42.667 19.115-42.667 42.667 19.115 42.667 42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["tag"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":0,"name":"tag","prevSize":24,"code":59654},"setIdx":2,"setId":2,"iconIdx":0},{"icon":{"paths":["M682.667 512c0-47.104-19.157-89.856-50.005-120.661s-73.557-50.005-120.661-50.005-89.856 19.157-120.661 50.005-50.005 73.557-50.005 120.661 19.157 89.856 50.005 120.661 73.557 50.005 120.661 50.005 89.856-19.157 120.661-50.005 50.005-73.557 50.005-120.661zM597.333 512c0 23.595-9.515 44.843-25.003 60.331s-36.736 25.003-60.331 25.003-44.843-9.515-60.331-25.003-25.003-36.736-25.003-60.331 9.515-44.843 25.003-60.331 36.736-25.003 60.331-25.003 44.843 9.515 60.331 25.003 25.003 36.736 25.003 60.331zM866.773 657.237c1.963-4.48 4.779-8.149 8.192-10.965 4.779-3.925 10.709-6.229 17.195-6.272h3.84c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496-14.379-67.413-37.504-90.496-55.168-37.504-90.496-37.504h-6.784c-4.693-0.043-9.173-1.195-13.141-3.243-5.419-2.816-9.813-7.339-12.459-13.312-0.128-1.237-0.171-2.517-0.171-3.797-1.024-2.347-1.707-4.736-2.091-7.168 0.853-14.251 3.285-19.371 7.168-23.339l2.645-2.645c24.96-25.003 37.461-57.856 37.419-90.539s-12.544-65.536-37.589-90.539c-25.003-24.96-57.856-37.461-90.539-37.419s-65.536 12.544-90.453 37.504l-1.963 1.963c-3.541 3.413-7.808 5.803-12.288 7.083-5.973 1.664-12.416 1.365-18.688-1.408-4.309-1.877-7.979-4.693-10.795-8.107-3.925-4.779-6.229-10.709-6.272-17.195v-3.84c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504-67.413 14.379-90.496 37.504-37.504 55.168-37.504 90.496v6.784c-0.043 4.693-1.195 9.173-3.243 13.141-2.816 5.419-7.339 9.813-13.312 12.459-1.237 0.128-2.517 0.171-3.797 0.171-2.347 1.024-4.736 1.707-7.168 2.091-14.293-0.896-19.413-3.328-23.381-7.211l-2.645-2.645c-25.003-24.96-57.813-37.461-90.539-37.461s-65.493 12.544-90.539 37.632c-24.96 25.003-37.461 57.813-37.461 90.539s12.544 65.536 37.504 90.453l2.048 2.005c3.413 3.541 5.803 7.808 7.083 12.288 1.664 5.973 1.365 12.416-1.323 18.517-0.256 0.683-0.555 1.451-0.896 2.219-1.749 4.651-4.608 8.661-8.149 11.733-4.693 4.053-10.667 6.528-16.341 6.656h-3.84c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.211-37.504 90.539 14.379 67.413 37.504 90.496 55.168 37.504 90.496 37.504h6.784c4.693 0.043 9.173 1.195 13.141 3.243 5.461 2.859 9.941 7.424 12.629 13.696 1.024 2.347 1.707 4.736 2.091 7.168-0.853 14.251-3.285 19.371-7.168 23.339l-2.645 2.645c-24.96 25.003-37.461 57.856-37.419 90.539s12.544 65.536 37.589 90.539c25.003 24.96 57.856 37.461 90.539 37.419s65.536-12.544 90.453-37.504l2.005-2.048c3.541-3.413 7.808-5.803 12.288-7.083 5.973-1.664 12.416-1.365 18.517 1.323 0.683 0.256 1.451 0.555 2.219 0.896 4.651 1.749 8.661 4.608 11.733 8.149 4.053 4.693 6.528 10.667 6.656 16.341v3.925c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504 67.413-14.379 90.496-37.504 37.504-55.168 37.504-90.496v-6.784c0.043-4.693 1.195-9.173 3.243-13.141 2.859-5.461 7.424-9.941 13.696-12.629 2.347-1.024 4.736-1.707 7.168-2.091 14.251 0.853 19.371 3.285 23.339 7.168l2.645 2.645c25.003 24.96 57.856 37.461 90.539 37.419s65.536-12.544 90.539-37.589c24.96-25.003 37.461-57.856 37.419-90.539s-12.544-65.536-37.504-90.453l-2.048-2.005c-3.413-3.541-5.803-7.808-7.083-12.288-1.664-5.973-1.365-12.416 1.323-18.517zM784.896 396.885c-0.512-8.576-1.621-12.672-3.243-16.299v3.413c0 1.835 0.128 3.584 0.341 5.333 0.896 2.56 1.835 5.077 2.901 7.552 0.171 3.84 0.213 3.883 0.213 3.925 10.624 24.789 29.184 43.947 51.541 55.595 15.829 8.235 33.493 12.715 51.669 12.928h7.68c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165-4.736 22.4-12.501 30.165-18.389 12.501-30.165 12.501h-3.84c-27.179 0.128-52.053 9.728-71.467 25.728-13.781 11.349-24.789 25.899-32 42.368-10.965 24.832-12.288 51.627-5.419 76.032 5.077 18.048 14.549 34.731 27.819 48.469l3.072 3.115c8.363 8.363 12.544 19.2 12.544 30.165s-4.139 21.845-12.459 30.165c-8.405 8.405-19.243 12.587-30.251 12.587s-21.845-4.139-30.165-12.459l-2.603-2.603c-19.755-19.328-44.373-29.952-69.632-32.085-18.645-1.579-37.632 1.451-55.168 9.045-24.661 10.581-43.819 29.141-55.467 51.456-8.235 15.829-12.715 33.493-12.928 51.669v7.723c0 11.776-4.736 22.4-12.501 30.165s-18.347 12.459-30.123 12.459-22.4-4.736-30.165-12.501-12.501-18.389-12.501-30.165v-3.84c-0.64-28.16-10.88-52.992-27.477-72.192-12.117-13.995-27.563-24.96-45.141-31.744-24.533-10.539-50.901-11.691-74.923-4.949-18.048 5.077-34.731 14.549-48.469 27.819l-3.115 3.072c-8.363 8.363-19.2 12.544-30.165 12.544s-21.845-4.139-30.165-12.459c-8.405-8.405-12.587-19.243-12.587-30.251s4.139-21.845 12.459-30.165l2.603-2.603c19.328-19.755 29.952-44.373 32.085-69.632 1.579-18.645-1.451-37.632-9.045-55.168-10.581-24.661-29.141-43.819-51.456-55.467-15.829-8.235-33.493-12.715-51.669-12.928l-7.68 0.043c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165 4.736-22.4 12.501-30.165 18.389-12.501 30.165-12.501h3.84c28.16-0.64 52.992-10.88 72.192-27.477 13.995-12.117 24.96-27.563 31.744-45.141 10.539-24.533 11.691-50.901 4.949-74.923-5.077-18.048-14.549-34.731-27.819-48.469l-3.115-3.115c-8.363-8.363-12.544-19.2-12.544-30.165s4.139-21.845 12.459-30.165c8.405-8.405 19.243-12.587 30.251-12.587s21.845 4.139 30.165 12.459l2.603 2.603c19.755 19.328 44.373 29.952 69.632 32.085 15.787 1.365 31.787-0.597 46.976-5.845 4.096-0.512 7.936-1.536 11.349-3.072-1.323 0.043-2.603 0.128-3.797 0.171-8.576 0.512-12.672 1.621-16.299 3.243h3.413c1.835 0 3.584-0.128 5.333-0.341 2.56-0.896 5.077-1.835 7.552-2.901 3.84-0.171 3.883-0.213 3.925-0.213 24.789-10.624 43.947-29.184 55.595-51.541 8.235-15.787 12.715-33.493 12.928-51.627v-7.723c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501 22.4 4.736 30.165 12.501 12.501 18.389 12.501 30.165v3.84c0.128 27.179 9.728 52.053 25.728 71.467 11.349 13.781 25.899 24.789 42.496 32.043 24.661 10.88 51.456 12.203 75.861 5.333 18.048-5.077 34.731-14.549 48.469-27.819l3.115-3.072c8.363-8.363 19.2-12.544 30.165-12.544s21.845 4.139 30.165 12.459c8.405 8.405 12.587 19.243 12.587 30.251s-4.139 21.845-12.459 30.165l-2.603 2.603c-19.328 19.755-29.952 44.373-32.085 69.632-1.365 15.787 0.597 31.787 5.845 46.976 0.512 4.053 1.579 7.893 3.072 11.349-0.043-1.365-0.085-2.645-0.171-3.797z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["settings"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":1,"name":"settings","prevSize":24,"code":59655},"setIdx":2,"setId":2,"iconIdx":1},{"icon":{"paths":["M101.803 350.336c-10.069 7.851-16.469 20.011-16.469 33.664v469.333c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h597.333c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-469.333c-0.043-12.8-5.717-25.301-16.469-33.664l-384-298.667c-15.275-11.733-36.736-12.16-52.395 0zM682.667 896v-384c0-23.552-19.115-42.667-42.667-42.667h-256c-23.552 0-42.667 19.115-42.667 42.667v384h-128c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-448.469l341.333-265.472 341.333 265.472v448.469c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501zM426.667 896v-341.333h170.667v341.333z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["home"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":2,"name":"home","prevSize":24,"code":59657},"setIdx":2,"setId":2,"iconIdx":2},{"icon":{"paths":["M512 133.035l331.264 165.632-331.264 165.632-331.264-165.632zM492.928 47.189l-426.667 213.333c-21.077 10.539-29.611 36.139-19.072 57.216 4.309 8.661 11.136 15.189 19.072 19.072l426.667 213.333c12.459 6.229 26.453 5.803 38.144 0l426.667-213.333c21.077-10.539 29.611-36.181 19.072-57.259-4.309-8.619-11.179-15.147-19.072-19.072l-426.667-213.333c-12.459-6.229-26.453-5.803-38.144 0zM66.261 763.477l426.667 213.333c12.459 6.229 26.453 5.803 38.144 0l426.667-213.333c21.077-10.539 29.611-36.181 19.072-57.259s-36.181-29.611-57.259-19.072l-407.552 203.819-407.595-203.776c-21.077-10.539-46.72-2.005-57.259 19.072s-2.005 46.72 19.072 57.259zM66.261 550.144l426.667 213.333c12.459 6.229 26.453 5.803 38.144 0l426.667-213.333c21.077-10.539 29.611-36.181 19.072-57.259s-36.181-29.611-57.259-19.072l-407.552 203.819-407.595-203.776c-21.077-10.539-46.72-2.005-57.259 19.072s-2.005 46.72 19.072 57.259z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["layers"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":3,"prevSize":24,"code":59656,"name":"layers"},"setIdx":2,"setId":2,"iconIdx":3},{"icon":{"paths":["M213.333 85.333c-35.328 0-67.413 14.379-90.496 37.504s-37.504 55.168-37.504 90.496v597.333c0 35.328 14.379 67.413 37.504 90.496s55.168 37.504 90.496 37.504h597.333c35.328 0 67.413-14.379 90.496-37.504s37.504-55.168 37.504-90.496v-597.333c0-35.328-14.379-67.413-37.504-90.496s-55.168-37.504-90.496-37.504zM853.333 341.333h-682.667v-128c0-11.776 4.736-22.4 12.501-30.165s18.389-12.501 30.165-12.501h597.333c11.776 0 22.4 4.736 30.165 12.501s12.501 18.389 12.501 30.165zM341.333 426.667v426.667h-128c-11.776 0-22.4-4.736-30.165-12.501s-12.501-18.389-12.501-30.165v-384zM426.667 853.333v-426.667h426.667v384c0 11.776-4.736 22.4-12.501 30.165s-18.389 12.501-30.165 12.501z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["layout"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":4,"name":"layout","prevSize":24,"code":59648},"setIdx":2,"setId":2,"iconIdx":4},{"icon":{"paths":["M657.365 298.368l160.853-160.256c3.456-3.371 6.485-7.68 8.747-12.629 9.685-21.504 0.085-46.763-21.376-56.405-11.221-5.035-22.699-9.387-34.432-13.056-67.499-20.992-142.507-18.261-211.755 13.099-75.136 34.005-129.408 95.317-156.331 166.784-23.637 62.592-26.325 133.291-3.712 200.405l-275.072 275.072c-25.984 25.984-38.997 60.16-38.997 94.165s13.013 68.181 38.997 94.165 60.16 38.997 94.165 38.997 68.181-13.013 94.165-38.997l275.115-275.115c2.133 0.725 4.267 1.408 6.443 2.091 67.499 20.992 142.507 18.261 211.755-13.099 75.136-34.005 129.408-95.317 156.331-166.784s26.624-153.344-7.381-228.48c-1.92-4.395-4.864-8.747-8.704-12.587-16.683-16.683-43.691-16.683-60.331 0l-160.256 160.853zM596.736 238.933c-16.341 16.64-24.448 38.4-24.405 59.989 0.085 21.419 8.192 42.965 24.363 59.477l68.565 68.608c16.981 16.64 38.699 24.747 60.288 24.704 21.419-0.085 42.965-8.192 59.477-24.363l109.824-109.824c3.84 33.963-0.64 67.968-12.416 99.243-19.285 51.157-57.984 94.805-111.659 119.125-49.493 22.4-102.912 24.363-151.253 9.344-8.405-2.603-16.683-5.76-24.704-9.387-16.512-7.424-35.285-3.499-47.701 8.747l-294.827 294.827c-9.344 9.344-21.504 13.995-33.835 13.995s-24.491-4.651-33.835-13.995-13.995-21.504-13.995-33.835 4.651-24.491 13.995-33.835l294.827-294.827c12.843-12.843 15.787-31.829 8.704-47.744-24.277-53.675-24.533-112.043-5.248-163.2s57.984-94.805 111.659-119.125c36.352-16.469 74.88-21.888 111.915-17.621z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["tool"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":5,"name":"tool","prevSize":24,"code":59649},"setIdx":2,"setId":2,"iconIdx":5},{"icon":{"paths":["M469.333 469.333h-64c-29.483 0-56.064-11.904-75.435-31.232s-31.232-45.952-31.232-75.435 11.904-56.064 31.232-75.435 45.952-31.232 75.435-31.232h64zM554.667 554.667h64c29.483 0 56.064 11.904 75.435 31.232s31.232 45.952 31.232 75.435-11.904 56.064-31.232 75.435-45.952 31.232-75.435 31.232h-64zM725.333 170.667h-170.667v-128c0-23.552-19.115-42.667-42.667-42.667s-42.667 19.115-42.667 42.667v128h-64c-52.992 0-101.077 21.547-135.765 56.235s-56.235 82.773-56.235 135.765 21.547 101.077 56.235 135.765 82.773 56.235 135.765 56.235h64v213.333h-213.333c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667h213.333v128c0 23.552 19.115 42.667 42.667 42.667s42.667-19.115 42.667-42.667v-128h64c52.992 0 101.077-21.547 135.765-56.235s56.235-82.773 56.235-135.765-21.547-101.077-56.235-135.765-82.773-56.235-135.765-56.235h-64v-213.333h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["dollar-sign"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":6,"name":"dollar-sign","prevSize":24,"code":59650},"setIdx":2,"setId":2,"iconIdx":6},{"icon":{"paths":["M170.667 384h682.667v469.333h-682.667zM42.667 85.333c-23.552 0-42.667 19.115-42.667 42.667v213.333c0 23.552 19.115 42.667 42.667 42.667h42.667v512c0 23.552 19.115 42.667 42.667 42.667h768c23.552 0 42.667-19.115 42.667-42.667v-512h42.667c23.552 0 42.667-19.115 42.667-42.667v-213.333c0-23.552-19.115-42.667-42.667-42.667zM85.333 170.667h853.333v128h-853.333zM426.667 554.667h170.667c23.552 0 42.667-19.115 42.667-42.667s-19.115-42.667-42.667-42.667h-170.667c-23.552 0-42.667 19.115-42.667 42.667s19.115 42.667 42.667 42.667z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["archive"],"grid":24},"attrs":[{}],"properties":{"order":1,"id":7,"name":"archive","prevSize":24,"code":59653},"setIdx":2,"setId":2,"iconIdx":7},{"icon":{"paths":["M608 416h320.183c52.919 0 95.817 42.963 95.817 95.961v224.078c0 53.009-42.899 95.961-95.817 95.961h-320.183v64.295c0 34.963-28.617 63.705-63.918 63.705h-480.165c-35.408 0-63.918-28.759-63.918-64.235v-735.531c0-35.488 28.693-64.235 64.088-64.235h351.912l192 224v96zM576 832h-384.183c-52.919 0-95.817-42.963-95.817-95.961v-224.078c0-53.009 42.899-95.961 95.817-95.961h384.183v-64h-128.067c-35.309 0-63.933-28.37-63.933-64.189v-159.811h-320.142c-17.595 0-31.858 14.568-31.858 31.855v736.291c0 17.593 14.551 31.855 31.999 31.855h480.003c17.672 0 31.999-14.238 31.999-31.789v-64.211zM416 144v143.719c0 17.828 14.421 32.281 31.896 32.281h118.503l-150.398-176zM192.235 448c-35.476 0-64.235 28.806-64.235 63.745v224.511c0 35.205 28.747 63.745 64.235 63.745h735.531c35.476 0 64.235-28.806 64.235-63.745v-224.511c0-35.205-28.747-63.745-64.235-63.745h-735.531zM928 704v32h-160v-224h32v192h128zM448 544v192h32v-192h64v-32h-160v32h64zM320 608v-96h32v224h-32v-96h-96v96h-32v-224h32v96h96zM656 608l-48-96h-32v224h32v-160l32 64h32l32-64v160h32v-224h-32l-48 96z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-file-html"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":0,"name":"document-file-html","prevSize":32,"code":59651},"setIdx":1,"setId":3,"iconIdx":0},{"icon":{"paths":["M672 416v-96l-192-224h-351.912c-35.395 0-64.088 28.747-64.088 64.235v735.531c0 35.476 28.51 64.235 63.918 64.235h480.165c35.301 0 63.918-28.743 63.918-63.705v-64.295h255.781c53.14 0 96.219-42.952 96.219-95.961v-224.078c0-52.998-42.752-95.961-96.219-95.961h-255.781zM640 832v64.211c0 17.55-14.326 31.789-31.999 31.789h-480.003c-17.448 0-31.999-14.262-31.999-31.855v-736.291c0-17.286 14.264-31.855 31.858-31.855h320.142v159.811c0 35.82 28.624 64.189 63.933 64.189h128.067v64h-255.781c-53.14 0-96.219 42.952-96.219 95.961v224.078c0 52.998 42.752 95.961 96.219 95.961h255.781zM480 144l150.398 176h-118.503c-17.475 0-31.896-14.453-31.896-32.281v-143.719zM383.826 448h544.348c34.951 0 63.826 28.539 63.826 63.745v224.511c0 34.939-28.576 63.745-63.826 63.745h-544.348c-34.951 0-63.826-28.539-63.826-63.745v-224.511c0-34.939 28.576-63.745 63.826-63.745zM544 672c-0.101 35.73-28.786 64-64.156 64h-31.688c-35.551 0-64.156-28.739-64.156-64.189v-95.621c0-35.82 28.724-64.189 64.156-64.189h31.688c35.488 0 64.054 28.636 64.156 64h-32c0-17.676-14.165-32-31.967-32h-32.067c-17.655 0-31.967 14.199-31.967 31.994v96.012c0 17.67 14.165 31.994 31.967 31.994h32.067c17.655 0 31.967-14.199 31.967-31.994l32-0.006zM640.156 512c-35.432 0-64.156 28.407-64.156 64 0 35.346 28.407 64 64 64h31.7c17.839 0 32.3 14.204 32.3 32 0 17.673-14.165 32-31.967 32h-32.067c-17.655 0-31.967-14.601-31.967-31.857v-0.362h-32v0.184c0 35.365 28.605 64.035 64.156 64.035h31.688c35.432 0 64.156-28.407 64.156-64 0-35.346-28.407-64-64-64h-31.7c-17.839 0-32.3-14.204-32.3-32 0-17.673 14.165-32 31.967-32h32.067c17.655 0 31.967 14.502 31.967 32h32c0-35.346-28.605-64-64.156-64h-31.688zM832.156 512c-35.432 0-64.156 28.407-64.156 64 0 35.346 28.407 64 64 64h31.7c17.839 0 32.3 14.204 32.3 32 0 17.673-14.165 32-31.967 32h-32.067c-17.655 0-31.967-14.601-31.967-31.857v-0.362h-32v0.184c0 35.365 28.605 64.035 64.156 64.035h31.688c35.432 0 64.156-28.407 64.156-64 0-35.346-28.407-64-64-64h-31.7c-17.839 0-32.3-14.204-32.3-32 0-17.673 14.165-32 31.967-32h32.067c17.655 0 31.967 14.502 31.967 32h32c0-35.346-28.605-64-64.156-64h-31.688z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["document-file-css"],"grid":32},"attrs":[{}],"properties":{"order":1,"id":1,"name":"document-file-css","prevSize":32,"code":59652},"setIdx":1,"setId":3,"iconIdx":1}],"height":1024,"metadata":{"name":"stylify-profiler"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"sp-icon-","metadata":{"fontFamily":"stylify-profiler","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"noie8":true,"ie7":false,"showSelector":true,"selector":"class","classSelector":".sp-icon","showMetrics":false,"showMetadata":false,"showVersion":false,"cssVars":false,"cssVarsFormat":"scss"},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon"},"historySize":50,"showCodes":true,"gridSize":16}} \ No newline at end of file diff --git a/packages/profiler/src/assets/icons/style.css b/packages/profiler/src/assets/icons/style.css index 265632ef..02285076 100644 --- a/packages/profiler/src/assets/icons/style.css +++ b/packages/profiler/src/assets/icons/style.css @@ -1,6 +1,6 @@ @font-face { font-family: 'stylify-profiler'; - src: url('assets/icons/fonts/stylify-profiler.woff?v857gh') format('woff'); + src: url('assets/icons/fonts/stylify-profiler.woff?72d9tc') format('woff'); font-weight: normal; font-style: normal; font-display: block; @@ -21,12 +21,33 @@ -moz-osx-font-smoothing: grayscale; } -.sp-icon-layers:before { - content: "\e908"; +.sp-icon-activity:before { + content: "\e90e"; +} +.sp-icon-circle:before { + content: "\e90d"; +} +.sp-icon-clock:before { + content: "\e90a"; +} +.sp-icon-menu:before { + content: "\e90b"; } -.sp-icon-link:before { +.sp-icon-x:before { + content: "\e90c"; +} +.sp-icon-tag:before { + content: "\e906"; +} +.sp-icon-settings:before { content: "\e907"; } +.sp-icon-home:before { + content: "\e909"; +} +.sp-icon-layers:before { + content: "\e908"; +} .sp-icon-layout:before { content: "\e900"; } @@ -36,15 +57,12 @@ .sp-icon-dollar-sign:before { content: "\e902"; } -.sp-icon-aperture:before { - content: "\e903"; -} -.sp-icon-clock:before { - content: "\e904"; -} .sp-icon-archive:before { content: "\e905"; } -.sp-icon-refresh-cw:before { - content: "\e906"; +.sp-icon-document-file-html:before { + content: "\e903"; +} +.sp-icon-document-file-css:before { + content: "\e904"; } diff --git a/packages/profiler/src/assets/normalize.scss b/packages/profiler/src/assets/normalize.scss new file mode 100644 index 00000000..2bf05b27 --- /dev/null +++ b/packages/profiler/src/assets/normalize.scss @@ -0,0 +1,352 @@ +#stylify-profiler { + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + + /* Document + ========================================================================== */ + + /** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + + + html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + } + + /* Sections + ========================================================================== */ + + /** + * Remove the margin in all browsers. + */ + + body { + margin: 0; + } + + /** + * Render the `main` element consistently in IE. + */ + + main { + display: block; + } + + /** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + + h1 { + font-size: 2em; + margin: 0.67em 0; + } + + /* Grouping content + ========================================================================== */ + + /** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + + hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ + } + + /** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + + pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ + } + + /* Text-level semantics + ========================================================================== */ + + /** + * Remove the gray background on active links in IE 10. + */ + + a { + background-color: transparent; + } + + /** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + + abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ + } + + /** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + + b, + strong { + font-weight: bolder; + } + + /** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + + code, + kbd, + samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ + } + + /** + * Add the correct font size in all browsers. + */ + + small { + font-size: 80%; + } + + /** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + + sub, + sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; + } + + sub { + bottom: -0.25em; + } + + sup { + top: -0.5em; + } + + /* Embedded content + ========================================================================== */ + + /** + * Remove the border on images inside links in IE 10. + */ + + img { + border-style: none; + } + + /* Forms + ========================================================================== */ + + /** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + + button, + input, + optgroup, + select, + textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ + } + + /** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + + button, + input { /* 1 */ + overflow: visible; + } + + /** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + + button, + select { /* 1 */ + text-transform: none; + } + + /** + * Correct the inability to style clickable types in iOS and Safari. + */ + + button, + [type="button"], + [type="reset"], + [type="submit"] { + -webkit-appearance: button; + } + + /** + * Remove the inner border and padding in Firefox. + */ + + button::-moz-focus-inner, + [type="button"]::-moz-focus-inner, + [type="reset"]::-moz-focus-inner, + [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; + } + + /** + * Restore the focus styles unset by the previous rule. + */ + + button:-moz-focusring, + [type="button"]:-moz-focusring, + [type="reset"]:-moz-focusring, + [type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; + } + + /** + * Correct the padding in Firefox. + */ + + fieldset { + padding: 0.35em 0.75em 0.625em; + } + + /** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + + legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ + } + + /** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + + progress { + vertical-align: baseline; + } + + /** + * Remove the default vertical scrollbar in IE 10+. + */ + + textarea { + overflow: auto; + } + + /** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + + [type="checkbox"], + [type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ + } + + /** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + + [type="number"]::-webkit-inner-spin-button, + [type="number"]::-webkit-outer-spin-button { + height: auto; + } + + /** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + + [type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ + } + + /** + * Remove the inner padding in Chrome and Safari on macOS. + */ + + [type="search"]::-webkit-search-decoration { + -webkit-appearance: none; + } + + /** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + + ::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ + } + + /* Interactive + ========================================================================== */ + + /* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + + details { + display: block; + } + + /* + * Add the correct display in all browsers. + */ + + summary { + display: list-item; + } + + /* Misc + ========================================================================== */ + + /** + * Add the correct display in IE 10+. + */ + + template { + display: none; + } + + /** + * Add the correct display in IE 10. + */ + + [hidden] { + display: none; + } +} diff --git a/packages/profiler/src/assets/style.css b/packages/profiler/src/assets/style.css new file mode 100644 index 00000000..0f083a71 --- /dev/null +++ b/packages/profiler/src/assets/style.css @@ -0,0 +1,56 @@ +@font-face { + font-family: 'stylify-profiler'; + src: + url('fonts/stylify-profiler.ttf?y8f5zi') format('truetype'), + url('fonts/stylify-profiler.woff?y8f5zi') format('woff'), + url('fonts/stylify-profiler.svg?y8f5zi#stylify-profiler') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +.sp-icon { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'stylify-profiler' !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.sp-icon-document-file-html:before { + content: "\e903"; +} +.sp-icon-document-file-css:before { + content: "\e904"; +} +.sp-icon-tag:before { + content: "\e906"; +} +.sp-icon-settings:before { + content: "\e907"; +} +.sp-icon-home:before { + content: "\e909"; +} +.sp-icon-layers:before { + content: "\e908"; +} +.sp-icon-layout:before { + content: "\e900"; +} +.sp-icon-tool:before { + content: "\e901"; +} +.sp-icon-dollar-sign:before { + content: "\e902"; +} +.sp-icon-archive:before { + content: "\e905"; +} diff --git a/packages/profiler/src/index.ts b/packages/profiler/src/index.ts index 77a484e3..62e5f279 100644 --- a/packages/profiler/src/index.ts +++ b/packages/profiler/src/index.ts @@ -1 +1,4 @@ +export * from './Utils'; +export * from './styledElements'; export * from './Profiler'; +export * from './Toolbar'; diff --git a/packages/profiler/src/profiler.scss b/packages/profiler/src/profiler.scss index 6eba770c..c7e3766c 100644 --- a/packages/profiler/src/profiler.scss +++ b/packages/profiler/src/profiler.scss @@ -1,2 +1,3 @@ +@import './assets/normalize'; @import './assets/icons/style'; @import './assets/profiler'; diff --git a/packages/profiler/src/styledElements/cardElements.tsx b/packages/profiler/src/styledElements/cardElements.tsx new file mode 100644 index 00000000..b0e0c135 --- /dev/null +++ b/packages/profiler/src/styledElements/cardElements.tsx @@ -0,0 +1,16 @@ +import { HideableElement, HideableElementPropsInterface, PropsInterface } from '.'; +import { JSXInternal } from 'preact/src/jsx'; + +export const Card = (props: HideableElementPropsInterface): JSXInternal.Element => { + return ( + +
+ {props.children} +
+
+ ); +}; + +export const CardTitle = (props: PropsInterface): JSXInternal.Element => { + return

{props.children}

; +}; diff --git a/packages/profiler/src/styledElements/index.ts b/packages/profiler/src/styledElements/index.ts new file mode 100644 index 00000000..0cbf6fd2 --- /dev/null +++ b/packages/profiler/src/styledElements/index.ts @@ -0,0 +1,5 @@ +export * from './props'; +export * from './inlineCardElements'; +export * from './tableElements'; +export * from './visibilityElements'; +export * from './cardElements'; diff --git a/packages/profiler/src/styledElements/inlineCardElements.tsx b/packages/profiler/src/styledElements/inlineCardElements.tsx new file mode 100644 index 00000000..f1d46e8b --- /dev/null +++ b/packages/profiler/src/styledElements/inlineCardElements.tsx @@ -0,0 +1,42 @@ +import { HideableElement, HideableElementPropsInterface, PropsInterface } from '.'; +import { JSXInternal } from 'preact/src/jsx'; + +export const InlineCard = (props: HideableElementPropsInterface): JSXInternal.Element => { + return ( + +
+ {props.children} +
+
+ ); +}; + +export const InlineCardTitle = (props: PropsInterface): JSXInternal.Element => { + return

{props.children}

; +}; + +export interface InlineCardIconPropsInterface extends PropsInterface { + icon: string, + color: string +} + +export const InlineCardIcon = (props: InlineCardIconPropsInterface): JSXInternal.Element => { + return */ + style={`background-color:${props.color}`} + /* */ + >; +}; + +export const InlineCardButtonsWrapper = (props: PropsInterface): JSXInternal.Element => { + return
{props.children}
; +}; + +export const InlineCardsWrapper = (props: PropsInterface): JSXInternal.Element => { + return ( +
+ {props.children} +
+ ); +}; diff --git a/packages/profiler/src/styledElements/props.ts b/packages/profiler/src/styledElements/props.ts new file mode 100644 index 00000000..a0075ce2 --- /dev/null +++ b/packages/profiler/src/styledElements/props.ts @@ -0,0 +1,10 @@ +import { JSXInternal } from 'preact/src/jsx'; + +export interface PropsInterface { + children?: JSXInternal.Element[] | JSXInternal.Element +} + +export interface HideableElementPropsInterface extends Partial { + visible?: boolean + visibleClasses?: string +} diff --git a/packages/profiler/src/styledElements/tableElements.tsx b/packages/profiler/src/styledElements/tableElements.tsx new file mode 100644 index 00000000..e7849cf0 --- /dev/null +++ b/packages/profiler/src/styledElements/tableElements.tsx @@ -0,0 +1,12 @@ +import { HideableElement, HideableElementPropsInterface } from '.'; +import { JSXInternal } from 'preact/src/jsx'; + +export const TableWrapper = (props: HideableElementPropsInterface): JSXInternal.Element => { + return ( + +
+ {props.children} +
+
+ ); +}; diff --git a/packages/profiler/src/styledElements/visibilityElements.tsx b/packages/profiler/src/styledElements/visibilityElements.tsx new file mode 100644 index 00000000..baf04a89 --- /dev/null +++ b/packages/profiler/src/styledElements/visibilityElements.tsx @@ -0,0 +1,10 @@ +import { HideableElementPropsInterface } from '.'; +import { JSXInternal } from 'preact/src/jsx'; + +export const HideableElement = (props: HideableElementPropsInterface): JSXInternal.Element => { + return ( +
+ {props.children} +
+ ); +}; diff --git a/packages/profiler/stylify.config.js b/packages/profiler/stylify.config.js new file mode 100644 index 00000000..22909d8b --- /dev/null +++ b/packages/profiler/stylify.config.js @@ -0,0 +1,70 @@ +const { nativePreset } = require('@stylify/stylify'); + +module.exports = { + compilerConfig: { + ...nativePreset.compiler, + ...{ + variables: { + grey1: '#374955', + grey2: '#f1f3f5', + grey3: '#dddddd', + + blue1: '#0072bf', + blue2: '#ebf6fa', + + blueLogo: 'rgb(16, 184, 240)', + blueLogoHover: 'rgba(16, 184, 240, 0.8)' + }, + plainSelectors: { + '*': 'box-sizing:border-box', + a: 'color:$blue1 text-decoration:none cursor:pointer hover:text-decoration:underline', + table: 'border-collapse:collapse width:100%', + thead: 'position:sticky top:0 background-color:$blue1 color:#fff', + 'td, th': 'text-align:left padding:12px', + tr: 'content-visibility:auto', + 'tbody tr:nth-child(even)': 'background-color:$grey2', + pre: ` + margin:0 padding:8px border-radius:4px background-color:$blue2 max-height:400px overflow:auto + width:100% max-width:100% + lg:padding:12px + `, + 'table pre': 'background:none padding:none', + 'main .profiler__card': 'box-shadow:0__4px__16px__-4px__rgba(0,__0,__0,__0.2)', + '.profiler__card': ` + display:inline-flex flex-direction:row align-items:center flex-direction:row padding:12px + background-color:#fff border-radius:8px + box-shadow:0__6px__8px__1px__rgba(0,0,0,0.06) + lg:padding:24px + `, + '.profiler__card--full-width': ` + flex-direction:column align-items:flex-start margin-bottom:12px width:100% + lg:margin-bottom:24px + `, + '.profiler__card-title': 'margin-top:0 margin-bottom:8px font-size:1rem', + '.profiler__card-title--large': 'margin-bottom:12px font-size:1.5rem md:margin-bottom:24px', + '.profiler__card-icon': 'border-radius:8px padding:12px margin-right:12px font-size:32px color:#fff', + '.profiler__tab-title': 'font-size:1,8rem margin-bottom:24px color:$blue1 md:margin-bottom:32px', + '.profiler__table-wrapper': ` + width:100% max-height:400px overflow:auto border:1px__solid__$grey2 border-radius:4px + ` + }, + components: { + 'profiler__tab-button': ` + font-weight:bold display:flex align-items:center padding:12px transition:background-color__0.3s + white-space:nowrap margin-bottom:8px color:#000 margin-bottom:8px + border-radius:8px cursor:pointer user-select:none + hover:background-color:$blue2 + `, + 'profiler__tab-button--selected': { + selectors: 'background-color:$blue1 color:#fff hover:background-color:$blue1', + selectorsChain: 'profiler__tab-button' + }, + 'profiler__tab-button-icon': `width:18px height:18px margin-right:12px`, + 'profiler__tab-button-icon--selected': { + selectors: 'filter:brightness(0)__invert(1)', + selectorsChain: 'profiler__tab-button-icon' + } + } + } + } +}; diff --git a/packages/stylify/src/Compiler/CompilationResult.ts b/packages/stylify/src/Compiler/CompilationResult.ts index baf4b048..44d19f98 100755 --- a/packages/stylify/src/Compiler/CompilationResult.ts +++ b/packages/stylify/src/Compiler/CompilationResult.ts @@ -1,26 +1,40 @@ import { CssRecord, MacroMatch, SelectorProperties, SerializedCssRecordInterface } from '.'; +type ScreensListMapType = Map; + +type OnPrepareCssRecordCallbackType = (cssRecord: CssRecord) => void; + +type ScreenSortingFunctionType = (screensList: ScreensListMapType) => ScreensListMapType; + +export type ScreensListRecordType = Record; + +export type SelectorsListType = Record; + +export type ComponentsListType = Record; + +export type VariablesType = Record; + export interface CompilationResultConfigInterface { dev?: boolean, reconfigurable?: boolean, - screensSortingFunction?: CallableFunction, - screensList?: Record, - selectorsList?: Record, - componentsList?: Record, + screensSortingFunction?: ScreenSortingFunctionType, + screensList?: ScreensListRecordType, + selectorsList?: SelectorsListType, + componentsList?: ComponentsListType, mangleSelectors?: boolean, - variables?: Record, - onPrepareCssRecord?: CallableFunction | string + variables?: VariablesType, + onPrepareCssRecord?: OnPrepareCssRecordCallbackType | string } export interface SerializedCompilationResultInterface { dev?: boolean, reconfigurable?: boolean, screensSortingFunction?: string, - screensList?: Record, - selectorsList?: Record, - componentsList?: Record + screensList?: ScreensListRecordType, + selectorsList?: SelectorsListType, + componentsList?: ComponentsListType, mangleSelectors?: boolean, - variables?: Record, + variables?: VariablesType, onPrepareCssRecord?: string } @@ -29,13 +43,18 @@ export interface SelectorsListInterface { processed: boolean } -type ScreensListType = Map; +export type SelectorsComponentsMapType = Record; + +export interface SelectorsComponentsMapInterface { + component: string, + selectorsChain: string[] +} export class CompilationResult { private readonly MATCH_VARIABLE_REG_EXP = /\$([\w-_]+)/g; - private screensList: ScreensListType = new Map(); + private screensList: ScreensListMapType = new Map(); private screensListSorted = false; @@ -49,23 +68,20 @@ export class CompilationResult { public selectorsList: Record = {}; - public componentsList: Record = {}; - - public screensSortingFunction: CallableFunction = null; + public componentsList: ComponentsListType = {}; - public variables: Record = {}; + public screensSortingFunction: ScreenSortingFunctionType = null; - public lastBuildInfo: Record = null; + public variables: VariablesType = {}; - public onPrepareCssRecord: CallableFunction = null; + public onPrepareCssRecord: OnPrepareCssRecordCallbackType = null; - public constructor(config: CompilationResultConfigInterface = {}) { - this.setBuildInfo(null); + public constructor(config: CompilationResultConfigInterface | SerializedCompilationResultInterface = {}) { this.addScreen('_'); this.configure(config); } - public configure(config: CompilationResultConfigInterface = {}): void { + public configure(config: CompilationResultConfigInterface | SerializedCompilationResultInterface = {}): void { if (!Object.keys(config).length) { return; } @@ -74,7 +90,7 @@ export class CompilationResult { this.mangleSelectors = typeof config.mangleSelectors === 'boolean' ? config.mangleSelectors : this.mangleSelectors; - this.screensSortingFunction = config.screensSortingFunction || this.screensSortingFunction; + this.variables = {...this.variables, ...config.variables || {}}; this.componentsList = {...this.componentsList, ...config.componentsList || {}}; @@ -89,10 +105,17 @@ export class CompilationResult { } } + if ('screensSortingFunction' in config) { + this.screensSortingFunction = typeof config.screensSortingFunction === 'string' + // eslint-disable-next-line @typescript-eslint/no-implied-eval + ? new Function(config.screensSortingFunction) as ScreenSortingFunctionType + : config.screensSortingFunction; + } + if ('onPrepareCssRecord' in config) { this.onPrepareCssRecord = typeof config.onPrepareCssRecord === 'string' // eslint-disable-next-line @typescript-eslint/no-implied-eval - ? new Function(config.onPrepareCssRecord) + ? new Function(config.onPrepareCssRecord) as OnPrepareCssRecordCallbackType : config.onPrepareCssRecord; } @@ -127,32 +150,6 @@ export class CompilationResult { this.screensListSorted = false; } - private setBuildInfo = (data: Record = null): void => { - if (data === null - || this.lastBuildInfo === null - || this.changed === true && this.lastBuildInfo.completed === true - ) { - this.lastBuildInfo = { - processedSelectors: [], - processedComponents: [], - completed: false - }; - } - - if (data === null || !this.dev) { - return; - } - - this.lastBuildInfo.completed = 'completed' in data ? data.completed : false; - - this.lastBuildInfo.processedComponents = [ - ...this.lastBuildInfo.processedComponents, ...data.processedComponents || [] - ]; - this.lastBuildInfo.processedSelectors = [ - ...this.lastBuildInfo.processedSelectors, ...data.processedSelectors || [] - ]; - }; - public generateCss(): string { let css = ''; const newLine = this.dev ? '\n' : ''; @@ -185,9 +182,6 @@ export class CompilationResult { } this.changed = false; - this.setBuildInfo({ - completed: true - }); return css.trim(); } @@ -219,7 +213,10 @@ export class CompilationResult { for (const property in macroResult) { const propertyValue = macroResult[property].replace( this.MATCH_VARIABLE_REG_EXP, - (match, substring): string => { + (match, substring: string): string => { + if (!(substring in this.variables)) { + throw new Error(`Stylify: Variable "${substring}" not found. Available variables are "${Object.keys(this.variables).join(', ')}".`); + } return String(this.variables[substring]); } ); @@ -229,39 +226,58 @@ export class CompilationResult { this.selectorsList[selector] = newCssRecord; this.changed = true; - - this.setBuildInfo({ - processedSelectors: [selector] - }); } - public bindComponentsSelectors(componentsSelectorsMap: Record): void { - const processedComponents = []; + public bindPlainSelectorsToSelectors(plainSelectorsSelectorsMap: Record): void { + for (const plainSelector in plainSelectorsSelectorsMap) { + for (const dependencySelector of plainSelectorsSelectorsMap[plainSelector]) { + this.selectorsList[dependencySelector].addPlainSelector(plainSelector); + } + } + } - for (const componentDependencySelector in componentsSelectorsMap) { - for (const component of componentsSelectorsMap[componentDependencySelector]) { - if (!(component in this.componentsList)) { - this.componentsList[component] = this.getUniqueSelectorId(); + public bindComponentsToSelectors(selectorsComponentsMap: SelectorsComponentsMapType): void { + for (const componentDependencySelector in selectorsComponentsMap) { + for (const componentToBind of selectorsComponentsMap[componentDependencySelector]) { + if (!(componentToBind.component in this.componentsList)) { + this.componentsList[componentToBind.component] = this.getUniqueSelectorId(); } + + componentToBind.selectorsChain = componentToBind.selectorsChain + .map((selectorsChain: string): string => { + return selectorsChain + .split(' ') + .map((selectorFromChain: string) => { + if (this.mangleSelectors) { + if (selectorFromChain in this.selectorsList) { + selectorFromChain = this.selectorsList[selectorFromChain].mangledSelector; + } else if (selectorFromChain in this.componentsList) { + selectorFromChain = this.componentsList[selectorFromChain]; + } else { + throw new Error(`Stylify: selector "${selectorFromChain}" from component "${componentToBind.component}" selectorsChain list not found.`); + } + } + + return selectorFromChain; + }) + .join(' '); + }); + this.selectorsList[componentDependencySelector].addComponent( - this.mangleSelectors ? this.componentsList[component] : component + this.mangleSelectors ? this.componentsList[componentToBind.component] : componentToBind.component, + componentToBind.selectorsChain ); - processedComponents.push(component); } } - - this.setBuildInfo({ - processedComponents: processedComponents - }); } - private sortCssTreeMediaQueries(screensList: ScreensListType): ScreensListType { + private sortCssTreeMediaQueries(screensList: ScreensListMapType): ScreensListMapType { this.screensListSorted = true; if (this.screensSortingFunction) { - return this.screensSortingFunction(screensList) as ScreensListType; + return this.screensSortingFunction(screensList); } - const sortedScreens: ScreensListType = new Map(); + const sortedScreens: ScreensListMapType = new Map(); sortedScreens.set('_', screensList.get('_')); screensList.delete('_'); @@ -346,16 +362,21 @@ export class CompilationResult { } public serialize(): SerializedCompilationResultInterface { - const serializedCompilationResult: SerializedCompilationResultInterface = { - mangleSelectors: this.mangleSelectors, - dev: this.dev - }; + const serializedCompilationResult: SerializedCompilationResultInterface = {}; + + if (this.mangleSelectors) { + serializedCompilationResult.mangleSelectors = this.mangleSelectors; + } + + if (this.dev) { + serializedCompilationResult.dev = this.dev; + } if (!this.reconfigurable) { serializedCompilationResult.reconfigurable = false; } - if (this.screensList.size) { + if (this.screensList.size > 1) { serializedCompilationResult.screensList = {}; for (const [screen, screenId] of this.screensList) { serializedCompilationResult.screensList[screen] = screenId; @@ -397,10 +418,7 @@ export class CompilationResult { } private getUniqueSelectorId(): string { - const randomNumber = Object.keys(this.selectorsList).length - + Object.keys(this.componentsList).length - + Math.random() + 1; - return `_${randomNumber.toString(32).slice(2, 9)}`; + return `_${(Math.random() + 1).toString(32).slice(2, 9)}`; } } diff --git a/packages/stylify/src/Compiler/Compiler.ts b/packages/stylify/src/Compiler/Compiler.ts index 0e0e378a..2ca5b11b 100755 --- a/packages/stylify/src/Compiler/Compiler.ts +++ b/packages/stylify/src/Compiler/Compiler.ts @@ -1,30 +1,73 @@ -import { CompilationResult, MacroMatch, SelectorProperties, SelectorsListInterface } from '.'; +import { + CompilationResult, + MacroMatch, + SelectorProperties, + SelectorsComponentsMapType, + SelectorsListInterface, + VariablesType +} from '.'; + +export type MacroCallbackType = (macroMatch: MacroMatch, selectorProperties: SelectorProperties) => void; + +export type ScreenCallbackType = (screen: string) => string; export interface SerializedCompilerInterface { selectorsList: SelectorsListInterface } +export type ComponentSelectorsType = string|string[]; + +export type PlainSelectorDependencySelectorsType = string|string[]; + +export interface PlainSelectorInterface { + processed: boolean, + selectors: string[] +} + +export interface ComponentConfigInterface { + selectors: ComponentSelectorsType + selectorsChain: string|string[] +} + +export interface CompilerContentOptionsInterface { + pregenerate: string, + components: Record, + variables: Record +} + +export type OnPrepareCompilationResultCallbackType = (compilationResult: CompilationResult) => void; + +export type ContentOptionsProcessorCallbackType = ( + contentOptions: Partial, + optionMatchValue: string + ) => Partial; + +export type ContentOptionsProcessorsType = Record; + +export type MacrosType = Record; + +export type HelpersType = Record; + +export type ScreensType = Record; + export interface CompilerConfigInterface { dev?: boolean, - macros?: Record, - helpers?: Record, - variables?: Record, - screens?: Record, + macros?: MacrosType, + helpers?: HelpersType, + variables?: VariablesType, + screens?: ScreensType, + plainSelectors?: Record, mangleSelectors?: boolean, pregenerate?: string[]|string, components?: Record, - onPrepareCompilationResult?: CallableFunction, - contentOptionsProcessors?: Record, + onPrepareCompilationResult?: OnPrepareCompilationResultCallbackType, + contentOptionsProcessors?: ContentOptionsProcessorsType, ignoredElements?: string[] } -export interface CompilerContentOptionsInterface { - pregenerate: string, - components: Record -} - export interface ComponentsInterface { selectors: string[], + selectorsChain: string[], processed: boolean } @@ -34,27 +77,29 @@ export class Compiler { private ignoredElementsRegExp: RegExp = null; - public contentOptionsProcessors: Record = {}; + public contentOptionsProcessors: ContentOptionsProcessorsType = {}; - public onPrepareCompilationResult: CallableFunction = null; + public onPrepareCompilationResult: OnPrepareCompilationResultCallbackType = null; public mangleSelectors = false; public dev = false; - public macros: Record = {}; + public macros: MacrosType = {}; - public helpers: Record = {}; + public helpers: HelpersType = {}; - public screens: Record = {}; + public screens: ScreensType = {}; - public variables: Record = {}; + public variables: VariablesType = {}; public components: Record = {}; public pregenerate = ''; - public ignoredElements = ['head', 'script', 'style', 'stylify-ignore']; + public ignoredElements = ['code', 'head', 'pre', 'script', 'style', 'stylify-ignore']; + + public plainSelectors: Record = {}; constructor(config: CompilerConfigInterface = {}) { if (!Object.keys(config).length) { @@ -83,43 +128,84 @@ export class Compiler { .filter((value, index, self) => { return self.indexOf(value) === index; }); + const ignoredElements = this.ignoredElements.map((element: string): string => { return `<${element}[\\s\\S]*?>[\\s\\S]*?<\\/${element}>`; }); - this.ignoredElementsRegExp = new RegExp(ignoredElements.join('|'), 'ig'); + this.ignoredElementsRegExp = new RegExp(ignoredElements.join('|'), 'g'); this.onPrepareCompilationResult = config.onPrepareCompilationResult || this.onPrepareCompilationResult; - for (const componentSelector in config.components) { - this.addComponent(componentSelector, config.components[componentSelector]); + const plainSelectors = config.plainSelectors || {}; + for (const plainSelector in plainSelectors) { + this.addPlainSelector(plainSelector, plainSelectors[plainSelector]); + } + + const components = config.components || {}; + for (const componentSelector in components) { + this.addComponent(componentSelector, components[componentSelector]); } return this; } - public addComponent(selector: string, selectorDependencies: string|string[]): Compiler { + public addPlainSelector(selector: string, dependencySelectors: PlainSelectorDependencySelectorsType): void { + const selectorsArray = selector.split(', '); + + for (const selector of selectorsArray) { + dependencySelectors = this.convertStringOrStringArrayToFilteredArray(dependencySelectors); + if (selector in this.plainSelectors) { + this.plainSelectors[selector].selectors = [ + ...this.plainSelectors[selector].selectors, + ...dependencySelectors + ]; + return; + } + + this.plainSelectors[selector] = { + processed: false, + selectors: dependencySelectors + }; + } + } + + public addComponent( + selector: string, + componentConfig: ComponentSelectorsType|ComponentConfigInterface + ): Compiler { if (selector in this.components) { return; } - selectorDependencies = typeof selectorDependencies === 'string' - ? selectorDependencies.replace(/\s/ig, ' ') - : selectorDependencies.join(' '); - - selectorDependencies = selectorDependencies.split(' ').filter((selector: string): boolean => { - return selector.trim().length > 0; - }); + if (typeof componentConfig === 'string' || Array.isArray(componentConfig)) { + componentConfig = { + selectors: componentConfig, + selectorsChain: [] + }; + } this.components[selector] = { - selectors: selectorDependencies, + selectors: this.convertStringOrStringArrayToFilteredArray(componentConfig.selectors), + selectorsChain: Array.isArray(componentConfig.selectorsChain) + ? componentConfig.selectorsChain + : [componentConfig.selectorsChain], processed: false }; return this; } + private convertStringOrStringArrayToFilteredArray(data: string|string[]): string[] { + if (Array.isArray(data)) { + data = data.join(' '); + } + + return data.replace(/\s/ig, ' ').split(' ').filter((value: string, index, self): boolean => { + return value.trim().length > 0 && self.indexOf(value) === index; + }); + } - public addMacro(re: string, callback: CallableFunction): Compiler { + public addMacro(re: string, callback: MacroCallbackType): Compiler { this.macros[re] = callback; return this; } @@ -172,14 +258,14 @@ export class Compiler { `${quoteType}([^${quoteType}]+)?${selector}([^${quoteType}]+)?${quoteType}`, 'g' ); - content = content.replace( - regExp, - (match, selectorsBefore = '', selectorsAfter = ''): string => { - return quoteType - + selectorsBefore + mangledSelector + selectorsAfter - + quoteType; - } - ); + while (regExp.exec(content)) { + content = content.replace( + regExp, + (match, selectorsBefore = '', selectorsAfter = ''): string => { + return `${quoteType}${selectorsBefore}${mangledSelector}${selectorsAfter}${quoteType}`; + } + ); + } } } @@ -192,12 +278,20 @@ export class Compiler { public compile(content: string, compilationResult: CompilationResult = null): CompilationResult { compilationResult = this.prepareCompilationResult(compilationResult); - const { components, pregenerate } = this.getOptionsFromContent(content); + this.configure(this.getOptionsFromContent(content)); - this.configure({ - components: components || {}, - pregenerate: pregenerate || '' - }); + const plainSelectorsSelectorsMap = {}; + for (const plainSelector in this.plainSelectors) { + const plainSelectorData = this.plainSelectors[plainSelector]; + if (plainSelectorData.processed) { + continue; + } + + plainSelectorsSelectorsMap[plainSelector] = plainSelectorData.selectors; + this.pregenerate += ' ' + plainSelectorData.selectors.join(' '); + + this.plainSelectors[plainSelector].processed = true; + } content = `${this.pregenerate} ${content}`; this.pregenerate = ''; @@ -216,7 +310,7 @@ export class Compiler { }); } - const selectorsComponentsMap = {}; + const selectorsComponentsMap: SelectorsComponentsMapType = {}; Object.keys(this.components) .filter((element): boolean => { @@ -227,19 +321,22 @@ export class Compiler { return this.components[element].processed === false; }) .forEach((notProcessedComponentsSelector) => { - if (!content.match(new RegExp(`${notProcessedComponentsSelector}\\b`, 'ig'))) { + if (!content.match(new RegExp(`${notProcessedComponentsSelector}\\b`, 'g'))) { return; } - const componentSelectors = this.components[notProcessedComponentsSelector].selectors; - content += ` ${componentSelectors.join(' ')}`; + const { selectors, selectorsChain } = this.components[notProcessedComponentsSelector]; + content += ` ${selectors.join(' ')}`; - componentSelectors.forEach((componentDependencySelector: string): void => { + selectors.forEach((componentDependencySelector: string): void => { if (! (componentDependencySelector in selectorsComponentsMap)) { selectorsComponentsMap[componentDependencySelector] = []; } - selectorsComponentsMap[componentDependencySelector].push(notProcessedComponentsSelector); + selectorsComponentsMap[componentDependencySelector].push({ + component: notProcessedComponentsSelector, + selectorsChain: selectorsChain + }); }); this.components[notProcessedComponentsSelector].processed = true; @@ -247,9 +344,8 @@ export class Compiler { this.processMacros(content, compilationResult); - if (Object.keys(selectorsComponentsMap).length) { - compilationResult.bindComponentsSelectors(selectorsComponentsMap); - } + compilationResult.bindPlainSelectorsToSelectors(plainSelectorsSelectorsMap); + compilationResult.bindComponentsToSelectors(selectorsComponentsMap); return compilationResult; } @@ -293,7 +389,7 @@ export class Compiler { private processMacros(content: string, compilationResult: CompilationResult = null) { for (const macroKey in this.macros) { // TODO negative lookbehind, is it necessary? - const macroRe = new RegExp(`(?:([a-z0-9-:&|]+):)?(?, - components?: string[], + plainSelectors?: string[], + components?: ComponentsType, pseudoClasses?: string[], onAddProperty?: string scope?: string } +export type ComponentsType = Record; + +export type OnAddPropertyCallbackType = (property: string, value: any) => Record|null; + export interface CssRecordConfigInterface { screenId: number, selector: string, mangledSelector: string, properties?: Record, - components?: string[], + plainSelectors?: string[], + components?: ComponentsType, pseudoClasses?: string[], - onAddProperty?: CallableFunction | string + onAddProperty?: OnAddPropertyCallbackType | string scope?: string shouldBeGenerated?: boolean } @@ -28,7 +34,7 @@ export interface CssRecordCompileParametersConfig { export class CssRecord { - private cache: string = null; + public cache: string = null; private changed = false; @@ -42,13 +48,15 @@ export class CssRecord { public scope: string = null; - public components: string[] = []; + public plainSelectors: string[] = []; + + public components: ComponentsType = {}; public properties: Record = {}; public pseudoClasses: string[] = []; - public onAddProperty: CallableFunction = null; + public onAddProperty: OnAddPropertyCallbackType = null; constructor(config: CssRecordConfigInterface) { this.configure(config); @@ -62,11 +70,11 @@ export class CssRecord { if ('onAddProperty' in config) { this.onAddProperty = typeof config.onAddProperty === 'string' // eslint-disable-next-line @typescript-eslint/no-implied-eval - ? new Function(config.onAddProperty) + ? new Function(config.onAddProperty) as OnAddPropertyCallbackType : config.onAddProperty; } this.shouldBeGenerated = 'shouldBeGenerated' in config ? config.shouldBeGenerated : this.shouldBeGenerated; - this.addComponents(config.components || []); + this.addComponents(config.components || {}); this.addProperties(config.properties || {}); this.addPseudoClasses(config.pseudoClasses || []); this.changed = true; @@ -85,9 +93,7 @@ export class CssRecord { } const onAddPropertyHook = (property: string, value: any): Record => { - let properties = this.onAddProperty - ? this.onAddProperty(property, value) as Record|null - : null; + let properties = this.onAddProperty ? this.onAddProperty(property, value) : null; if (!properties) { properties = { @@ -115,53 +121,90 @@ export class CssRecord { } } - public addComponents(selectors: string[]): void { - for (const selector of selectors) { - this.addComponent(selector); + public addPlainSelector(selector: string): void { + if (this.plainSelectors.includes(selector)) { + return; } + + this.plainSelectors.push(selector); } - public addComponent(selector: string): void { + public addComponents(components: ComponentsType): void { + for (const componentSelector in components) { + this.addComponent(componentSelector, components[componentSelector]); + } + } + + public addComponent(selector: string, selectorsChain: string[] = []): void { selector = selector.replace(/([^-_a-zA-Z\d])/g, '\\$1'); - if (this.components.includes(selector)) { + if (selector in this.components) { return; } this.changed = true; - this.components.push(selector); + this.components[selector] = selectorsChain; } public generateCss(config: CssRecordCompileParametersConfig): string { if (this.changed || !this.cache) { const newLine = config.minimize ? '' : '\n'; - const scopePart = this.scope ? this.scope + ' ' : ''; const cssRecordSelector = config.mangleSelectors ? this.mangledSelector : this.selector; - let selectors: string[] = []; + let plainSelectors: string[] = []; + let classSelectors: string[] = []; + const componentsSelectors: string[] = []; + + for (const componentSelector in this.components) { + const selectorsChain = this.components[componentSelector]; + if (!selectorsChain.length) { + componentsSelectors.push(componentSelector); + continue; + } + + for (const chainedSelectors of selectorsChain) { + componentsSelectors.push([...chainedSelectors.split(' '), componentSelector].join('.')); + } + } if (this.pseudoClasses.length) { for (const pseudoClass of this.pseudoClasses) { const pseudoClassSuffix = `:${pseudoClass}`; - selectors.push(`${cssRecordSelector}${pseudoClassSuffix}`); - - for (const component of this.components) { - selectors.push(`${component}${pseudoClassSuffix}`); - } + plainSelectors = [ + ...plainSelectors, + ...plainSelectors.map((selector: string): string => { + return `${selector}${pseudoClassSuffix}`; + }) + ]; + classSelectors = [ + ...classSelectors, + ...[`${cssRecordSelector}${pseudoClassSuffix}`], + ...componentsSelectors.map((selector): string => { + return `${selector}${pseudoClassSuffix}`; + }) + ]; } } else { - selectors = [cssRecordSelector, ...this.components]; + plainSelectors = this.plainSelectors; + classSelectors = [cssRecordSelector, ...componentsSelectors]; } - this.cache = selectors - .map((selector): string => { + const scopePart = this.scope ? this.scope + ' ' : ''; + const selectors = [ + ...plainSelectors.map((selector): string => { + return `${scopePart}${selector}`; + }), + ...classSelectors.map((selector): string => { return `${scopePart}.${selector}`; }) - .join(',' + newLine) + '{' + newLine - + Object.keys(this.properties) - .map(property => `${(config.minimize ? '' : '\t') + property}:${this.properties[property]}`) - .join(';' + newLine) - + newLine + '}' + newLine; + ]; + + this.cache = selectors.join(',' + newLine) + + '{' + newLine + + Object.keys(this.properties) + .map(property => `${(config.minimize ? '' : '\t') + property}:${this.properties[property]}`) + .join(';' + newLine) + newLine + + '}' + newLine; this.changed = false; } @@ -176,13 +219,18 @@ export class CssRecord { mangledSelector: this.mangledSelector }; - if (this.components.length) { - serializedObject.components = []; - for (const component of this.components) { - serializedObject.components.push(component.replace(/\\([^-_a-zA-Z\d])/g, '$1')); + if (Object.keys(this.components).length) { + serializedObject.components = {}; + for (const componentSelector in this.components) { + const selectorsChain = this.components[componentSelector]; + serializedObject.components[componentSelector.replace(/\\([^-_a-zA-Z\d])/g, '$1')] = selectorsChain; } } + if (this.plainSelectors.length) { + serializedObject.plainSelectors = this.plainSelectors; + } + if (this.onAddProperty) { serializedObject.onAddProperty = this.onAddProperty.toString(); } diff --git a/packages/stylify/src/Compiler/MacroMatch.ts b/packages/stylify/src/Compiler/MacroMatch.ts index 2cb30367..a2d00c91 100755 --- a/packages/stylify/src/Compiler/MacroMatch.ts +++ b/packages/stylify/src/Compiler/MacroMatch.ts @@ -29,7 +29,7 @@ export class MacroMatch { let screenMatched = false; for (const key in screens) { - const screenRegExp = new RegExp(key, 'ig'); + const screenRegExp = new RegExp(key, 'g'); const screenMatches = screenRegExp.exec(possibleScreenMatch); if (screenMatches === null) { diff --git a/packages/stylify/src/Compiler/SelectorProperties.ts b/packages/stylify/src/Compiler/SelectorProperties.ts index 02db2fd4..394e8d2d 100755 --- a/packages/stylify/src/Compiler/SelectorProperties.ts +++ b/packages/stylify/src/Compiler/SelectorProperties.ts @@ -2,18 +2,12 @@ export class SelectorProperties { public properties: Record = {}; - public add(property: string, value: string|number): SelectorProperties { + public add(property: string, value: string|number): void { this.properties[property] = String(value); - return this; } - public addMultiple(properties: Record): SelectorProperties { - let property: string; - // Object assign? - for (property in properties) { - this.add(property, properties[property]); - } - return this; + public addMultiple(properties: Record): void { + this.properties = {...this.properties, ...properties}; } } diff --git a/packages/stylify/src/Presets/index.ts b/packages/stylify/src/Presets/index.ts index ec900efc..c29379fc 100644 --- a/packages/stylify/src/Presets/index.ts +++ b/packages/stylify/src/Presets/index.ts @@ -1 +1 @@ -export * from './NativePreset'; +export * from './nativePreset'; diff --git a/packages/stylify/src/Presets/NativePreset.ts b/packages/stylify/src/Presets/nativePreset.ts similarity index 97% rename from packages/stylify/src/Presets/NativePreset.ts rename to packages/stylify/src/Presets/nativePreset.ts index 3d2b616a..34b040d3 100644 --- a/packages/stylify/src/Presets/NativePreset.ts +++ b/packages/stylify/src/Presets/nativePreset.ts @@ -13,8 +13,6 @@ const orientationScreen = (screen: string): string => `(orientation: ${screen})` const nativePreset = { compiler: { screens: { - toxs: maxWidthScreen('319px'), - xs: minWidthScreen('320px'), tosm: maxWidthScreen('639px'), sm: minWidthScreen('640px'), tomd: maxWidthScreen('767px'), @@ -36,11 +34,12 @@ const nativePreset = { onlyScreen: 'only screen', portrait: orientationScreen('portrait'), landscape: orientationScreen('landscape'), - dark: '(prefers-color-scheme: dark)' + dark: '(prefers-color-scheme: dark)', + light: '(prefers-color-scheme: light)' }, macros: { // eslint-disable-next-line quote-props - '(-(?:apple-(?:color-filter|pay-(?:button-(?:style|type))|trailing-word)|moz-(?:appearance|box-(?:align|direction|flex|ordinal-group|orient|pack)|float-edge|force-(?:broken-(?:image-icon))|image-region|orient|outline-(?:radius-(?:bottomleft|bottomright|topleft|topright))|stack-sizing|tab-size|text-(?:size-adjust)|user-(?:focus|input|modify|select)|window-dragging)|webkit-(?:app-region|appearance|aspect-ratio|backdrop-filter|backface-visibility|background-(?:clip|composite|origin|size)|border-(?:fit|horizontal-spacing|image|vertical-spacing)|box-(?:align|decoration-break|direction|flex(?:-group)?|lines|ordinal-group|orient|pack|reflect|shadow)|column-(?:axis|break-(?:after|before|inside)|progression)|cursor-visibility|font-(?:kerning|smoothing)|highlight|hyphenate-(?:character|limit-(?:after|before|lines))|hyphens|initial-letter|line-(?:align|box-contain|clamp|grid|snap)|locale|margin-(?:after-collapse|before-collapse|bottom-collapse|top-collapse)|mask-(?:box-(?:image(?:-(?:outset|repeat|slice|source|width))?)|clip|composite|image|origin|position-(?:x|y)|repeat-(?:x|y)|size|source-type)|nbsp-mode|perspective-(?:origin-(?:x|y))|print-(?:color-adjust)|rtl-ordering|ruby-position|tap-(?:highlight-color)|text-(?:combine|decorations-(?:in-effect)|emphasis-(?:color|position|style)|fill-color|orientation|security|size-adjust|stroke-(?:color|width)|zoom)|transform-(?:origin-(?:x|y|z)|style)|user-(?:drag|modify|select)))|align-(?:content|items|self)|alignment-baseline|all|alt|animation-(?:delay|direction|duration|fill-mode|iteration-count|name|play-state|timing-function)|appearance|aspect-ratio|backdrop-filter|backface-visibility|background(?:-(?:attachment|blend-mode|clip|color|image|origin|position(?:-(?:x|y))?|repeat(?:-(?:x|y))?|size))?|baseline-shift|block-size|border(?:-(?:block-(?:end-(?:color|style|width)|start-(?:color|style|width))|bottom(?:-(?:color|left-radius|right-radius|style|width))?|collapse|end-(?:end-radius|start-radius)|image-(?:outset|repeat|slice|source|width)|inline-(?:end-(?:color|style|width)|start-(?:color|style|width))|left(?:-(?:color|style|width))?|radius|right(?:-(?:color|style|width))?|spacing|start-(?:end-radius|start-radius)|top(?:-(?:color|left-radius|right-radius|style|width))?))?|bottom|box-(?:decoration-break|shadow|sizing)|break-(?:after|before|inside)|buffered-rendering|caption-side|caret-color|clear|clip(?:-(?:path|rule))?|color(?:-(?:adjust|interpolation(?:-filters)?|rendering|scheme))?|column-(?:count|fill|gap|rule-(?:color|style|width)|span|width)|contain(?:-(?:intrinsic-size))?|content(?:-visibility)?|counter-(?:increment|reset|set)|cursor|cx|cy|d|direction|display|dominant-baseline|empty-cells|fill(?:-(?:opacity|rule))?|filter|flex(?:-(?:basis|direction|grow|shrink|wrap))?|float|flood-(?:color|opacity)|font(?:-(?:family|feature-settings|kerning|language-override|optical-sizing|size(?:-adjust)?|stretch|style|synthesis|variant(?:-(?:alternates|caps|east-asian|ligatures|numeric|position))?|variation-settings|weight))?|forced-(?:color-adjust)|glyph-(?:orientation-(?:horizontal|vertical))|grid-(?:auto-(?:columns|flow|rows)|column-(?:end|start)|row-(?:end|start)|template-(?:areas|columns|rows))|hanging-punctuation|height|hyphens|image-(?:orientation|rendering)|ime-mode|inline-size|inset-(?:block-(?:end|start)|inline-(?:end|start))|isolation|justify-(?:content|items|self)|kerning|left|letter-spacing|lighting-color|line-(?:break|height(?:-step)?)|list-(?:style(?:-(?:image|position|type))?)|margin(?:-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top))?|marker(?:-(?:end|mid|start))?|mask(?:-(?:clip|composite|image|mode|origin|position(?:-(?:x|y))?|repeat|size|type))?|math-(?:depth|shift|style)|max-(?:block-size|height|inline-size|width)|min-(?:block-size|height|inline-size|width)|mix-(?:blend-mode)|object-(?:fit|position)|offset-(?:anchor|distance|path|position|rotate)|opacity|order|orphans|outline(?:-(?:color|offset|style|width))?|overflow(?:-(?:anchor|wrap|x|y))?|overscroll-(?:behavior-(?:block|inline|x|y))|padding(?:-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top))?|page(?:-(?:break-(?:after|before|inside)|orientation))?|paint-order|perspective(?:-(?:origin(?:-(?:x|y))?))?|pointer-events|position|quotes|r|resize|right|rotate|row-gap|ruby-(?:align|position)|rx|ry|scale|scroll-(?:behavior|margin(?:-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top))?|padding-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top)|snap-(?:align|margin-(?:bottom|left|right|top)|stop|type))|scrollbar-(?:color|width)|shape-(?:image-threshold|margin|outside|rendering)|size|speak(?:-as)?|stop-(?:color|opacity)|stroke(?:-(?:color|dasharray|dashoffset|linecap|linejoin|miterlimit|opacity|width))?|tab-size|table-layout|text-(?:align(?:-last)?|anchor|combine-upright|decoration(?:-(?:color|line|skip(?:-ink)?|style|thickness))?|emphasis-(?:color|position|style)|indent|justify|orientation|overflow|rendering|shadow|size-adjust|transform|underline-(?:offset|position))|top|touch-action|transform(?:-(?:box|origin(?:-(?:x|y|z))?|style))?|transition(?:-(?:delay|duration|property|timing-function))?|translate|unicode-bidi|user-select|vector-effect|vertical-align|visibility|white-space|widows|width|will-change|word-(?:break|spacing|wrap)|writing-mode|x|y|z-index|zoom)\\b:([^ \'"`{}\\[\\]]+)': (m: MacroMatch, p: SelectorProperties): void => { + '(-(?:apple-(?:color-filter|pay-(?:button-(?:style|type))|trailing-word)|moz-(?:appearance|box-(?:align|direction|flex|ordinal-group|orient|pack)|float-edge|force-(?:broken-(?:image-icon))|image-region|orient|outline-(?:radius-(?:bottomleft|bottomright|topleft|topright))|stack-sizing|tab-size|text-(?:size-adjust)|user-(?:focus|input|modify|select)|window-dragging)|webkit-(?:app-region|appearance|aspect-ratio|backdrop-filter|backface-visibility|background-(?:clip|composite|origin|size)|border-(?:fit|horizontal-spacing|image|vertical-spacing)|box-(?:align|decoration-break|direction|flex(?:-group)?|lines|ordinal-group|orient|pack|reflect|shadow)|column-(?:axis|break-(?:after|before|inside)|progression)|cursor-visibility|font-(?:kerning|smoothing)|highlight|hyphenate-(?:character|limit-(?:after|before|lines))|hyphens|initial-letter|line-(?:align|box-contain|clamp|grid|snap)|locale|margin-(?:after-collapse|before-collapse|bottom-collapse|top-collapse)|mask-(?:box-(?:image(?:-(?:outset|repeat|slice|source|width))?)|clip|composite|image|origin|position-(?:x|y)|repeat-(?:x|y)|size|source-type)|nbsp-mode|perspective-(?:origin-(?:x|y))|print-(?:color-adjust)|rtl-ordering|ruby-position|tap-(?:highlight-color)|text-(?:combine|decorations-(?:in-effect)|emphasis-(?:color|position|style)|fill-color|orientation|security|size-adjust|stroke-(?:color|width)|zoom)|transform-(?:origin-(?:x|y|z)|style)|user-(?:drag|modify|select)))|align-(?:content|items|self)|alignment-baseline|all|alt|animation-(?:delay|direction|duration|fill-mode|iteration-count|name|play-state|timing-function)|appearance|aspect-ratio|backdrop-filter|backface-visibility|background(?:-(?:attachment|blend-mode|clip|color|image|origin|position(?:-(?:x|y))?|repeat(?:-(?:x|y))?|size))?|baseline-shift|block-size|border(?:-(?:block-(?:end-(?:color|style|width)|start-(?:color|style|width))|bottom(?:-(?:color|left-radius|right-radius|style|width))?|collapse|end-(?:end-radius|start-radius)|image-(?:outset|repeat|slice|source|width)|inline-(?:end-(?:color|style|width)|start-(?:color|style|width))|left(?:-(?:color|style|width))?|radius|right(?:-(?:color|style|width))?|spacing|start-(?:end-radius|start-radius)|top(?:-(?:color|left-radius|right-radius|style|width))?))?|bottom|box-(?:decoration-break|shadow|sizing)|break-(?:after|before|inside)|buffered-rendering|caption-side|caret-color|clear|clip(?:-(?:path|rule))?|color(?:-(?:adjust|interpolation(?:-filters)?|rendering|scheme))?|column-(?:count|fill|gap|rule-(?:color|style|width)|span|width)|contain(?:-(?:intrinsic-size))?|content(?:-visibility)?|counter-(?:increment|reset|set)|cursor|cx|cy|d|direction|display|dominant-baseline|empty-cells|fill(?:-(?:opacity|rule))?|filter|flex(?:-(?:basis|direction|grow|shrink|wrap))?|float|flood-(?:color|opacity)|font(?:-(?:family|feature-settings|kerning|language-override|optical-sizing|size(?:-adjust)?|stretch|style|synthesis|variant(?:-(?:alternates|caps|east-asian|ligatures|numeric|position))?|variation-settings|weight))?|forced-(?:color-adjust)|glyph-(?:orientation-(?:horizontal|vertical))|grid-(?:auto-(?:columns|flow|rows)|column-(?:end|start)|row-(?:end|start)|template-(?:areas|columns|rows))|hanging-punctuation|height|hyphens|image-(?:orientation|rendering)|ime-mode|inline-size|inset-(?:block-(?:end|start)|inline-(?:end|start))|isolation|justify-(?:content|items|self)|kerning|left|letter-spacing|lighting-color|line-(?:break|height(?:-step)?)|list-(?:style(?:-(?:image|position|type))?)|margin(?:-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top))?|marker(?:-(?:end|mid|start))?|mask(?:-(?:clip|composite|image|mode|origin|position(?:-(?:x|y))?|repeat|size|type))?|math-(?:depth|shift|style)|max-(?:block-size|height|inline-size|width)|min-(?:block-size|height|inline-size|width)|mix-(?:blend-mode)|object-(?:fit|position)|offset-(?:anchor|distance|path|position|rotate)|opacity|order|orphans|outline(?:-(?:color|offset|style|width))?|overflow(?:-(?:anchor|wrap|x|y))?|overscroll-(?:behavior-(?:block|inline|x|y))|padding(?:-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top))?|page(?:-(?:break-(?:after|before|inside)|orientation))?|paint-order|perspective(?:-(?:origin(?:-(?:x|y))?))?|pointer-events|position|quotes|r|resize|right|rotate|row-gap|ruby-(?:align|position)|rx|ry|scale|scroll-(?:behavior|margin(?:-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top))?|padding-(?:block-(?:end|start)|bottom|inline-(?:end|start)|left|right|top)|snap-(?:align|margin-(?:bottom|left|right|top)|stop|type))|scrollbar-(?:color|width)|shape-(?:image-threshold|margin|outside|rendering)|size|speak(?:-as)?|stop-(?:color|opacity)|stroke(?:-(?:color|dasharray|dashoffset|linecap|linejoin|miterlimit|opacity|width))?|tab-size|table-layout|text-(?:align(?:-last)?|anchor|combine-upright|decoration(?:-(?:color|line|skip(?:-ink)?|style|thickness))?|emphasis-(?:color|position|style)|indent|justify|orientation|overflow|rendering|shadow|size-adjust|transform|underline-(?:offset|position))|top|touch-action|transform(?:-(?:box|origin(?:-(?:x|y|z))?|style))?|transition(?:-(?:delay|duration|property|timing-function))?|translate|unicode-bidi|user-select|vector-effect|vertical-align|visibility|white-space|widows|width|will-change|word-(?:break|spacing|wrap)|writing-mode|x|y|z-index|zoom)\\b:([^ \'"`{}\\[\\]<>]+)': (m: MacroMatch, p: SelectorProperties): void => { p.add(m.getCapture(0), m.getCapture(1)); } } diff --git a/packages/stylify/src/Runtime.ts b/packages/stylify/src/Runtime.ts index beb0bb8e..646997b3 100755 --- a/packages/stylify/src/Runtime.ts +++ b/packages/stylify/src/Runtime.ts @@ -1,4 +1,4 @@ -import { CompilationResult, Compiler, CompilerConfigInterface, SerializedCompilationResultInterface } from '.'; +import { CompilationResult, Compiler, CompilerConfigInterface, SerializedCompilationResultInterface } from './Compiler'; export interface RuntimeConfigInterface { dev?: boolean, @@ -9,25 +9,25 @@ export interface RuntimeConfigInterface { } } -export class Runtime { - - public static readonly STYLIFY_STYLE_EL_ID: string = 'stylify-css'; - - public static readonly RUNTIME_CACHE_CLASS = 'stylify-runtime-cache'; +interface UpdateCssCallbackArgumentsInterface { + css: string|null, + compilationResult: CompilationResult, + content: string +} - public static readonly STYLIFY_RUNTIME_IGNORE_CLASS = 'stylify-ignore'; +type UpdateCssCallbackType = (data: UpdateCssCallbackArgumentsInterface) => void; - public static readonly STYLIFY_CLOAK_ATTR_NAME: string = 's-cloak'; +export class Runtime { - public static readonly STYLIFY_READY_EVENT = 'stylify:ready'; + public static readonly STYLE_EL_ID: string = 'stylify-css'; - public static readonly STYLIFY_RUNTIME_CONFIGURED_EVENT = 'stylify:runtime:configured'; + public static readonly CACHE_CLASS = 'stylify-runtime-cache'; - public static readonly STYLIFY_COMPILER_CONFIGURED_EVENT = 'stylify:compiler:configured'; + public static readonly IGNORE_CLASS = 'stylify-ignore'; - public static readonly STYLIFY_REPAINTED_EVENT = 'stylify:runtime:repainted'; + public static readonly CLOAK_CLASS: string = 's-cloak'; - public static readonly STYLIFY_UNCLOAK_EVENT = 'stylify:runtime:uncloak'; + public readonly version = '__PACKAGE__VERSION__'; public dev = false; @@ -46,10 +46,14 @@ export class Runtime { return; } + if (typeof globalThis.Stylify === 'undefined') { + globalThis.Stylify = this; + } + this.configure(config); this.initialPaintCompleted = false; - this.triggerEvent(Runtime.STYLIFY_READY_EVENT, this); + this.triggerEvent('stylify:ready', this); if (['complete', 'loaded', 'interactive'].includes(document.readyState)) { this.init(); @@ -75,10 +79,6 @@ export class Runtime { this.dev = 'dev' in config ? config.dev : this.dev; this.repaintTimeout = runtimeConfig.repaintTimeout || this.repaintTimeout; - this.triggerEvent(Runtime.STYLIFY_RUNTIME_CONFIGURED_EVENT, { - config: config - }); - compilerConfig.dev = this.dev; if (!this.compiler) { @@ -89,8 +89,8 @@ export class Runtime { this.compiler.configure(compilerConfig); - this.triggerEvent(Runtime.STYLIFY_COMPILER_CONFIGURED_EVENT, { - compiler: this + this.triggerEvent('stylify:configured', { + config: config }); return this; @@ -98,19 +98,10 @@ export class Runtime { private init() { if (!this.initialPaintCompleted) { - const repaintStartTime = performance.now(); const content = document.documentElement.outerHTML; - const css = this.updateCss(content); - this.initialPaintCompleted = true; - - if (css !== null) { - this.triggerEvent(Runtime.STYLIFY_REPAINTED_EVENT, { - css: css, - repaintTime: performance.now() - repaintStartTime, - compilationResult: this.compilationResult, - content: content - }); - } + this.updateCss(content, () => { + this.initialPaintCompleted = true; + }); } if (!this.mutationObserverInitialized) { @@ -120,13 +111,17 @@ export class Runtime { public hydrate(data: string|SerializedCompilationResultInterface = null): void { if (!data) { - const cacheElements = document.querySelectorAll(`.${Runtime.RUNTIME_CACHE_CLASS}`) || []; + const cacheElements = document.querySelectorAll(`.${Runtime.CACHE_CLASS}:not(.processed)`) || []; cacheElements.forEach((cacheElement: Element) => { cacheElement.classList.add('processed'); if (cacheElement.innerHTML.trim().length > 0) { this.hydrate(cacheElement.innerHTML); } - cacheElement.parentElement.removeChild(cacheElement); + if (this.dev) { + cacheElement.classList.add('processed'); + } else { + cacheElement.parentElement.removeChild(cacheElement); + } }); return; } @@ -139,13 +134,9 @@ export class Runtime { } else { this.compilationResult = this.compiler.createCompilationResultFromSerializedData(parsedData); } - - this.triggerEvent('stylify:runtime:hydrated', { - cache: parsedData - }); } - private updateCss(content: string): string|null { + private updateCss(content: string, callback: UpdateCssCallbackType = null): string|null { this.hydrate(); this.compilationResult = this.compiler.compile(content, this.compilationResult); @@ -155,6 +146,21 @@ export class Runtime { const css: string = this.compilationResult.generateCss(); this.injectCss(css); + + if (callback) { + callback({ + css: css, + compilationResult: this.compilationResult, + content: content + }); + } + + this.triggerEvent('stylify:repainted', { + css: css, + compilationResult: this.compilationResult, + content: content + }); + return css; } @@ -164,57 +170,43 @@ export class Runtime { const config = { attributeFilter: ['class'], childList: true, subtree: true }; let compilerContentQueue = ''; let updateTimeout = null; - let repaintStartTime = null; + const ignoreSelector = `.${Runtime.IGNORE_CLASS}`; const observer = new MutationObserver((mutationsList) => { - if (repaintStartTime === null) { - repaintStartTime = performance.now(); - } - mutationsList.forEach((mutation) => { - const targetElement = mutation.target as Element; + let targetElement = mutation.target as Element; if (!['attributes', 'childList'].includes(mutation.type) || mutation.type === 'attributes' && mutation.attributeName !== 'class' || targetElement.nodeType !== Node.ELEMENT_NODE - || targetElement.id === Runtime.STYLIFY_STYLE_EL_ID - || targetElement.classList.contains(Runtime.STYLIFY_RUNTIME_IGNORE_CLASS) - || targetElement.closest(`.${Runtime.STYLIFY_RUNTIME_IGNORE_CLASS}`) !== null + || targetElement.id === Runtime.STYLE_EL_ID + || targetElement.classList.contains(Runtime.IGNORE_CLASS) + || targetElement.closest(ignoreSelector) !== null ) { return; } + targetElement = targetElement.cloneNode(true) as Element; + targetElement.querySelectorAll(ignoreSelector).forEach((element) => { + element.remove(); + }); + compilerContentQueue += mutation.type === 'attributes' ? targetElement.className : targetElement.outerHTML; }); - if (!compilerContentQueue.trim().length) { - repaintStartTime = null; - return; - } - if (updateTimeout) { window.clearTimeout(updateTimeout); } updateTimeout = window.setTimeout(() => { const css = this.updateCss(compilerContentQueue); - const repaintTime = performance.now() - repaintStartTime; - repaintStartTime = null; if (css === null) { return; } - this.triggerEvent(Runtime.STYLIFY_REPAINTED_EVENT, { - css: css, - repaintTime: repaintTime, - compilationResult: this.compilationResult, - content: compilerContentQueue - }); - - repaintStartTime = null; compilerContentQueue = ''; }, this.repaintTimeout); @@ -224,24 +216,20 @@ export class Runtime { } public injectCss(css: string): void { - let el = document.querySelector(`#${Runtime.STYLIFY_STYLE_EL_ID}`); + let el = document.querySelector(`#${Runtime.STYLE_EL_ID}`); if (el) { el.innerHTML = css; } else { el = document.createElement('style'); - el.id = Runtime.STYLIFY_STYLE_EL_ID; + el.id = Runtime.STYLE_EL_ID; el.innerHTML = css; document.head.appendChild(el); } - const elements = document.querySelectorAll(`[${Runtime.STYLIFY_CLOAK_ATTR_NAME}]`); + const elements = document.querySelectorAll(`.${Runtime.CLOAK_CLASS}`); elements.forEach((element) => { - element.removeAttribute(Runtime.STYLIFY_CLOAK_ATTR_NAME); - this.triggerEvent(Runtime.STYLIFY_UNCLOAK_EVENT, { - id: element.getAttribute(Runtime.STYLIFY_CLOAK_ATTR_NAME) || null, - el: element - }); + element.classList.remove(Runtime.CLOAK_CLASS); }); } diff --git a/packages/stylify/tests/jest/components-mangle-selectors/expected/index.css b/packages/stylify/tests/jest/components-mangle-selectors/expected/index.css index 5a7cf848..4f7b0f45 100644 --- a/packages/stylify/tests/jest/components-mangle-selectors/expected/index.css +++ b/packages/stylify/tests/jest/components-mangle-selectors/expected/index.css @@ -1,36 +1,36 @@ -._tfd4v84hkk, -._4etcappqdbo{ +._au6cg35, +._qi1d4vf{ padding:8px } -._shp0ceaccug, -._4etcappqdbo{ +._iehecp9, +._qi1d4vf{ background-color:#000 } -._cdbb5mftv58, -._4etcappqdbo{ +._9r9hq5f, +._qi1d4vf{ display:inline-block } -._sdof9i580t, -._4etcappqdbo, -._0338oggc0hg{ +._0mhe3cd, +._qi1d4vf, +._kbb49ls{ font-size:24px } -._0ti2i3k4bpg, -._dd39h43lg08{ +._ut8ieu2, +._lmnpjdv{ max-width:800px } -._dkjra4j66mo, -._dd39h43lg08{ +._v79j45i, +._lmnpjdv{ margin:0 auto } -._i9eu7s1simg, -._0338oggc0hg{ +._uvjc7sm, +._kbb49ls{ color:green } @media (min-width: 768px) { -._09t5nug0sk, -._0338oggc0hg{ +._3mes49q, +._kbb49ls{ font-size:32px } } \ No newline at end of file diff --git a/packages/stylify/tests/jest/components-mangle-selectors/expected/index.html b/packages/stylify/tests/jest/components-mangle-selectors/expected/index.html index 66544896..17051219 100644 --- a/packages/stylify/tests/jest/components-mangle-selectors/expected/index.html +++ b/packages/stylify/tests/jest/components-mangle-selectors/expected/index.html @@ -1,3 +1,3 @@ - -
-

+