feat: support typescript & dynamic parsing in material parser

This commit is contained in:
gengyang 2020-08-14 16:41:08 +08:00
parent c343a59c26
commit 6168ef59c7
792 changed files with 169788 additions and 33157 deletions

View File

@ -1,4 +1,14 @@
# @ali/lowcode-engine-material-parser
# @ali/lowcode-material-parser
> 入料模块
本模块负责物料接入,能自动扫描、解析源码组件,并最终产出一份符合 **[《中后台搭建组件描述协议》](https://yuque.antfin-inc.com/rt656r/spec/pbeaqx)** 的 **JSON Schema**
详见[文档](https://yuque.antfin-inc.com/ali-lowcode/docs/tyktrt)。
## demo
```shell
cd demo
node index.js
```

View File

@ -0,0 +1,76 @@
import React from 'react';
import PropTypes from 'prop-types';
import './main.scss';
class Demo extends React.Component {
render() {
return <div> Test </div>;
}
}
Demo.propTypes = {
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: PropTypes.node,
// A React element (ie. <MyComponent />).
optionalElement: PropTypes.element,
// A React element type (ie. MyComponent).
optionalElementType: PropTypes.elementType,
// You can also declare that a prop is an instance of a class. This uses
// JS's instanceof operator.
optionalMessage: PropTypes.instanceOf(Demo),
// You can ensure that your prop is limited to specific values by treating
// it as an enum.
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// An object that could be one of many types
optionalUnion: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Demo)]),
// An array of a certain type
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// An object with property values of a certain type
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// You can chain any of the above with `isRequired` to make sure a warning
// is shown if the prop isn't provided.
// An object taking on a particular shape
optionalObjectWithShape: PropTypes.shape({
optionalProperty: PropTypes.string,
requiredProperty: PropTypes.number.isRequired,
}),
optionalObjectWithShape2: PropTypes.shape({
optionalProperty: PropTypes.string,
requiredProperty: PropTypes.number.isRequired,
}).isRequired,
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
optionalProperty: PropTypes.string,
requiredProperty: PropTypes.number.isRequired,
}),
requiredFunc: PropTypes.func.isRequired,
// A value of any data type
requiredAny: PropTypes.any.isRequired,
};
Demo.defaultProps = {};
export default Demo;

View File

@ -0,0 +1,11 @@
const parse = require('../lib').default;
(async () => {
const options = {
entry: './component.jsx',
accesser: 'local',
};
const actual = await parse(options);
console.log(JSON.stringify(actual, null, 2));
})();

View File

@ -8,23 +8,29 @@
"schemas"
],
"devDependencies": {
"@babel/runtime": "^7.11.2",
"@types/babel__generator": "^7.6.1",
"@types/babel__traverse": "^7.0.13",
"@types/debug": "^4.1.5",
"@types/fs-extra": "^8.0.1",
"@types/js-yaml": "^3.12.2",
"@types/lodash": "^4.14.149",
"@types/prop-types": "^15.7.3",
"@types/semver": "^7.1.0",
"ava": "3.8.1",
"globby": "^10.0.1",
"jest": "^24.8.0",
"jest-watch-typeahead": "^0.3.1",
"js-yaml": "^3.13.1",
"json-schema-to-typescript": "^8.2.0",
"ts-node": "^8.10.2",
"tslib": "^1.11.1",
"typescript": "^3.8.3"
},
"scripts": {
"build": "tsc",
"prebuild": "npm run schema",
"test": "ava",
"test": "ava -T 100000",
"test:snapshot": "ava --update-snapshots",
"schema": "node ./scripts/transform.js"
},
@ -52,10 +58,14 @@
"debug": "^4.1.1",
"fs-extra": "^8.1.0",
"lodash": "^4.17.15",
"parse-prop-types": "^0.3.0",
"prop-types": "^15.7.2",
"react-docgen": "^5.3.0",
"react-docgen-typescript": "^1.16.5",
"semver": "^7.1.3",
"short-uuid": "^3.1.1",
"typescript": "^3.8.3"
"typescript": "^3.9.5",
"vm2": "^3.9.2"
},
"publishConfig": {
"registry": "https://registry.npm.alibaba-inc.com"

View File

@ -9,7 +9,6 @@ export default async function(
): Promise<ComponentMeta[]> {
const containerList = [];
for (const matParsedModel of matParsedModels) {
// TODO 可以开放扩展点让上层使用者指定导出哪些组件或者不导出哪些组件
// 默认排除掉 defaultExportName 为空的组件
if (!matParsedModel.componentName) {
log('skip');

View File

@ -1,3 +1,4 @@
import { remove } from 'fs-extra';
export { default as validate } from './validate';
export { default as schema } from './validate/schema.json';
@ -11,16 +12,26 @@ import parse from './parse';
import localize from './localize';
export default async function(options: IMaterializeOptions): Promise<ComponentMeta[]> {
const { accesser = 'local' } = options;
const { accesser = 'local', entry = '' } = options;
let workDir = entry;
let moduleDir = '';
if (accesser === 'online') {
const entry = await localize(options);
options.entry = entry;
const result = await localize(options);
workDir = result.workDir;
moduleDir = result.moduleDir;
options.entry = moduleDir;
}
const scanedModel = await scan(options);
const parsedModel = await parse({
filePath: scanedModel.entryFilePath,
fileContent: scanedModel.entryFileContent,
...scanedModel,
accesser,
npmClient: options.npmClient,
workDir,
moduleDir,
});
const result = await generate(scanedModel, parsedModel);
if (workDir && accesser === 'online') {
await remove(workDir);
}
return result;
}

View File

@ -20,29 +20,37 @@ const log = debug.extend('mat');
* @memberof OnlineAccesser
*/
export async function createFakePackage(params: {
tempDir: string;
workDir: string;
pkgName: string;
pkgVersion: string;
npmClient?: string;
}): Promise<void> {
// 创建临时组件包
const tempDir = params.tempDir;
const pkgJsonFilePath = join(tempDir, 'package.json');
const workDir = params.workDir;
const pkgJsonFilePath = join(workDir, 'package.json');
await ensureFile(pkgJsonFilePath);
await writeFile(
pkgJsonFilePath,
JSON.stringify({
name: params.pkgName,
version: params.pkgVersion || '0.0.0',
dependencies: {
[params.pkgName]: params.pkgVersion || 'latest',
JSON.stringify(
{
name: params.pkgName,
version: params.pkgVersion || '0.0.0',
dependencies: {
[params.pkgName]: params.pkgVersion || 'latest',
react: 'latest',
'react-dom': 'latest',
'parse-prop-types': '^0.3.0',
typesync: 'latest',
},
},
}),
null,
2,
),
);
// 安装依赖
const npmClient = params.npmClient || 'tnpm';
await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: tempDir } as any);
await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
}
/**
@ -52,12 +60,12 @@ export async function createFakePackage(params: {
* @returns {Promise<string>}
* @memberof LocalGenerator
*/
export async function createTempDir(): Promise<string> {
const tempDirName = uuid.generate();
const tempDir = join(__dirname, '../../node_modules/.temp/', tempDirName);
await ensureDir(tempDir);
log('create temp dir successfully', tempDir);
return tempDir;
export async function createworkDir(): Promise<string> {
const workDirName = uuid.generate();
const workDir = join(__dirname, '../../node_modules/.temp/', workDirName);
await ensureDir(workDir);
log('create temp dir successfully', workDir);
return workDir;
}
/**
@ -69,32 +77,39 @@ export async function createTempDir(): Promise<string> {
* @memberof OnlineAccesser
*/
export function getPkgNameAndVersion(pkgNameWithVersion: string): { [key: string]: any } {
const matches = pkgNameWithVersion.match(/(@\d+\.\d+\.\d+)$/);
const matches = pkgNameWithVersion.match(/(@[^/]+)$/);
if (!matches) {
return {
name: pkgNameWithVersion,
};
}
const semverObj = semver.coerce(matches[0]);
const name = pkgNameWithVersion.replace(matches[0], '');
return {
version: semverObj && semverObj.version,
version: matches[0].slice(1),
name,
};
}
// 将问题转化为本地物料化场景
export default async function localize(options: IMaterializeOptions): Promise<string> {
export default async function localize(
options: IMaterializeOptions,
): Promise<{
workDir: string;
moduleDir: string;
}> {
// 创建临时目录
const tempDir = await createTempDir();
const workDir = await createworkDir();
// 创建组件包
const { name, version } = getPkgNameAndVersion(options.entry);
await createFakePackage({
pkgName: name,
pkgVersion: version,
tempDir,
workDir,
npmClient: options.npmClient,
});
return join(tempDir, 'node_modules', name);
return {
workDir,
moduleDir: join(workDir, 'node_modules', name),
};
}

View File

@ -1,40 +1,57 @@
const reactDocs = require('react-docgen');
import { transformItem } from './transform';
import { debug } from '../otter-core';
import { IMaterialParsedModel, IMaterialScanModel } from '../types';
import resolver from './resolver';
import handlers from './handlers';
import parseDynamic from './runtime';
import parseJS from './js';
import parseTS from './ts';
import { install, installPeerDeps, installTypeModules } from '../utils';
import { IMaterialScanModel } from '../types';
export default function parse(params: { fileContent: string; filePath: string }): Promise<IMaterialParsedModel[]> {
const { fileContent, filePath } = params;
const result = reactDocs.parse(
fileContent,
(ast: any) => {
ast.__path = filePath;
return resolver(ast);
},
handlers,
{
filename: filePath,
},
);
const coms = result.reduce((res: any[], info: any) => {
if (!info || !info.props) return res;
const props = Object.keys(info.props).reduce((acc: any[], name) => {
try {
const item: any = transformItem(name, info.props[name]);
acc.push(item);
} catch (e) {
} finally {
return acc;
}
}, []);
res.push({
componentName: info.displayName,
props,
meta: info.meta || {},
});
return res;
}, []);
return coms;
export interface IParseArgs extends IMaterialScanModel {
accesser?: 'online' | 'local';
npmClient?: string;
workDir: string;
moduleDir: string;
typingsFileAbsolutePath?: string;
mainFileAbsolutePath: string;
moduleFileAbsolutePath?: string;
}
export default async (args: IParseArgs) => {
const { typingsFileAbsolutePath, mainFileAbsolutePath, moduleFileAbsolutePath = mainFileAbsolutePath } = args;
if (args.accesser === 'local') {
if (moduleFileAbsolutePath.endsWith('ts') || moduleFileAbsolutePath.endsWith('tsx')) {
await install(args);
return parseTS(moduleFileAbsolutePath);
} else {
try {
return parseJS(moduleFileAbsolutePath);
} catch (e) {
await install(args);
const info = parseDynamic(mainFileAbsolutePath);
if (!info || !info.length) {
throw Error();
}
return info;
}
}
} else if (args.accesser === 'online') {
// ts
if (typingsFileAbsolutePath) {
await installTypeModules(args);
return parseTS(typingsFileAbsolutePath);
}
// js
try {
// try dynamic parsing first
await installPeerDeps(args);
const info = parseDynamic(mainFileAbsolutePath);
if (!info || !info.length) {
throw Error();
}
return info;
} catch (e) {
console.error(e);
// if error, use static js parsing instead
return parseJS(moduleFileAbsolutePath);
}
}
return parseJS(moduleFileAbsolutePath);
};

View File

@ -3,12 +3,12 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
import { namedTypes as t } from 'ast-types';
import getTSType from '../utils/getTSType';
import getRoot from '../utils/getRoot';
import parseTS from '../../ts';
const { unwrapUtilityType } = require('react-docgen/dist/utils/flowUtilityTypes');
const { getFlowType, getPropertyName, resolveToValue } = require('react-docgen').utils;
const setPropDescription = require('react-docgen/dist/utils/setPropDescription').default;
@ -92,4 +92,16 @@ export default function flowTypeHandler(documentation: any, path: any) {
applyToFlowTypeProperties(documentation, flowTypesPath, (propertyPath: any, typeParams: any) => {
setPropDescriptor(documentation, propertyPath, typeParams);
});
// const root = getRoot(path);
// const { __path } = root;
// const result = parseTS(__path);
// result.length &&
// Object.keys(result[0].props).forEach((propName: string) => {
// const propItem = result[0].props[propName];
// const propDescriptor = documentation.getPropDescriptor(propName);
// propDescriptor.required = propItem.required;
// propDescriptor.type = propItem.type;
// propDescriptor.description = propItem.description;
// propDescriptor.defaultValue = propItem.defaultValue;
// });
}

View File

@ -0,0 +1,40 @@
const reactDocs = require('react-docgen');
import { transformItem } from '../transform';
import { IMaterialParsedModel } from '../../types';
import { loadFile } from '../../utils';
import resolver from './resolver';
import handlers from './handlers';
export default function parse(filePath: string): IMaterialParsedModel[] {
const fileContent = loadFile(filePath);
const result = reactDocs.parse(
fileContent,
(ast: any) => {
ast.__path = filePath;
return resolver(ast);
},
handlers,
{
filename: filePath,
},
);
const coms = result.reduce((res: any[], info: any) => {
if (!info || !info.props) return res;
const props = Object.keys(info.props).reduce((acc: any[], name) => {
try {
const item: any = transformItem(name, info.props[name]);
acc.push(item);
} catch (e) {
} finally {
return acc;
}
}, []);
res.push({
componentName: info.displayName,
props,
meta: info.meta || {},
});
return res;
}, []);
return coms;
}

View File

@ -1,8 +1,7 @@
import { namedTypes as t } from 'ast-types';
const { match, resolveToValue } = require('react-docgen').utils;
const { match } = require('react-docgen').utils;
const { traverseShallow } = require('react-docgen/dist/utils/traverse');
import isReactComponentStaticMember from './isReactComponentStaticMember';
import getRoot from '../utils/getRoot';
function findAssignedMethods(scope: any, idPath: any) {
const results: any[] = [];
@ -12,7 +11,7 @@ function findAssignedMethods(scope: any, idPath: any) {
}
const name = idPath.node.name;
const idScope = idPath.scope.lookup(idPath.node.name);
// const idScope = idPath.scope.lookup(idPath.node.name);
traverseShallow(scope.path, {
visitAssignmentExpression: function(path: any) {
@ -34,21 +33,4 @@ function findAssignedMethods(scope: any, idPath: any) {
return results.filter((x) => !isReactComponentStaticMember(x.get('left')));
}
export default findAssignedMethods;
// const findAssignedMethodsFromScopes = (scope: any, idPath: any) => {
// const rootNode = getRoot(idPath);
// let { __scope: scopes = [] } = rootNode;
// if (!scopes.find((x: any) => x.scope === scope && x.idPath === idPath)) {
// scopes = [
// ...scopes,
// {
// scope,
// idPath,
// },
// ];
// }
// return scopes.map(({ scope: s, idPath: id }: any) => findAssignedMethods(s, id)).flatMap((x: any) => x);
// };
// export { findAssignedMethodsFromScopes };
export default findAssignedMethods;

View File

@ -1,11 +1,3 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import { namedTypes as t, visit } from 'ast-types';
import { uniqBy } from 'lodash';
import checkIsIIFE from './checkIsIIFE';
@ -82,7 +74,27 @@ function getDefinition(definition: any, cache: ICache = {}): any {
definition = resolveTranspiledClass(definition);
}
} else if (t.SequenceExpression.check(definition.node)) {
return getDefinition(resolveToValue(definition.get('expressions').get(0)), cache);
const classNameNode = definition.parent.get('id').node;
const localNames: string[] = [];
let node = definition.get('expressions', 0).node;
while (t.AssignmentExpression.check(node)) {
// @ts-ignore
const name = node.left.name;
if (name) {
localNames.push(name);
}
node = node.right;
}
definition.get('expressions').each((x: any) => {
if (!x.name) return;
if (t.AssignmentExpression.check(x.node) && t.MemberExpression.check(x.node.left)) {
const objectName = x.node.left.object.name;
if (localNames.includes(objectName)) {
x.get('left', 'object').replace(classNameNode);
}
}
});
definition = getDefinition(resolveToValue(definition.get('expressions').get(0)), cache);
} else {
return resolveImport(definition, (ast: any, sourcePath: string) => {
const importMeta: any[] = [];
@ -146,7 +158,7 @@ function getDefinition(definition: any, cache: ICache = {}): any {
});
}
}
if (definition && !definition.__meta) {
if (definition && (!definition.__meta || Object.keys(definition.__meta).length === 0)) {
definition.__meta = exportMeta;
}
return definition;

View File

@ -1,10 +1,3 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { namedTypes as t, visit } from 'ast-types';
const {

View File

@ -0,0 +1,119 @@
import { isEmpty } from 'lodash';
// import * as path from 'path';
// @ts-ignore
import parsePropTypes from 'parse-prop-types';
import PropTypes from 'prop-types';
import { transformItem } from '../transform';
import { IParseArgs } from '../index';
import requireInSandbox from './requireInSandbox';
export interface IComponentInfo {
component: any;
meta: {
exportName: string;
subName?: string;
};
}
const reservedKeys = [
'propTypes',
'defaultProps',
'name',
'arguments',
'caller',
'length',
'contextTypes',
'displayName',
'__esModule',
'version',
];
function getKeys(com: any) {
const keys = Object.keys(com).filter((x) => {
return !reservedKeys.includes(x) && !x.startsWith('_');
});
return keys;
}
function isComponent(obj: any) {
return typeof obj === 'function' && (obj.hasOwnProperty('propTypes') || obj.hasOwnProperty('defaultProps'));
}
export default function(filePath: string) {
// const { filePath } = arg;
// const modulePath = path.resolve(workDir, 'node_modules', 'parse-prop-types');
// const parsePropTypes = require(modulePath).default;
const Com = requireInSandbox(filePath, PropTypes);
const components: IComponentInfo[] = [];
let index = 0;
if (Com.__esModule) {
const keys = getKeys(Com);
keys.forEach((k) => {
if (isComponent(Com[k])) {
components.push({
component: Com[k],
meta: {
exportName: k,
},
});
}
});
} else {
if (isComponent(Com)) {
components.push({
component: Com,
meta: {
exportName: 'default',
},
});
}
}
// dps
while (index < components.length) {
const item = components[index++];
const keys = getKeys(item.component);
const subs = keys
.filter((k) => isComponent(item.component[k]))
.map((k) => ({
component: item.component[k],
meta: {
...item.meta,
subName: k,
},
}));
if (subs.length) {
components.splice(index, 0, ...subs);
}
}
const result = components.reduce((acc: any, { meta, component }) => {
const componentInfo = parsePropTypes(component);
if (!isEmpty(componentInfo)) {
const props = Object.keys(componentInfo).reduce((acc: any[], name) => {
try {
const item: any = transformItem(name, componentInfo[name]);
acc.push(item);
} catch (e) {
} finally {
return acc;
}
}, []);
return [
...acc,
{
meta,
props,
componentName: meta.subName || meta.exportName || component.displayName,
},
];
}
return acc;
}, []);
return result;
}

View File

@ -0,0 +1,37 @@
import { readFileSync } from 'fs-extra';
import { NodeVM } from 'vm2';
// import PropTypes from 'prop-types';
const cssPattern = /\.(css|scss|sass|less)$/;
function requireInSandbox(filePath: string, PropTypes: any) {
const vm = new NodeVM({
sandbox: {},
sourceExtensions: ['js', 'css', 'scss', 'sass', 'less'],
compiler: (code, filename) => {
if (filename.match(cssPattern)) {
return `
const handler = {
get() {
return new Proxy({}, handler);
},
};
const proxiedObject = new Proxy({}, handler);
module.exports = proxiedObject;
`;
} else {
return code;
}
},
require: {
external: true,
context: 'sandbox',
mock: {
'prop-types': PropTypes,
},
},
});
const fileContent = readFileSync(filePath, { encoding: 'utf8' });
return vm.run(fileContent, filePath);
}
export default requireInSandbox;

View File

@ -1,3 +1,5 @@
import { omit, pick } from 'lodash';
export function transformType(itemType: any) {
if (typeof itemType === 'string') return itemType;
const { name, elements, value = elements, computed, required, type } = itemType;
@ -27,10 +29,12 @@ export function transformType(itemType: any) {
return eval(value);
case 'enum':
case 'tuple':
case 'oneOf':
result.type = 'oneOf';
result.value = value.map(transformType);
break;
case 'union':
case 'oneOfType':
result.type = 'oneOfType';
result.value = value.map(transformType);
break;
@ -46,8 +50,12 @@ export function transformType(itemType: any) {
case 'Array':
case 'arrayOf': {
result.type = 'arrayOf';
const v = transformType(value[0]);
if (typeof v.type === 'string') result.value = v.type;
const v = omit(transformType(value[0]), ['isRequired']);
if (Object.keys(v).length === 1 && v.type) {
result.value = v.type;
} else {
result.value = v;
}
break;
}
case 'signature': {
@ -56,15 +64,15 @@ export function transformType(itemType: any) {
break;
}
result.type = 'shape';
const {
signature: { properties },
} = type;
const properties = type?.signature?.properties || [];
if (properties.length === 0) {
result.type = 'object';
} else if (properties.length === 1 && typeof properties[0].key === 'object') {
result.type = 'objectOf';
const v = transformType(properties[0].value);
if (typeof v.type === 'string') result.value = v.type;
} else if (properties.length === 1 && properties[0].key === '__call') {
result.type = 'func';
} else {
result.value = properties
.filter((item: any) => typeof item.key !== 'object')
@ -75,9 +83,7 @@ export function transformType(itemType: any) {
} = prop;
return transformItem(key, {
...others,
type: {
name,
},
type: pick(prop.value, ['name', 'value']),
});
});
}
@ -122,7 +128,7 @@ export function transformType(itemType: any) {
}
export function transformItem(name: string, item: any) {
const { description, flowType, tsType, type = tsType || flowType, required, defaultValue } = item;
const { description, flowType, tsType, type = tsType || flowType, required, defaultValue, ...others } = item;
const result: any = {
name,
};
@ -130,11 +136,16 @@ export function transformItem(name: string, item: any) {
if (type) {
result.propType = transformType({
...type,
...omit(others, ['name']),
required: !!required,
});
}
if (description) {
result.description = description;
if (description.includes('\n')) {
result.description = description.split('\n')[0];
} else {
result.description = description;
}
}
if (defaultValue !== undefined) {
try {

View File

@ -0,0 +1,338 @@
import { Parser, ComponentDoc } from 'react-docgen-typescript';
import ts, { SymbolFlags, TypeFlags } from 'typescript';
import { isEmpty, isEqual } from 'lodash';
import { transformItem } from '../transform';
function getSymbolName(symbol: ts.Symbol) {
// @ts-ignore
const prefix: string = symbol.parent && getSymbolName(symbol.parent);
const name = symbol.getName();
if (prefix && prefix.length <= 20) {
return `${prefix}.${name}`;
}
return name;
}
const blacklistNames = [
'prototype',
'getDerivedStateFromProps',
'propTypes',
'defaultProps',
'contextTypes',
'displayName',
'contextType',
'Provider',
'Consumer',
];
function getDocgenTypeHelper(
checker: ts.TypeChecker,
type: ts.Type,
skipRequired = false,
parentIds: number[] = [],
isRequired: boolean = false,
): any {
function isTuple(type: ts.Type) {
// @ts-ignore use internal methods
return checker.isArrayLikeType(type) && !checker.isArrayType(type);
}
// if (type.aliasSymbol && type.aliasSymbol.getName() === 'ReactNode') {
// return 'children';
// }
let required: boolean;
if (isRequired !== undefined) {
required = isRequired;
} else {
required = !(type.flags & SymbolFlags.Optional) || isRequired;
}
function makeResult(typeInfo: object) {
if (skipRequired) {
return {
raw: checker.typeToString(type),
...typeInfo,
};
} else {
return {
required,
raw: checker.typeToString(type),
...typeInfo,
};
}
}
function getShapeFromArray(symbolArr: ts.Symbol[], type: ts.Type) {
const shape: {
key:
| {
name: string;
}
| string;
value: any;
}[] = symbolArr.map((prop) => {
const propType = checker.getTypeOfSymbolAtLocation(
prop,
prop.valueDeclaration || (prop.declarations && prop.declarations[0]) || {},
);
return {
key: prop.getName(),
value: getDocgenTypeHelper(
checker,
propType,
false,
// @ts-ignore
[...parentIds, type.id],
// @ts-ignore
prop?.valueDeclaration?.questionToken ? false : undefined,
),
};
});
// @ts-ignore use internal methods
if (checker.isArrayLikeType(type)) {
return shape;
}
if (type.getStringIndexType()) {
// @ts-ignore use internal methods
if (!type.stringIndexInfo) {
return shape;
}
shape.push({
key: {
name: 'string',
},
// @ts-ignore use internal methods
value: getDocgenTypeHelper(checker, type.stringIndexInfo.type, false, [...parentIds, type.id]),
});
} else if (type.getNumberIndexType()) {
// @ts-ignore use internal methods
if (!type.numberIndexInfo) {
return shape;
}
shape.push({
key: {
name: 'number',
},
// @ts-ignore use internal methods
value: getDocgenTypeHelper(checker, type.numberIndexInfo.type, false, [...parentIds, type.id]),
});
}
return shape;
}
function getShape(type: ts.Type) {
const { symbol } = type;
if (symbol && symbol.members) {
// @ts-ignore
const props: ts.Symbol[] = Array.from(symbol.members.values());
return getShapeFromArray(
props.filter((prop) => prop.getName() !== '__index'),
type,
);
} else {
// @ts-ignore
const args = type.resolvedTypeArguments || [];
const props = checker.getPropertiesOfType(type);
const shape = getShapeFromArray(props.slice(0, args.length), type);
return shape;
}
}
const pattern = /^__global\.(.+)$/;
// @ts-ignore
if (parentIds.includes(type.id)) {
return makeResult({
name: checker.typeToString(type),
});
}
if (type.symbol) {
const symbolName = getSymbolName(type.symbol);
if (symbolName) {
const matches = pattern.exec(symbolName);
if (matches) {
return makeResult({
name: matches[1],
});
}
}
}
if (type.flags & TypeFlags.Number) {
return makeResult({
name: 'number',
});
} else if (type.flags & TypeFlags.String) {
return makeResult({
name: 'string',
});
} else if (type.flags & TypeFlags.NumberLiteral) {
return makeResult({
name: 'literal',
// @ts-ignore
value: type.value,
});
} else if (type.flags & TypeFlags.Literal) {
return makeResult({
name: 'literal',
value: checker.typeToString(type),
});
// @ts-ignore
} else if (type.flags & TypeFlags.DisjointDomains) {
return makeResult({
name: checker.typeToString(type),
});
} else if (type.flags & TypeFlags.Any) {
return makeResult({
name: 'any',
});
} else if (type.flags & TypeFlags.Union) {
return makeResult({
name: 'union',
// @ts-ignore
value: type.types.map((t) => getDocgenTypeHelper(checker, t, true, [...parentIds, type.id])),
});
} else if (type.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
if (isTuple(type)) {
const props = getShape(type);
return makeResult({
name: 'union',
value: props.map((p) => p.value),
});
// @ts-ignore
} else if (checker.isArrayType(type)) {
return makeResult({
name: 'Array',
// @ts-ignore
elements: [getDocgenTypeHelper(checker, type.typeArguments[0], false, [...parentIds, type.id])],
});
} else if (type.aliasSymbol) {
return makeResult({
name: getSymbolName(type.aliasSymbol),
});
// @ts-ignore
} else if (type?.symbol?.valueDeclaration?.parameters?.length) {
return makeResult({
name: 'func',
});
} else {
const props = getShape(type);
return makeResult({
name: 'signature',
type: {
signature: {
properties: props,
},
},
});
}
} else {
return makeResult({
name: 'any',
});
}
}
class MyParser extends Parser {
getDocgenType(propType: ts.Type): any {
// @ts-ignore
const result = getDocgenTypeHelper(this.checker, propType, true);
return result;
}
}
const compilerOptions = {
jsx: ts.JsxEmit.React,
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.Latest,
};
interface SymbolWithMeta extends ts.Symbol {
meta?: {
exportName: string;
subName?: string;
};
}
export default function parseTS(filePathOrPaths: string | string[], parserOpts: any = {}): ComponentDoc[] {
const filePaths = Array.isArray(filePathOrPaths) ? filePathOrPaths : [filePathOrPaths];
const program = ts.createProgram(filePaths, compilerOptions);
const parser = new MyParser(program, parserOpts);
const checker = program.getTypeChecker();
const result = filePaths
.map((filePath) => program.getSourceFile(filePath))
.filter((sourceFile) => typeof sourceFile !== 'undefined')
.reduce((docs: any[], sourceFile) => {
const moduleSymbol = checker.getSymbolAtLocation(sourceFile as ts.Node);
if (!moduleSymbol) {
return docs;
}
const exportSymbols = checker.getExportsOfModule(moduleSymbol);
for (let index = 0; index < exportSymbols.length; index++) {
const sym: SymbolWithMeta = exportSymbols[index];
const name = sym.getName();
if (blacklistNames.includes(name)) {
continue;
}
// @ts-ignore
const info = parser.getComponentInfo(sym, sourceFile, parserOpts.componentNameResolver);
if (info === null) {
continue;
}
const exportName = sym.meta && sym.meta.exportName;
const meta = {
subName: exportName ? name : '',
exportName: exportName ? exportName : name,
};
if (docs.find((x) => isEqual(x.meta, meta))) {
continue;
}
docs.push({
...info,
meta,
});
// find sub components
if (!!sym.declarations && sym.declarations.length === 0) {
continue;
}
const type = checker.getTypeOfSymbolAtLocation(sym, sym.valueDeclaration || sym.declarations[0]);
Array.prototype.push.apply(
exportSymbols,
type.getProperties().map((x: SymbolWithMeta) => {
x.meta = { exportName: name };
return x;
}),
);
}
return docs;
}, []);
const coms = result.reduce((res: any[], info: any) => {
if (!info || !info.props || isEmpty(info.props)) return res;
const props = Object.keys(info.props).reduce((acc: any[], name) => {
try {
const item: any = transformItem(name, info.props[name]);
acc.push(item);
} catch (e) {
console.log('error', e);
} finally {
return acc;
}
}, []);
res.push({
componentName: info?.meta?.exportName || info.displayName,
props,
meta: info.meta || {},
});
return res;
}, []);
return coms;
}

View File

@ -1,16 +1,15 @@
import { IMaterializeOptions, IMaterialScanModel, SourceType } from './types';
import { pathExists, readFile, lstatSync } from 'fs-extra';
import { join } from 'path';
import { IMaterializeOptions, IMaterialScanModel } from './types';
import { pathExists, lstatSync } from 'fs-extra';
import { join, isAbsolute, resolve } from 'path';
import { debug } from './otter-core';
import { resolvePkgJson } from './utils';
const log = debug.extend('mat');
export default async function scan(options: IMaterializeOptions): Promise<IMaterialScanModel> {
const model: IMaterialScanModel = {
pkgName: '',
pkgVersion: '',
sourceType: SourceType.MODULE,
entryFilePath: '',
entryFileContent: '',
mainFileAbsolutePath: '',
mainFilePath: '',
};
log('options', options);
@ -18,7 +17,6 @@ export default async function scan(options: IMaterializeOptions): Promise<IMater
let entryFilePath = options.entry;
const stats = lstatSync(entryFilePath);
if (!stats.isFile()) {
let mainFilePath = '';
const pkgJsonPath = join(entryFilePath, 'package.json');
// 判断是否存在 package.json
if (!(await pathExists(pkgJsonPath))) {
@ -29,40 +27,27 @@ export default async function scan(options: IMaterializeOptions): Promise<IMater
model.pkgName = pkgJson.name;
model.pkgVersion = pkgJson.version;
if (pkgJson.module) {
// 支持 es module
model.sourceType = SourceType.MODULE;
mainFilePath = pkgJson.module;
} else if (pkgJson.main) {
// 支持 commonjs
model.sourceType = SourceType.MAIN;
mainFilePath = pkgJson.main;
} else {
mainFilePath = './index.js';
model.moduleFilePath = pkgJson.module;
model.moduleFileAbsolutePath = join(entryFilePath, pkgJson.module);
}
model.mainFilePath = mainFilePath;
entryFilePath = join(entryFilePath, mainFilePath);
model.mainFilePath = pkgJson.main || './index.js';
model.mainFileAbsolutePath = join(entryFilePath, pkgJson.main);
const typingsFilePath = pkgJson.typings || pkgJson.types || './lib/index.d.ts';
const typingsFileAbsolutePath = join(entryFilePath, typingsFilePath);
if (await pathExists(typingsFileAbsolutePath)) {
model.typingsFileAbsolutePath = typingsFileAbsolutePath;
model.typingsFilePath = typingsFilePath;
}
} else if (isAbsolute(entryFilePath)) {
model.mainFilePath = entryFilePath;
model.mainFileAbsolutePath = entryFilePath;
} else {
model.mainFilePath = entryFilePath;
model.mainFileAbsolutePath = resolve(entryFilePath);
}
log('entryFilePath', entryFilePath);
const entryFileContent = await loadFile(entryFilePath);
log('entryFile', entryFileContent);
model.entryFilePath = entryFilePath;
model.entryFileContent = entryFileContent;
// 记录入口文件
log('model', model);
return model;
}
export async function loadFile(filePath: string): Promise<string> {
const content: string | Buffer = await readFile(filePath);
if (typeof content === 'string') {
return content;
}
return content.toString();
}
export async function resolvePkgJson(pkgJsonPath: string): Promise<{ [k: string]: any }> {
const content = await loadFile(pkgJsonPath);
const json = JSON.parse(content);
return json;
}

View File

@ -2,18 +2,22 @@
*
*/
interface IMaterialScanModel {
/** 标记物料组件包所使用的模块规范 */
sourceType: 'module' | 'main';
/** 入口文件路径 */
entryFilePath: string;
/** 入口文件内容 */
entryFileContent: string;
/** main文件相对路径 */
mainFilePath: string;
/** 当前包名 */
pkgName: string;
/** 当前包版本 */
pkgVersion: string;
/** main文件相对路径 */
mainFilePath: string;
/** module文件相对路径 */
moduleFilePath?: string;
/** typings文件相对路径 */
typingsFilePath?: string;
/** main文件绝对路径 */
mainFileAbsolutePath: string;
/** module文件绝对路径 */
moduleFileAbsolutePath?: string;
/** typings文件绝对路径 */
typingsFileAbsolutePath?: string;
}
export default IMaterialScanModel;

View File

@ -22,6 +22,11 @@ interface IMaterializeOptions {
*/
accesser: 'local' | 'online';
/**
*
*/
mode?: 'static' | 'dynamic' | 'mixed' | 'auto'
/**
*
*/

View File

@ -1,11 +0,0 @@
/**
*
*/
enum SourceType {
/** ES6 规范 */
MODULE = 'module',
/** CommonJS 规范 */
MAIN = 'main',
}
export default SourceType;

View File

@ -7,7 +7,6 @@ import IExtensionConfigManifest from './IExtensionConfigManifest';
import IMaterializeOptions from './IMaterializeOptions';
import IMaterialScanModel from './IMaterialScanModel';
import { IMaterialParsedModel } from './IMaterialParsedModel';
import SourceType from './SourceType';
export {
ExtensionName,
@ -15,7 +14,6 @@ export {
IMaterialParsedModel,
IMaterializeOptions,
IMaterialScanModel,
SourceType,
ChannelType,
EcologyType,
IAccesser,

View File

@ -0,0 +1,67 @@
import { pathExists, readFileSync, writeFile } from 'fs-extra';
import * as path from 'path';
import spawn from 'cross-spawn-promise';
export async function isNPMInstalled(args: { workDir: string; moduleDir: string; npmClient?: string }) {
return await pathExists(path.join(args.workDir, 'node_modules'));
}
export async function install(args: { workDir: string; moduleDir: string; npmClient?: string }) {
if (await isNPMInstalled(args)) return;
const { workDir, moduleDir, npmClient = 'tnpm' } = args;
try {
await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
} catch (e) {}
}
export async function installTypeScript(args: { workDir: string; moduleDir: string; npmClient?: string }) {
if (await isNPMInstalled(args)) return;
const { workDir, moduleDir, npmClient = 'tnpm' } = args;
await spawn(npmClient, ['i', 'typescript'], { stdio: 'inherit', cwd: workDir } as any);
}
export async function installPeerDeps(args: { workDir: string; moduleDir: string; npmClient?: string }) {
const { workDir, moduleDir, npmClient = 'tnpm' } = args;
const modulePkgJsonPath = path.resolve(moduleDir, 'package.json');
if (!(await pathExists(modulePkgJsonPath))) {
return;
}
const pkgJsonPath = path.resolve(workDir, 'package.json');
if (!(await pathExists(pkgJsonPath))) {
return;
}
const modulePkgJson = await resolvePkgJson(modulePkgJsonPath);
const pkgJson = await resolvePkgJson(pkgJsonPath);
const { peerDependencies = {} } = modulePkgJson;
pkgJson.dependencies = pkgJson.dependencies || {};
pkgJson.dependencies = {
...pkgJson.dependencies,
...peerDependencies,
};
await writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
await spawn(npmClient, ['i'], { stdio: 'inherit', cwd: workDir } as any);
}
export async function installTypeModules(args: { workDir: string; moduleDir: string; npmClient?: string }) {
const { workDir, moduleDir, npmClient = 'tnpm' } = args;
const pkgJsonPath = path.resolve(moduleDir, 'package.json');
if (!(await pathExists(pkgJsonPath))) {
return;
}
await spawn(npmClient.replace('m', 'x'), ['typesync'], { stdio: 'inherit', cwd: workDir } as any);
}
export async function resolvePkgJson(pkgJsonPath: string): Promise<{ [k: string]: any }> {
const content = await loadFile(pkgJsonPath);
const json = JSON.parse(content);
return json;
}
export function loadFile(filePath: string): string {
const content: string | Buffer = readFileSync(filePath);
if (typeof content === 'string') {
return content;
}
return content.toString();
}

View File

@ -0,0 +1,17 @@
import test from 'ava';
import parse from '../src';
import { IMaterializeOptions } from '../src/types';
import { getFromFixtures } from './helpers';
const antdComptPath = getFromFixtures('antd-component');
test('antd component by local', async t => {
const options: IMaterializeOptions = {
entry: antdComptPath,
accesser: 'local',
};
const actual = await parse(options);
t.snapshot(actual);
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,644 @@
# Snapshot report for `test/online.ts`
The actual snapshot is saved in `online.ts.snap`.
Generated by [AVA](https://avajs.dev).
## materialize custom breadcrumb by online
> Snapshot 1
[
{
componentName: 'default',
docUrl: '',
npm: {
destructuring: false,
exportName: 'default',
main: 'lib/index.js',
package: 'mc-breadcrumb',
subName: '',
version: '1.0.0',
},
props: [
{
name: 'prefix',
propType: 'string',
},
{
name: 'rtl',
propType: 'bool',
},
{
name: 'children',
propType: {
type: 'instanceOf',
value: 'custom',
},
},
{
name: 'maxNode',
propType: {
type: 'oneOfType',
value: [
'number',
{
type: 'oneOf',
value: [
'auto',
],
},
],
},
},
{
name: 'separator',
propType: {
type: 'oneOfType',
value: [
{
type: 'instanceOf',
value: 'node',
},
'string',
],
},
},
{
name: 'component',
propType: {
type: 'oneOfType',
value: [
'string',
'func',
],
},
},
{
name: 'className',
propType: 'any',
},
{
name: 'locale',
propType: 'object',
},
{
name: 'pure',
propType: 'bool',
},
{
name: 'device',
propType: {
type: 'oneOf',
value: [
'tablet',
'desktop',
'phone',
],
},
},
{
name: 'popupContainer',
propType: 'any',
},
{
name: 'errorBoundary',
propType: {
type: 'oneOfType',
value: [
'bool',
'object',
],
},
},
],
screenshot: '',
title: 'mc-breadcrumb',
},
{
componentName: 'Item',
docUrl: '',
npm: {
destructuring: false,
exportName: 'default',
main: 'lib/index.js',
package: 'mc-breadcrumb',
subName: 'Item',
version: '1.0.0',
},
props: [
{
name: 'prefix',
propType: 'string',
},
{
name: 'rtl',
propType: 'bool',
},
{
name: 'link',
propType: 'string',
},
{
name: 'activated',
propType: 'bool',
},
{
name: 'separator',
propType: {
type: 'instanceOf',
value: 'node',
},
},
{
name: 'className',
propType: 'any',
},
{
name: 'children',
propType: {
type: 'instanceOf',
value: 'node',
},
},
{
name: 'locale',
propType: 'object',
},
{
name: 'pure',
propType: 'bool',
},
{
name: 'device',
propType: {
type: 'oneOf',
value: [
'tablet',
'desktop',
'phone',
],
},
},
{
name: 'popupContainer',
propType: 'any',
},
{
name: 'errorBoundary',
propType: {
type: 'oneOfType',
value: [
'bool',
'object',
],
},
},
],
screenshot: '',
title: 'mc-breadcrumb',
},
]
## materialize react-color by online
> Snapshot 1
[
{
componentName: 'BlockPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'BlockPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 170,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
name: 'triangle',
propType: {
type: 'oneOf',
value: [
'top',
'hide',
],
},
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'CirclePicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'CirclePicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 252,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
defaultValue: 28,
name: 'circleSize',
propType: 'number',
},
{
defaultValue: 14,
name: 'circleSpacing',
propType: 'number',
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'default',
docUrl: '',
npm: {
destructuring: false,
exportName: 'default',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 225,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
defaultValue: false,
name: 'disableAlpha',
propType: 'bool',
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
{
name: 'defaultView',
propType: {
type: 'oneOf',
value: [
'hex',
'rgb',
'hsl',
],
},
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'ChromePicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'ChromePicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 225,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
defaultValue: false,
name: 'disableAlpha',
propType: 'bool',
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
{
name: 'defaultView',
propType: {
type: 'oneOf',
value: [
'hex',
'rgb',
'hsl',
],
},
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'CompactPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'CompactPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'GithubPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'GithubPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 200,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
name: 'triangle',
propType: {
type: 'oneOf',
value: [
'hide',
'top-left',
'top-right',
'bottom-left',
'bottom-right',
],
},
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'HuePicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'HuePicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'PhotoshopPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'PhotoshopPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
name: 'header',
propType: 'string',
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'SketchPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'SketchPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: false,
name: 'disableAlpha',
propType: 'bool',
},
{
defaultValue: 200,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'SliderPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'SliderPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'SwatchesPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'SwatchesPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 320,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
defaultValue: 240,
name: 'height',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
{
componentName: 'TwitterPicker',
docUrl: '',
npm: {
destructuring: true,
exportName: 'TwitterPicker',
main: 'lib/index.js',
package: 'react-color',
subName: '',
version: '2.18.1',
},
props: [
{
defaultValue: 276,
name: 'width',
propType: {
type: 'oneOfType',
value: [
'string',
'number',
],
},
},
{
name: 'triangle',
propType: {
type: 'oneOf',
value: [
'hide',
'top-left',
'top-right',
],
},
},
{
defaultValue: {},
name: 'styles',
propType: 'object',
},
],
screenshot: '',
title: 'react-color',
},
]

View File

@ -9,21 +9,10 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1
{
entryFileContent: `import AIMakeBlank from './basic/AIMakeBlank';␊
import AIMakeIcon from './basic/AIMakeIcon';␊
import AIMakeImage from './basic/AIMakeImage';␊
import AIMakeLink from './basic/AIMakeLink';␊
import AIMakePlaceholder from './basic/AIMakePlaceholder';␊
import AIMakeText from './basic/AIMakeText';␊
import Root from './basic/Root';␊
export { AIMakeBlank, AIMakeIcon, AIMakeImage, AIMakeLink, AIMakePlaceholder, AIMakeText, Root };␊
`,
entryFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine-v0.8/packages/material-parser/test/fixtures/multiple-exported-component/es/index.js',
mainFilePath: 'es/index.js',
pkgName: 'multiple-exported-component',
pkgVersion: '1.0.0',
sourceType: 'module',
}
## scan single exported component
@ -31,94 +20,8 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1
{
entryFileContent: `import _classCallCheck from "@babel/runtime/helpers/classCallCheck";␊
import _createClass from "@babel/runtime/helpers/createClass";␊
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";␊
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";␊
import _inherits from "@babel/runtime/helpers/inherits";␊
/* eslint-disable react/no-unused-prop-types */␊
/* eslint-disable react/require-default-props */␊
import React from 'react';␊
import PropTypes from 'prop-types';␊
import "./main.css";␊
const Demo =␊
/* #__PURE__ */␊
function (_React$Component) {␊
_inherits(Demo, _React$Component);␊
function Demo() {␊
_classCallCheck(this, Demo);␊
return _possibleConstructorReturn(this, _getPrototypeOf(Demo).apply(this, arguments));␊
}␊
_createClass(Demo, [{␊
key: "render",␊
value: function render() {␊
return React.createElement("div", null, " Test ");␊
},␊
}]);␊
return Demo;␊
}(React.Component);␊
Demo.propTypes = {␊
optionalArray: PropTypes.array,␊
optionalBool: PropTypes.bool,␊
optionalFunc: PropTypes.func,␊
optionalNumber: PropTypes.number,␊
optionalObject: PropTypes.object,␊
optionalString: PropTypes.string,␊
optionalSymbol: PropTypes.symbol,␊
// Anything that can be rendered: numbers, strings, elements or an array␊
// (or fragment) containing these types.␊
optionalNode: PropTypes.node,␊
// A React element (ie. <MyComponent />).␊
optionalElement: PropTypes.element,␊
// A React element type (ie. MyComponent).␊
optionalElementType: PropTypes.elementType,␊
// You can also declare that a prop is an instance of a class. This uses␊
// JS's instanceof operator.␊
optionalMessage: PropTypes.instanceOf(Demo),␊
// You can ensure that your prop is limited to specific values by treating␊
// it as an enum.␊
optionalEnum: PropTypes.oneOf(['News', 'Photos']),␊
// An object that could be one of many types␊
optionalUnion: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.instanceOf(Demo)]),␊
// An array of a certain type␊
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),␊
// An object with property values of a certain type␊
optionalObjectOf: PropTypes.objectOf(PropTypes.number),␊
// You can chain any of the above with `isRequired` to make sure a warning␊
// is shown if the prop isn't provided.␊
// An object taking on a particular shape␊
optionalObjectWithShape: PropTypes.shape({␊
optionalProperty: PropTypes.string,␊
requiredProperty: PropTypes.number.isRequired,␊
}),␊
optionalObjectWithShape2: PropTypes.shape({␊
optionalProperty: PropTypes.string,␊
requiredProperty: PropTypes.number.isRequired,␊
}).isRequired,␊
// An object with warnings on extra properties␊
optionalObjectWithStrictShape: PropTypes.exact({␊
optionalProperty: PropTypes.string,␊
requiredProperty: PropTypes.number.isRequired,␊
}),␊
requiredFunc: PropTypes.func.isRequired,␊
// A value of any data type␊
requiredAny: PropTypes.any.isRequired,␊
};␊
Demo.defaultProps = {␊
optionalNumber: 123,␊
};␊
export default Demo;`,
entryFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine-v0.8/packages/material-parser/test/fixtures/single-exported-component/es/index.js',
mainFilePath: 'es/index.js',
entryFilePath: '/Users/gengyang/code/frontend/low-code/ali-lowcode-engine-v0.8/packages/material-parser/test/fixtures/single-exported-component/src/index.js',
mainFilePath: 'src/index.js',
pkgName: 'single-exported-component',
pkgVersion: '1.0.0',
sourceType: 'module',
}

View File

@ -40,7 +40,7 @@
"lib/**/style/*",
"*.less"
],
"main": "lib/index.js",
"main": "components/index.tsx",
"module": "components/index.tsx",
"unpkg": "dist/antd.min.js",
"typings": "lib/index.d.ts",
@ -148,17 +148,54 @@
"@ant-design/tools": "^8.2.0",
"@qixian.cs/github-contributors-list": "^1.0.3",
"@stackblitz/sdk": "^1.3.0",
"@types/cheerio": "^0.22.21",
"@types/classnames": "^2.2.8",
"@types/concurrently": "^5.2.1",
"@types/enzyme": "^3.10.5",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/enzyme-to-json": "^1.5.3",
"@types/eslint": "^6.8.1",
"@types/fetch-jsonp": "^1.0.0",
"@types/fs-extra": "^9.0.1",
"@types/glob": "^7.1.3",
"@types/gtag.js": "^0.0.3",
"@types/http-server": "^0.10.0",
"@types/inquirer": "^7.3.0",
"@types/jest": "^25.1.0",
"@types/jquery": "^3.5.1",
"@types/jsdom": "^16.2.3",
"@types/lodash": "^4.14.139",
"@types/logrocket-react": "^3.0.0",
"@types/lz-string": "^1.3.34",
"@types/mockdate": "^2.0.0",
"@types/node-fetch": "^2.5.7",
"@types/prettier": "^2.0.2",
"@types/prop-types": "^15.7.1",
"@types/raf": "^3.4.0",
"@types/rc-select": "~5.9.34",
"@types/rc-slider": "~8.6.6",
"@types/rc-steps": "~3.5.0",
"@types/rc-switch": "~1.9.0",
"@types/rc-tooltip": "~3.7.3",
"@types/rc-tree": "~1.11.3",
"@types/react": "^16.9.21",
"@types/react-color": "^3.0.1",
"@types/react-copy-to-clipboard": "^4.3.0",
"@types/react-dom": "^16.9.5",
"@types/react-github-button": "^0.1.0",
"@types/react-highlight-words": "^0.16.1",
"@types/react-infinite-scroller": "^1.2.1",
"@types/react-resizable": "^1.7.2",
"@types/react-router-dom": "^5.1.5",
"@types/react-sticky": "^6.0.3",
"@types/react-test-renderer": "^16.9.3",
"@types/react-virtualized": "~9.21.10",
"@types/react-window": "^1.8.2",
"@types/rimraf": "^3.0.0",
"@types/stylelint": "^9.10.1",
"@types/warning": "^3.0.0",
"@types/webpack-bundle-analyzer": "^3.8.0",
"@types/yaml-front-matter": "^4.1.0",
"@typescript-eslint/eslint-plugin": "^2.19.0",
"@typescript-eslint/parser": "^2.19.0",
"antd-pro-merge-less": "^3.0.3",

View File

@ -0,0 +1,299 @@
import _extends from 'babel-runtime/helpers/extends';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
var _class, _temp;
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { findDOMNode } from 'react-dom';
import { polyfill } from 'react-lifecycles-compat';
import { obj, events, func } from '../util';
import ConfigProvider from '../config-provider';
import { getScroll, getRect, getNodeHeight } from './util';
/** Affix */
var Affix = (_temp = _class = function (_React$Component) {
_inherits(Affix, _React$Component);
Affix._getAffixMode = function _getAffixMode(nextProps) {
var affixMode = {
top: false,
bottom: false,
offset: 0
};
if (!nextProps) {
return affixMode;
}
var offsetTop = nextProps.offsetTop,
offsetBottom = nextProps.offsetBottom;
if (typeof offsetTop !== 'number' && typeof offsetBottom !== 'number') {
// set default
affixMode.top = true;
} else if (typeof offsetTop === 'number') {
affixMode.top = true;
affixMode.bottom = false;
affixMode.offset = offsetTop;
} else if (typeof offsetBottom === 'number') {
affixMode.bottom = true;
affixMode.top = false;
affixMode.offset = offsetBottom;
}
return affixMode;
};
function Affix(props, context) {
_classCallCheck(this, Affix);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
_this.updatePosition = function () {
_this._updateNodePosition();
};
_this._updateNodePosition = function () {
var affixMode = _this.state.affixMode;
var _this$props = _this.props,
container = _this$props.container,
useAbsolute = _this$props.useAbsolute;
var affixContainer = container();
if (!affixContainer || !_this.affixNode) {
return false;
}
var containerScrollTop = getScroll(affixContainer, true); // 容器在垂直位置上的滚动 offset
var affixOffset = _this._getOffset(_this.affixNode, affixContainer); // 目标节点当前相对于容器的 offset
var containerHeight = getNodeHeight(affixContainer); // 容器的高度
var affixHeight = _this.affixNode.offsetHeight;
var containerRect = getRect(affixContainer);
var affixChildHeight = _this.affixChildNode.offsetHeight;
var affixStyle = {
width: affixOffset.width
};
var containerStyle = {
width: affixOffset.width,
height: affixChildHeight
};
if (affixMode.top && containerScrollTop > affixOffset.top - affixMode.offset) {
// affix top
if (useAbsolute) {
affixStyle.position = 'absolute';
affixStyle.top = containerScrollTop - (affixOffset.top - affixMode.offset);
containerStyle.position = 'relative';
} else {
affixStyle.position = 'fixed';
affixStyle.top = affixMode.offset + containerRect.top;
}
_this._setAffixStyle(affixStyle, true);
_this._setContainerStyle(containerStyle);
} else if (affixMode.bottom && containerScrollTop < affixOffset.top + affixHeight + affixMode.offset - containerHeight) {
// affix bottom
affixStyle.height = affixHeight;
if (useAbsolute) {
affixStyle.position = 'absolute';
affixStyle.top = containerScrollTop - (affixOffset.top + affixHeight + affixMode.offset - containerHeight);
containerStyle.position = 'relative';
} else {
affixStyle.position = 'fixed';
affixStyle.bottom = affixMode.offset;
}
_this._setAffixStyle(affixStyle, true);
_this._setContainerStyle(containerStyle);
} else {
_this._setAffixStyle(null);
_this._setContainerStyle(null);
}
};
_this._affixNodeRefHandler = function (ref) {
_this.affixNode = findDOMNode(ref);
};
_this._affixChildNodeRefHandler = function (ref) {
_this.affixChildNode = findDOMNode(ref);
};
_this.state = {
style: null,
containerStyle: null,
affixMode: Affix._getAffixMode(props)
};
return _this;
}
Affix.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
if ('offsetTop' in nextProps || 'offsetBottom' in nextProps) {
return {
affixMode: Affix._getAffixMode(nextProps)
};
}
return null;
};
Affix.prototype.componentDidMount = function componentDidMount() {
var _this2 = this;
var container = this.props.container;
this._updateNodePosition();
// wait for parent rendered
this.timeout = setTimeout(function () {
_this2._setEventHandlerForContainer(container);
});
};
Affix.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState, snapshot) {
setTimeout(this._updateNodePosition);
};
Affix.prototype.componentWillUnmount = function componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
var container = this.props.container;
this._removeEventHandlerForContainer(container);
};
Affix.prototype._setEventHandlerForContainer = function _setEventHandlerForContainer(getContainer) {
var container = getContainer();
if (!container) {
return;
}
events.on(container, 'scroll', this._updateNodePosition, false);
events.on(container, 'resize', this._updateNodePosition, false);
};
Affix.prototype._removeEventHandlerForContainer = function _removeEventHandlerForContainer(getContainer) {
var container = getContainer();
if (container) {
events.off(container, 'scroll', this._updateNodePosition);
events.off(container, 'resize', this._updateNodePosition);
}
};
Affix.prototype._setAffixStyle = function _setAffixStyle(affixStyle) {
var affixed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (obj.shallowEqual(affixStyle, this.state.style)) {
return;
}
this.setState({
style: affixStyle
});
var onAffix = this.props.onAffix;
if (affixed) {
setTimeout(function () {
return onAffix(true);
});
} else if (!affixStyle) {
setTimeout(function () {
return onAffix(false);
});
}
};
Affix.prototype._setContainerStyle = function _setContainerStyle(containerStyle) {
if (obj.shallowEqual(containerStyle, this.state.containerStyle)) {
return;
}
this.setState({ containerStyle: containerStyle });
};
Affix.prototype._getOffset = function _getOffset(affixNode, affixContainer) {
var affixRect = affixNode.getBoundingClientRect(); // affix 元素 相对浏览器窗口的位置
var containerRect = getRect(affixContainer); // affix 容器 相对浏览器窗口的位置
var containerScrollTop = getScroll(affixContainer, true);
var containerScrollLeft = getScroll(affixContainer, false);
return {
top: affixRect.top - containerRect.top + containerScrollTop,
left: affixRect.left - containerRect.left + containerScrollLeft,
width: affixRect.width,
height: affixRect.height
};
};
Affix.prototype.render = function render() {
var _classnames;
var affixMode = this.state.affixMode;
var _props = this.props,
prefix = _props.prefix,
className = _props.className,
style = _props.style,
children = _props.children;
var state = this.state;
var classNames = classnames((_classnames = {}, _classnames[prefix + 'affix'] = state.style, _classnames[prefix + 'affix-top'] = !state.style && affixMode.top, _classnames[prefix + 'affix-bottom'] = !state.style && affixMode.bottom, _classnames[className] = className, _classnames));
var combinedStyle = _extends({}, state.containerStyle, style);
return React.createElement(
'div',
{ ref: this._affixNodeRefHandler, style: combinedStyle },
React.createElement(
'div',
{
ref: this._affixChildNodeRefHandler,
className: classNames,
style: state.style
},
children
)
);
};
return Affix;
}(React.Component), _class.propTypes = {
prefix: PropTypes.string,
/**
* 设置 Affix 需要监听滚动事件的容器元素
* @return {ReactElement} 目标容器元素的实例
*/
container: PropTypes.func,
/**
* 距离窗口顶部达到指定偏移量后触发
*/
offsetTop: PropTypes.number,
/**
* 距离窗口底部达到制定偏移量后触发
*/
offsetBottom: PropTypes.number,
/**
* 当元素的样式发生固钉样式变化时触发的回调函数
* @param {Boolean} affixed 元素是否被固钉
*/
onAffix: PropTypes.func,
/**
* 是否启用绝对布局实现 affix
* @param {Boolean} 是否启用绝对布局
*/
useAbsolute: PropTypes.bool,
className: PropTypes.string,
style: PropTypes.object,
children: PropTypes.any
}, _class.defaultProps = {
prefix: 'next-',
container: function container() {
return window;
},
onAffix: func.noop
}, _temp);
Affix.displayName = 'Affix';
export default ConfigProvider.config(polyfill(Affix));

View File

@ -0,0 +1 @@
@import "./main.scss";

View File

@ -0,0 +1 @@
/* stylelint-disable-next-line */

View File

@ -0,0 +1 @@
import './main.scss';

View File

@ -0,0 +1,22 @@
export function getScroll(node, isVertical) {
if (typeof window === 'undefined') {
return 0;
}
var windowProp = isVertical ? 'pageYOffset' : 'pageXOffset';
var elementProp = isVertical ? 'scrollTop' : 'scrollLeft';
return node === window ? node[windowProp] : node[elementProp];
}
export function getRect(node) {
return node !== window ? node.getBoundingClientRect() : { top: 0, left: 0, bottom: 0 };
}
export function getNodeHeight(node) {
if (!node) {
return 0;
}
if (node === window) {
return window.innerHeight;
}
return node.clientHeight;
}

View File

@ -0,0 +1,192 @@
import _extends from 'babel-runtime/helpers/extends';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import _typeof from 'babel-runtime/helpers/typeof';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
var _class, _temp;
import React, { Component, Children } from 'react';
import PropTypes from 'prop-types';
import { TransitionGroup } from 'react-transition-group';
import AnimateChild from './child';
var noop = function noop() {};
var FirstChild = function FirstChild(props) {
var childrenArray = React.Children.toArray(props.children);
return childrenArray[0] || null;
};
/**
* Animate
*/
var Animate = (_temp = _class = function (_Component) {
_inherits(Animate, _Component);
function Animate() {
_classCallCheck(this, Animate);
return _possibleConstructorReturn(this, _Component.apply(this, arguments));
}
Animate.prototype.normalizeNames = function normalizeNames(names) {
if (typeof names === 'string') {
return {
appear: names + '-appear',
appearActive: names + '-appear-active',
enter: names + '-enter',
enterActive: names + '-enter-active',
leave: names + '-leave',
leaveActive: names + '-leave-active'
};
}
if ((typeof names === 'undefined' ? 'undefined' : _typeof(names)) === 'object') {
return {
appear: names.appear,
appearActive: names.appear + '-active',
enter: '' + names.enter,
enterActive: names.enter + '-active',
leave: '' + names.leave,
leaveActive: names.leave + '-active'
};
}
};
Animate.prototype.render = function render() {
var _this2 = this;
/* eslint-disable no-unused-vars */
var _props = this.props,
animation = _props.animation,
children = _props.children,
animationAppear = _props.animationAppear,
singleMode = _props.singleMode,
component = _props.component,
beforeAppear = _props.beforeAppear,
onAppear = _props.onAppear,
afterAppear = _props.afterAppear,
beforeEnter = _props.beforeEnter,
onEnter = _props.onEnter,
afterEnter = _props.afterEnter,
beforeLeave = _props.beforeLeave,
onLeave = _props.onLeave,
afterLeave = _props.afterLeave,
others = _objectWithoutProperties(_props, ['animation', 'children', 'animationAppear', 'singleMode', 'component', 'beforeAppear', 'onAppear', 'afterAppear', 'beforeEnter', 'onEnter', 'afterEnter', 'beforeLeave', 'onLeave', 'afterLeave']);
/* eslint-enable no-unused-vars */
var animateChildren = Children.map(children, function (child) {
return React.createElement(
AnimateChild,
{
key: child.key,
names: _this2.normalizeNames(animation),
onAppear: beforeAppear,
onAppearing: onAppear,
onAppeared: afterAppear,
onEnter: beforeEnter,
onEntering: onEnter,
onEntered: afterEnter,
onExit: beforeLeave,
onExiting: onLeave,
onExited: afterLeave
},
child
);
});
return React.createElement(
TransitionGroup,
_extends({
appear: animationAppear,
component: singleMode ? FirstChild : component
}, others),
animateChildren
);
};
return Animate;
}(Component), _class.propTypes = {
/**
* 动画 className
*/
animation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
/**
* 子元素第一次挂载时是否执行动画
*/
animationAppear: PropTypes.bool,
/**
* 包裹子元素的标签
*/
component: PropTypes.any,
/**
* 是否只有单个子元素如果有多个子元素请设置为 false
*/
singleMode: PropTypes.bool,
/**
* 子元素
*/
children: PropTypes.oneOfType([PropTypes.element, PropTypes.arrayOf(PropTypes.element)]),
/**
* 执行第一次挂载动画前触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
beforeAppear: PropTypes.func,
/**
* 执行第一次挂载动画添加 xxx-appear-active 类名后触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
onAppear: PropTypes.func,
/**
* 执行完第一次挂载动画后触发的函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
afterAppear: PropTypes.func,
/**
* 执行进场动画前触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
beforeEnter: PropTypes.func,
/**
* 执行进场动画添加 xxx-enter-active 类名后触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
onEnter: PropTypes.func,
/**
* 执行完进场动画后触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
afterEnter: PropTypes.func,
/**
* 执行离场动画前触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
beforeLeave: PropTypes.func,
/**
* 执行离场动画添加 xxx-leave-active 类名后触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
onLeave: PropTypes.func,
/**
* 执行完离场动画后触发的回调函数
* @param {HTMLElement} node 执行动画的 dom 元素
*/
afterLeave: PropTypes.func
}, _class.defaultProps = {
animationAppear: true,
component: 'div',
singleMode: true,
beforeAppear: noop,
onAppear: noop,
afterAppear: noop,
beforeEnter: noop,
onEnter: noop,
afterEnter: noop,
beforeLeave: noop,
onLeave: noop,
afterLeave: noop
}, _temp);
Animate.displayName = 'Animate';
export default Animate;

View File

@ -0,0 +1,259 @@
import _extends from 'babel-runtime/helpers/extends';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
var _class, _temp;
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Transition } from 'react-transition-group';
import { func, support, events, dom, guid } from '../util';
var noop = function noop() {};
var on = events.on,
off = events.off;
var addClass = dom.addClass,
removeClass = dom.removeClass;
var prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', ''];
function getStyleProperty(node, name) {
var style = window.getComputedStyle(node);
var ret = '';
for (var i = 0; i < prefixes.length; i++) {
ret = style.getPropertyValue(prefixes[i] + name);
if (ret) {
break;
}
}
return ret;
}
var AnimateChild = (_temp = _class = function (_Component) {
_inherits(AnimateChild, _Component);
function AnimateChild(props) {
_classCallCheck(this, AnimateChild);
var _this2 = _possibleConstructorReturn(this, _Component.call(this, props));
func.bindCtx(_this2, ['handleEnter', 'handleEntering', 'handleEntered', 'handleExit', 'handleExiting', 'handleExited', 'addEndListener']);
_this2.endListeners = {
transitionend: [],
animationend: []
};
_this2.timeoutMap = {};
return _this2;
}
AnimateChild.prototype.componentWillUnmount = function componentWillUnmount() {
var _this3 = this;
Object.keys(this.endListeners).forEach(function (eventName) {
_this3.endListeners[eventName].forEach(function (listener) {
off(_this3.node, eventName, listener);
});
});
this.endListeners = {
transitionend: [],
animationend: []
};
};
AnimateChild.prototype.generateEndListener = function generateEndListener(node, done, eventName, id) {
var _this = this;
return function endListener(e) {
if (e && e.target === node) {
if (_this.timeoutMap[id]) {
clearTimeout(_this.timeoutMap[id]);
delete _this.timeoutMap[id];
}
done();
off(node, eventName, endListener);
var listeners = _this.endListeners[eventName];
var index = listeners.indexOf(endListener);
index > -1 && listeners.splice(index, 1);
}
};
};
AnimateChild.prototype.addEndListener = function addEndListener(node, done) {
var _this4 = this;
if (support.transition || support.animation) {
var id = guid();
this.node = node;
if (support.transition) {
var transitionEndListener = this.generateEndListener(node, done, 'transitionend', id);
on(node, 'transitionend', transitionEndListener);
this.endListeners.transitionend.push(transitionEndListener);
}
if (support.animation) {
var animationEndListener = this.generateEndListener(node, done, 'animationend', id);
on(node, 'animationend', animationEndListener);
this.endListeners.animationend.push(animationEndListener);
}
setTimeout(function () {
var transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0;
var transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0;
var animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0;
var animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0;
var time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay);
if (time) {
_this4.timeoutMap[id] = setTimeout(function () {
done();
}, time * 1000 + 200);
}
}, 15);
} else {
done();
}
};
AnimateChild.prototype.removeEndtListener = function removeEndtListener() {
this.transitionOff && this.transitionOff();
this.animationOff && this.animationOff();
};
AnimateChild.prototype.removeClassNames = function removeClassNames(node, names) {
Object.keys(names).forEach(function (key) {
removeClass(node, names[key]);
});
};
AnimateChild.prototype.handleEnter = function handleEnter(node, isAppearing) {
var names = this.props.names;
if (names) {
this.removeClassNames(node, names);
var className = isAppearing ? 'appear' : 'enter';
addClass(node, names[className]);
}
var hook = isAppearing ? this.props.onAppear : this.props.onEnter;
hook(node);
};
AnimateChild.prototype.handleEntering = function handleEntering(node, isAppearing) {
var _this5 = this;
setTimeout(function () {
var names = _this5.props.names;
if (names) {
var className = isAppearing ? 'appearActive' : 'enterActive';
addClass(node, names[className]);
}
var hook = isAppearing ? _this5.props.onAppearing : _this5.props.onEntering;
hook(node);
}, 10);
};
AnimateChild.prototype.handleEntered = function handleEntered(node, isAppearing) {
var names = this.props.names;
if (names) {
var classNames = isAppearing ? [names.appear, names.appearActive] : [names.enter, names.enterActive];
classNames.forEach(function (className) {
removeClass(node, className);
});
}
var hook = isAppearing ? this.props.onAppeared : this.props.onEntered;
hook(node);
};
AnimateChild.prototype.handleExit = function handleExit(node) {
var names = this.props.names;
if (names) {
this.removeClassNames(node, names);
addClass(node, names.leave);
}
this.props.onExit(node);
};
AnimateChild.prototype.handleExiting = function handleExiting(node) {
var _this6 = this;
setTimeout(function () {
var names = _this6.props.names;
if (names) {
addClass(node, names.leaveActive);
}
_this6.props.onExiting(node);
}, 10);
};
AnimateChild.prototype.handleExited = function handleExited(node) {
var names = this.props.names;
if (names) {
[names.leave, names.leaveActive].forEach(function (className) {
removeClass(node, className);
});
}
this.props.onExited(node);
};
AnimateChild.prototype.render = function render() {
/* eslint-disable no-unused-vars */
var _props = this.props,
names = _props.names,
onAppear = _props.onAppear,
onAppeared = _props.onAppeared,
onAppearing = _props.onAppearing,
onEnter = _props.onEnter,
onEntering = _props.onEntering,
onEntered = _props.onEntered,
onExit = _props.onExit,
onExiting = _props.onExiting,
onExited = _props.onExited,
others = _objectWithoutProperties(_props, ['names', 'onAppear', 'onAppeared', 'onAppearing', 'onEnter', 'onEntering', 'onEntered', 'onExit', 'onExiting', 'onExited']);
/* eslint-enable no-unused-vars */
return React.createElement(Transition, _extends({}, others, {
onEnter: this.handleEnter,
onEntering: this.handleEntering,
onEntered: this.handleEntered,
onExit: this.handleExit,
onExiting: this.handleExiting,
onExited: this.handleExited,
addEndListener: this.addEndListener
}));
};
return AnimateChild;
}(Component), _class.propTypes = {
names: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
onAppear: PropTypes.func,
onAppearing: PropTypes.func,
onAppeared: PropTypes.func,
onEnter: PropTypes.func,
onEntering: PropTypes.func,
onEntered: PropTypes.func,
onExit: PropTypes.func,
onExiting: PropTypes.func,
onExited: PropTypes.func
}, _class.defaultProps = {
onAppear: noop,
onAppearing: noop,
onAppeared: noop,
onEnter: noop,
onEntering: noop,
onEntered: noop,
onExit: noop,
onExiting: noop,
onExited: noop
}, _temp);
AnimateChild.displayName = 'AnimateChild';
export { AnimateChild as default };

View File

@ -0,0 +1,152 @@
import _extends from 'babel-runtime/helpers/extends';
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
var _class, _temp;
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { func, dom } from '../util';
import Animate from './animate';
var noop = function noop() {};
var getStyle = dom.getStyle;
var Expand = (_temp = _class = function (_Component) {
_inherits(Expand, _Component);
function Expand(props) {
_classCallCheck(this, Expand);
var _this = _possibleConstructorReturn(this, _Component.call(this, props));
func.bindCtx(_this, ['beforeEnter', 'onEnter', 'afterEnter', 'beforeLeave', 'onLeave', 'afterLeave']);
return _this;
}
Expand.prototype.beforeEnter = function beforeEnter(node) {
if (this.leaving) {
this.afterLeave(node);
}
this.cacheCurrentStyle(node);
this.cacheComputedStyle(node);
this.setCurrentStyleToZero(node);
this.props.beforeEnter(node);
};
Expand.prototype.onEnter = function onEnter(node) {
this.setCurrentStyleToComputedStyle(node);
this.props.onEnter(node);
};
Expand.prototype.afterEnter = function afterEnter(node) {
this.restoreCurrentStyle(node);
this.props.afterEnter(node);
};
Expand.prototype.beforeLeave = function beforeLeave(node) {
this.leaving = true;
this.cacheCurrentStyle(node);
this.cacheComputedStyle(node);
this.setCurrentStyleToComputedStyle(node);
this.props.beforeLeave(node);
};
Expand.prototype.onLeave = function onLeave(node) {
this.setCurrentStyleToZero(node);
this.props.onLeave(node);
};
Expand.prototype.afterLeave = function afterLeave(node) {
this.leaving = false;
this.restoreCurrentStyle(node);
this.props.afterLeave(node);
};
Expand.prototype.cacheCurrentStyle = function cacheCurrentStyle(node) {
this.styleBorderTopWidth = node.style.borderTopWidth;
this.stylePaddingTop = node.style.paddingTop;
this.styleHeight = node.style.height;
this.stylePaddingBottom = node.style.paddingBottom;
this.styleBorderBottomWidth = node.style.borderBottomWidth;
};
Expand.prototype.cacheComputedStyle = function cacheComputedStyle(node) {
this.borderTopWidth = getStyle(node, 'borderTopWidth');
this.paddingTop = getStyle(node, 'paddingTop');
this.height = node.offsetHeight;
this.paddingBottom = getStyle(node, 'paddingBottom');
this.borderBottomWidth = getStyle(node, 'borderBottomWidth');
};
Expand.prototype.setCurrentStyleToZero = function setCurrentStyleToZero(node) {
node.style.borderTopWidth = '0px';
node.style.paddingTop = '0px';
node.style.height = '0px';
node.style.paddingBottom = '0px';
node.style.borderBottomWidth = '0px';
};
Expand.prototype.setCurrentStyleToComputedStyle = function setCurrentStyleToComputedStyle(node) {
node.style.borderTopWidth = this.borderTopWidth + 'px';
node.style.paddingTop = this.paddingTop + 'px';
node.style.height = this.height + 'px';
node.style.paddingBottom = this.paddingBottom + 'px';
node.style.borderBottomWidth = this.borderBottomWidth + 'px';
};
Expand.prototype.restoreCurrentStyle = function restoreCurrentStyle(node) {
node.style.borderTopWidth = this.styleBorderTopWidth;
node.style.paddingTop = this.stylePaddingTop;
node.style.height = this.styleHeight;
node.style.paddingBottom = this.stylePaddingBottom;
node.style.borderBottomWidth = this.styleBorderBottomWidth;
};
Expand.prototype.render = function render() {
var _props = this.props,
animation = _props.animation,
others = _objectWithoutProperties(_props, ['animation']);
var newAnimation = animation || 'expand';
return React.createElement(Animate, _extends({}, others, {
animation: newAnimation,
beforeEnter: this.beforeEnter,
onEnter: this.onEnter,
afterEnter: this.afterEnter,
beforeLeave: this.beforeLeave,
onLeave: this.onLeave,
afterLeave: this.afterLeave
}));
};
return Expand;
}(Component), _class.propTypes = {
animation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
beforeEnter: PropTypes.func,
onEnter: PropTypes.func,
afterEnter: PropTypes.func,
beforeLeave: PropTypes.func,
onLeave: PropTypes.func,
afterLeave: PropTypes.func
}, _class.defaultProps = {
beforeEnter: noop,
onEnter: noop,
afterEnter: noop,
beforeLeave: noop,
onLeave: noop,
afterLeave: noop
}, _temp);
Expand.displayName = 'Expand';
export { Expand as default };

View File

@ -0,0 +1,6 @@
import Animate from './animate';
import Expand from './expand';
Animate.Expand = Expand;
export default Animate;

View File

@ -0,0 +1 @@
@import "./main.scss";

View File

@ -0,0 +1,145 @@
@import "scss/mixin";
@import "scss/variable";
@import "scss/_fading-entrances/_fadeIn.scss";
@import "scss/_fading-entrances/_fadeInDown.scss";
@import "scss/_fading-entrances/_fadeInLeft.scss";
@import "scss/_fading-entrances/_fadeInRight.scss";
@import "scss/_fading-entrances/_fadeInUp.scss";
@import "scss/_fading-exits/_fadeOut.scss";
@import "scss/_fading-exits/_fadeOutDown.scss";
@import "scss/_fading-exits/_fadeOutLeft.scss";
@import "scss/_fading-exits/_fadeOutRight.scss";
@import "scss/_fading-exits/_fadeOutUp.scss";
@import "scss/_sliding-exits/sliding-exits.scss";
@import "scss/_sliding-entrances/sliding-entrances.scss";
@import "scss/_zooming-entrances/_zoomIn.scss";
@import "scss/_zooming-exits/_zoomOut.scss";
@import "scss/_expand-entrances/_expandInDown.scss";
@import "scss/_expand-entrances/_expandInUp.scss";
@import "scss/_expand-entrances/_withFade.scss";
@import "scss/_expand-exits/_expandOutUp.scss";
@import "scss/_expand-exits/_expandOutDown.scss";
@import "scss/_expand-exits/_withFade.scss";
@import "scss/_attention-seekers/_pulse.scss";
.fadeIn {
@include fadeIn();
}
.fadeInDown {
@include fadeInDown();
}
.fadeInLeft {
@include fadeInLeft();
}
.fadeInRight {
@include fadeInRight();
}
.fadeInUp {
@include fadeInUp();
}
.fadeOut {
@include fadeOut();
}
.fadeOutDown {
@include fadeOutDown();
}
.fadeOutLeft {
@include fadeOutLeft();
}
.fadeOutRight {
@include fadeOutRight();
}
.fadeOutUp {
@include fadeOutUp();
}
.slideInUp {
@include slideInUp();
}
.slideInDown {
@include slideInDown();
}
.slideInLeft {
@include slideInLeft();
}
.slideInRight {
@include slideInRight();
}
.slideOutUp {
@include slideOutUp();
}
.slideOutRight {
@include slideOutRight();
}
.slideOutLeft {
@include slideOutLeft();
}
.slideOutDown {
@include slideOutDown();
}
.zoomIn {
@include zoomIn();
}
.zoomOut {
@include zoomOut();
}
.expandInDown {
@include expandInDown();
}
.expandOutUp {
@include expandOutUp();
}
.expandInUp {
@include expandInUp();
}
.expandOutDown {
@include expandOutDown();
}
.pulse {
@include pulse();
}
.expand-enter {
overflow: hidden;
}
.expand-enter-active {
transition: all .3s ease-out;
& > * {
@include expandInWithFade();
}
}
.expand-leave {
overflow: hidden;
}
.expand-leave-active {
transition: all .2s ease-out;
& > * {
@include expandOutWithFade();
}
}

View File

@ -0,0 +1,14 @@
@include keyframes(buttonClick) {
50% {
@include transform(scale3d(.95, .95, .95));
}
}
@mixin buttonClick($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(buttonClick);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,14 @@
@include keyframes(press) {
50% {
@include transform(scale3d(.7, .7, .7));
}
}
@mixin press($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(press);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,21 @@
@include keyframes(pulse) {
from {
@include transform(scale(1));
}
20% {
@include transform(scale(1.2));
}
to {
@include transform(scale(1));
}
}
@mixin pulse($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(pulse);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,32 @@
@include keyframes(shake) {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
@mixin shake($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(shake);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,14 @@
@include keyframes(unpress) {
50% {
@include transform(scale3d(.7, .7, .7));
}
}
@mixin unpress($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(unpress);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,7 @@
// INDEX OF FADING EXITS
@import "_pulse";
@import "_shake";
@import "_press";
@import "_unpress";
@import "_buttonClick";

View File

@ -0,0 +1,48 @@
@include keyframes(bounceIn) {
from,
20%,
40%,
60%,
80%,
to {
-webkit-animation-timing-function: cubic-bezier(.215, .610, .355, 1.000);
animation-timing-function: cubic-bezier(.215, .610, .355, 1.000);
}
0% {
opacity: 0;
-webkit-transform: scale3d(.3, .3, .3);
transform: scale3d(.3, .3, .3);
}
20% {
-webkit-transform: scale3d(1.1, 1.1, 1.1);
transform: scale3d(1.1, 1.1, 1.1);
}
40% {
-webkit-transform: scale3d(.9, .9, .9);
transform: scale3d(.9, .9, .9);
}
60% {
opacity: 1;
-webkit-transform: scale3d(1.03, 1.03, 1.03);
transform: scale3d(1.03, 1.03, 1.03);
}
80% {
-webkit-transform: scale3d(.97, .97, .97);
transform: scale3d(.97, .97, .97);
}
to {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@mixin bounceIn($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(bounceIn);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,3 @@
// INDEX OF FADING ENTRANCES
@import "_bounceIn";

View File

@ -0,0 +1,27 @@
@include keyframes(bounceOut) {
20% {
-webkit-transform: scale3d(.9, .9, .9);
transform: scale3d(.9, .9, .9);
}
50%,
55% {
opacity: 1;
-webkit-transform: scale3d(1.1, 1.1, 1.1);
transform: scale3d(1.1, 1.1, 1.1);
}
to {
opacity: 0;
-webkit-transform: scale3d(.3, .3, .3);
transform: scale3d(.3, .3, .3);
}
}
@mixin bounceOut($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(bounceOut);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,3 @@
// INDEX OF FADING EXITS
@import "_bounceOut";

View File

@ -0,0 +1,22 @@
@include keyframes(expandInDown) {
0% {
opacity: 0;
@include transform(scaleY(.6));
@include transform-origin(left top 0);
}
100% {
opacity: 1;
@include transform(scaleY(1));
@include transform-origin(left top 0);
}
}
@mixin expandInDown($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(expandInDown);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,22 @@
@include keyframes(expandInUp) {
0% {
opacity: 0;
@include transform(scaleY(.6));
@include transform-origin(left bottom 0);
}
100% {
opacity: 1;
@include transform(scaleY(1));
@include transform-origin(left bottom 0);
}
}
@mixin expandInUp($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(expandInUp);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,24 @@
@include keyframes(expandInWithFade) {
0% {
opacity: 0;
}
40% {
opacity: .1;
}
50% {
opacity: .9;
}
100% {
opacity: 1;
}
}
@mixin expandInWithFade($count: $countDefault, $duration: .2s, $delay: $delayDefault, $function: $functionDefault, $fill: 'forwards', $visibility: $visibilityDefault) {
@include animation-name(expandInWithFade);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,22 @@
@include keyframes(expandOutDown) {
0% {
opacity: 1;
@include transform(scaleY(1));
@include transform-origin(left bottom 0);
}
100% {
opacity: 0;
@include transform(scaleY(.6));
@include transform-origin(left bottom 0);
}
}
@mixin expandOutDown($count: $countDefault, $duration: .15s, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(expandOutDown);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,22 @@
@include keyframes(expandOutUp) {
0% {
opacity: 1;
@include transform(scaleY(1));
@include transform-origin(left top 0);
}
100% {
opacity: 0;
@include transform(scaleY(.6));
@include transform-origin(left top 0);
}
}
@mixin expandOutUp($count: $countDefault, $duration: .15s, $delay: $delayDefault, $function: $functionDefault, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(expandOutUp);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,21 @@
@include keyframes(expandOutWithFade) {
0% {
opacity: 1;
}
70% {
opacity: 0;
}
100% {
opacity: 0;
}
}
@mixin expandOutWithFade($count: $countDefault, $duration: .2s, $delay: $delayDefault, $function: $functionDefault, $fill: 'forwards', $visibility: $visibilityDefault) {
@include animation-name(expandOutWithFade);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,18 @@
@include keyframes(fadeIn) {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@mixin fadeIn($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeIn);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInDown) {
0% {
opacity: 0;
@include transform(translateY(-100px));
}
100% {
opacity: 1;
@include transform(translateY(0));
}
}
@mixin fadeInDown($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInDown);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInDownBig) {
0% {
opacity: 0;
@include transform(translateY(-2000px));
}
100% {
opacity: 1;
@include transform(translateY(0));
}
}
@mixin fadeInDownBig($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInDownBig);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInLeft) {
0% {
opacity: 0;
@include transform(translateX(-20px));
}
100% {
opacity: 1;
@include transform(translateX(0));
}
}
@mixin fadeInLeft($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInLeft);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInLeftBig) {
0% {
opacity: 0;
@include transform(translateX(-2000px));
}
100% {
opacity: 1;
@include transform(translateX(0));
}
}
@mixin fadeInLeftBig($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInLeftBig);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInRight) {
0% {
opacity: 0;
@include transform(translateX(20px));
}
100% {
opacity: 1;
@include transform(translateX(0));
}
}
@mixin fadeInRight($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInRight);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInRightBig) {
0% {
opacity: 0;
@include transform(translateX(2000px));
}
100% {
opacity: 1;
@include transform(translateX(0));
}
}
@mixin fadeInRightBig($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInRightBig);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,19 @@
@include keyframes(fadeInUp) {
0% {
opacity: 0;
@include transform(translateY(20px));}
100% {
opacity: 1;
@include transform(translateY(0));
}
}
@mixin fadeInUp($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInUp);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeInUpBig) {
0% {
opacity: 0;
@include transform(translateY(2000px));
}
100% {
opacity: 1;
@include transform(translateY(0));
}
}
@mixin fadeInUpBig($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-out-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeInUpBig);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,11 @@
// INDEX OF FADING ENTRANCES
@import "_fadeIn";
@import "_fadeInDown";
@import "_fadeInDownBig";
@import "_fadeInLeft";
@import "_fadeInLeftBig";
@import "_fadeInRight";
@import "_fadeInRightBig";
@import "_fadeInUp";
@import "_fadeInUpBig";

View File

@ -0,0 +1,18 @@
@include keyframes(fadeOut) {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@mixin fadeOut($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeOut);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeOutDown) {
0% {
opacity: 1;
@include transform(translateY(0));
}
100% {
opacity: 0;
@include transform(translateY(20px));
}
}
@mixin fadeOutDown($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeOutDown);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeOutDownBig) {
0% {
opacity: 1;
@include transform(translateY(0));
}
100% {
opacity: 0;
@include transform(translateY(2000px));
}
}
@mixin fadeOutDownBig($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeOutDownBig);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeOutLeft) {
0% {
opacity: 1;
@include transform(translateX(0));
}
100% {
opacity: 0;
@include transform(translateX(-20px));
}
}
@mixin fadeOutLeft($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeOutLeft);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeOutLeftBig) {
0% {
opacity: 1;
@include transform(translateX(0));
}
100% {
opacity: 0;
@include transform(translateX(-2000px));
}
}
@mixin fadeOutLeftBig($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeOutLeftBig);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

View File

@ -0,0 +1,20 @@
@include keyframes(fadeOutRight) {
0% {
opacity: 1;
@include transform(translateX(0));
}
100% {
opacity: 0;
@include transform(translateX(20px));
}
}
@mixin fadeOutRight($count: $countDefault, $duration: $durationDefault, $delay: $delayDefault, $function: $ease-in-quint, $fill: $fillDefault, $visibility: $visibilityDefault) {
@include animation-name(fadeOutRight);
@include count($count);
@include duration($duration);
@include delay($delay);
@include function($function);
@include fill-mode($fill);
@include visibility($visibility);
}

Some files were not shown because too many files have changed in this diff Show More