Repository URL to install this package:
Version:
1.2.13 ▾
|
"use strict";
// @flow
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const hoist_non_react_statics_1 = __importDefault(require("hoist-non-react-statics"));
const prop_types_1 = __importDefault(require("prop-types"));
const react_1 = require("react");
const constants_1 = require("../constants");
const createWarnTooManyClasses_1 = __importDefault(require("../utils/createWarnTooManyClasses"));
const determineTheme_1 = __importDefault(require("../utils/determineTheme"));
const escape_1 = __importDefault(require("../utils/escape"));
const generateDisplayName_1 = __importDefault(require("../utils/generateDisplayName"));
const getComponentName_1 = __importDefault(require("../utils/getComponentName"));
const isStyledComponent_1 = __importDefault(require("../utils/isStyledComponent"));
const isTag_1 = __importDefault(require("../utils/isTag"));
const validAttr_1 = __importDefault(require("../utils/validAttr"));
const hasInInheritanceChain_1 = __importDefault(require("../utils/hasInInheritanceChain"));
const ServerStyleSheet_1 = __importDefault(require("./ServerStyleSheet"));
const StyleSheet_1 = __importDefault(require("./StyleSheet"));
const ThemeProvider_1 = require("./ThemeProvider");
// HACK for generating all static styles without needing to allocate
// an empty execution context every single time...
const STATIC_EXECUTION_CONTEXT = {};
const exporting = (ComponentStyle, constructWithOptions) => {
const identifiers = {};
/* We depend on components having unique IDs */
const generateId = (_displayName, parentComponentId) => {
const displayName = typeof _displayName !== 'string' ? 'sc' : escape_1.default(_displayName);
/**
* This ensures uniqueness if two components happen to share
* the same displayName.
*/
const nr = (identifiers[displayName] || 0) + 1;
identifiers[displayName] = nr;
const componentId = `${displayName}-${ComponentStyle.generateName(displayName + nr)}`;
return parentComponentId !== undefined
? `${parentComponentId}-${componentId}`
: componentId;
};
// $FlowFixMe
class BaseStyledComponent extends react_1.Component {
constructor() {
super(...arguments);
this.attrs = {};
this.state = {
theme: null,
generatedClassName: '',
};
this.unsubscribeId = -1;
}
unsubscribeFromContext() {
if (this.unsubscribeId !== -1) {
this.context[ThemeProvider_1.CHANNEL_NEXT].unsubscribe(this.unsubscribeId);
}
}
buildExecutionContext(theme, props) {
const { attrs } = this.constructor;
const context = Object.assign({}, props, { theme });
if (attrs === undefined) {
return context;
}
this.attrs = Object.keys(attrs).reduce((acc, key) => {
const attr = attrs[key];
// eslint-disable-next-line no-param-reassign
acc[key] =
typeof attr === 'function' && !hasInInheritanceChain_1.default(attr, react_1.Component)
? attr(context)
: attr;
return acc;
}, {});
return Object.assign({}, context, this.attrs);
}
generateAndInjectStyles(theme, props) {
const { attrs, componentStyle, warnTooManyClasses } = this.constructor;
const styleSheet = this.context[constants_1.CONTEXT_KEY] || StyleSheet_1.default.master;
// staticaly styled-components don't need to build an execution context object,
// and shouldn't be increasing the number of class names
if (componentStyle.isStatic && attrs === undefined) {
return componentStyle.generateAndInjectStyles(STATIC_EXECUTION_CONTEXT, styleSheet);
}
else {
const executionContext = this.buildExecutionContext(theme, props);
const className = componentStyle.generateAndInjectStyles(executionContext, styleSheet);
if (process.env.NODE_ENV !== 'production' &&
warnTooManyClasses !== undefined) {
warnTooManyClasses(className);
}
return className;
}
}
componentWillMount() {
const { componentStyle } = this.constructor;
const styledContext = this.context[ThemeProvider_1.CHANNEL_NEXT];
// If this is a staticaly-styled component, we don't need to the theme
// to generate or build styles.
if (componentStyle.isStatic) {
const generatedClassName = this.generateAndInjectStyles(STATIC_EXECUTION_CONTEXT, this.props);
this.setState({ generatedClassName });
// If there is a theme in the context, subscribe to the event emitter. This
// is necessary due to pure components blocking context updates, this circumvents
// that by updating when an event is emitted
}
else if (styledContext !== undefined) {
const { subscribe } = styledContext;
this.unsubscribeId = subscribe(nextTheme => {
// This will be called once immediately
const theme = determineTheme_1.default(this.props, nextTheme, this.constructor.defaultProps);
const generatedClassName = this.generateAndInjectStyles(theme, this.props);
this.setState({ theme, generatedClassName });
});
}
else {
// eslint-disable-next-line react/prop-types
const theme = this.props.theme || {};
const generatedClassName = this.generateAndInjectStyles(theme, this.props);
this.setState({ theme, generatedClassName });
}
}
componentWillReceiveProps(nextProps) {
// If this is a statically-styled component, we don't need to listen to
// props changes to update styles
const { componentStyle } = this.constructor;
if (componentStyle.isStatic) {
return;
}
this.setState(prevState => {
const theme = determineTheme_1.default(nextProps, prevState.theme, this.constructor.defaultProps);
const generatedClassName = this.generateAndInjectStyles(theme, nextProps);
return { theme, generatedClassName };
});
}
componentWillUnmount() {
this.unsubscribeFromContext();
}
render() {
// eslint-disable-next-line react/prop-types
const { innerRef } = this.props;
const { generatedClassName } = this.state;
const { styledComponentId, target } = this.constructor;
const isTargetTag = isTag_1.default(target);
const className = [
// eslint-disable-next-line react/prop-types
this.props.className,
styledComponentId,
this.attrs.className,
generatedClassName,
]
.filter(Boolean)
.join(' ');
const baseProps = Object.assign({}, this.attrs, { className });
if (isStyledComponent_1.default(target)) {
baseProps.innerRef = innerRef;
}
else {
baseProps.ref = innerRef;
}
const propsForElement = Object.keys(this.props).reduce((acc, propName) => {
// Don't pass through non HTML tags through to HTML elements
// always omit innerRef
if (propName !== 'innerRef' &&
propName !== 'className' &&
(!isTargetTag || validAttr_1.default(propName))) {
// eslint-disable-next-line no-param-reassign
acc[propName] = this.props[propName];
}
return acc;
}, baseProps);
return react_1.createElement(target, propsForElement);
}
}
const createStyledComponent = (target, options, rules) => {
const { isClass = !isTag_1.default(target), displayName = generateDisplayName_1.default(target), componentId = generateId(options.displayName, options.parentComponentId), ParentComponent = BaseStyledComponent, rules: extendingRules, attrs, } = options;
const styledComponentId = options.displayName && options.componentId
? `${escape_1.default(options.displayName)}-${options.componentId}`
: options.componentId || componentId;
const componentStyle = new ComponentStyle(extendingRules === undefined ? rules : extendingRules.concat(rules), attrs, styledComponentId);
class StyledComponent extends ParentComponent {
static withComponent(tag) {
const { componentId: previousComponentId } = options, optionsToCopy = __rest(options, ["componentId"]);
const newComponentId = previousComponentId &&
`${previousComponentId}-${isTag_1.default(tag) ? tag : escape_1.default(getComponentName_1.default(tag))}`;
const newOptions = Object.assign({}, optionsToCopy, { componentId: newComponentId, ParentComponent: StyledComponent });
return createStyledComponent(tag, newOptions, rules);
}
static get extend() {
const { rules: rulesFromOptions, componentId: parentComponentId } = options, optionsToCopy = __rest(options, ["rules", "componentId"]);
const newRules = rulesFromOptions === undefined
? rules
: rulesFromOptions.concat(rules);
const newOptions = Object.assign({}, optionsToCopy, { rules: newRules, parentComponentId, ParentComponent: StyledComponent });
return constructWithOptions(createStyledComponent, target, newOptions);
}
}
StyledComponent.attrs = attrs;
StyledComponent.componentStyle = componentStyle;
StyledComponent.displayName = displayName;
StyledComponent.styledComponentId = styledComponentId;
StyledComponent.target = target;
StyledComponent.contextTypes = {
[ThemeProvider_1.CHANNEL]: prop_types_1.default.func,
[ThemeProvider_1.CHANNEL_NEXT]: ThemeProvider_1.CONTEXT_CHANNEL_SHAPE,
[constants_1.CONTEXT_KEY]: prop_types_1.default.oneOfType([
prop_types_1.default.instanceOf(StyleSheet_1.default),
prop_types_1.default.instanceOf(ServerStyleSheet_1.default),
]),
};
if (process.env.NODE_ENV !== 'production') {
StyledComponent.warnTooManyClasses = createWarnTooManyClasses_1.default(displayName);
}
if (isClass) {
hoist_non_react_statics_1.default(StyledComponent, target, {
// all SC-specific things should not be hoisted
attrs: true,
componentStyle: true,
displayName: true,
extend: true,
styledComponentId: true,
target: true,
warnTooManyClasses: true,
withComponent: true,
});
}
return StyledComponent;
};
return createStyledComponent;
};
exports.default = exporting;
//# sourceMappingURL=StyledComponent.js.map