Skip to content

Commit

Permalink
feat: add the ability to switch off emotion
Browse files Browse the repository at this point in the history
New prop `withoutEmotion`.

Emotion makes development easier, but it can make the consumption of
a library harder on the users. This option allows the user to remove
all usage of emotion in @remirror/react so and provide total freedom
to style their components as they please.

In a future commit perhaps provide some default CSS files which can be
used or extended.
  • Loading branch information
ifiokjr committed Jun 21, 2019
1 parent 027e497 commit 190702f
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 9 deletions.
10 changes: 9 additions & 1 deletion @remirror/react-utils/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { jsx } from '@emotion/core';
import { css, jsx } from '@emotion/core';
import {
AnyFunction,
bool,
Expand Down Expand Up @@ -162,3 +162,11 @@ export const propIsFunction = (prop: unknown): prop is AnyFunction => {
}
return true;
};

/**
* A noop function that mimics the css emotion call but renders no output.
*
* @remarks
* This is useful for enabling the library user to switch of emotion for core react elements.
*/
export const cssNoOp: typeof css = () => undefined as any;
10 changes: 10 additions & 0 deletions @remirror/react-utils/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,16 @@ export interface RemirrorProps extends StringHandlerParams {
* This can be overridden with this property
*/
forceEnvironment?: RenderEnvironment;

/**
* Removes the emotion injected styles from the component.
*
* @remarks
* This is accomplished by making the `css` function a noop.
*
* @default false
*/
withoutEmotion: boolean;
}

export interface PlaceholderConfig {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ test('RemirrorProvider', () => {
);
const reactString = renderToStaticMarkup(element);
expect(reactString).toInclude('basic');
expect(reactString).toMatchSnapshot();
});

test('ManagedRemirrorProvider', () => {
Expand Down
16 changes: 16 additions & 0 deletions @remirror/react/src/components/__tests__/remirror-server.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,22 @@ test('prepends to the react element when insertPosition=start with getRootProps'
expect(isAscending([indexOfInjectedSSRComponent, indexOfInnerDiv, indexOfOuter])).toBeTrue();
});

describe('withoutEmotion', () => {
it('should not render extra class names when true', () => {
const manager = createTestManager();
const child = () => <div data-testid='test' />;
const withEmotionString = renderToString(<Remirror manager={manager}>{child}</Remirror>);
expect(withEmotionString).toInclude('css-');

const withoutEmotionString = renderToString(
<Remirror manager={manager} withoutEmotion={true}>
{child}
</Remirror>,
);
expect(withoutEmotionString).not.toInclude('css-');
});
});

/**
* Check that the numbers passed in are of ascending order.
*
Expand Down
16 changes: 16 additions & 0 deletions @remirror/react/src/components/__tests__/remirror.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,19 @@ describe('Remirror Controlled Component', () => {
expect(getByRole('textbox')).toContainHTML(expectedContent);
});
});

describe('withoutEmotion', () => {
it('should not render extra class names when true', () => {
const manager = createTestManager();
const child = () => <div data-testid='test' />;
const { getByTestId, rerender } = render(<Remirror manager={manager}>{child}</Remirror>);
expect(getByTestId('test')).toHaveAttribute('class');

rerender(
<Remirror manager={manager} withoutEmotion={true}>
{child}
</Remirror>,
);
expect(getByTestId('test')).not.toHaveAttribute('class');
});
});
7 changes: 6 additions & 1 deletion @remirror/react/src/components/remirror.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
BaseListenerParams,
CalculatePositionerParams,
cloneElement,
cssNoOp,
getElementProps,
GetPositionerPropsConfig,
GetPositionerReturn,
Expand Down Expand Up @@ -114,6 +115,10 @@ export class Remirror extends Component<RemirrorProps, CompareStateParams> {
return this.props.manager;
}

private get css(): typeof css {
return this.props.withoutEmotion ? cssNoOp : css;
}

constructor(props: RemirrorProps) {
super(props);

Expand Down Expand Up @@ -219,7 +224,7 @@ export class Remirror extends Component<RemirrorProps, CompareStateParams> {
return {
[refKey]: this.onRef,
key: this.uid,
css: css(this.editorStyles),
css: this.css(this.editorStyles),
...config,
children: this.renderChildren(null),
} as RefKeyRootProps<GRefKey>;
Expand Down
1 change: 1 addition & 0 deletions @remirror/react/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const defaultProps = asDefaultProps<RemirrorProps>()({
label: '',
editorStyles: {},
insertPosition: 'end',
withoutEmotion: false,
stringHandler: () => {
throw new Error(
'No valid string handler. In order to pass in `string` as `initialContent` to the remirror editor you must provide a valid stringHandler prop',
Expand Down
35 changes: 32 additions & 3 deletions @remirror/react/src/node-views/node-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,28 @@ import {
PlainObject,
ProsemirrorNode,
} from '@remirror/core';
import { RemirrorProps } from '@remirror/react-utils';
import { css, Interpolation } from 'emotion';
import { Decoration, EditorView, NodeView } from 'prosemirror-view';

export type GetPosition = () => number;

/**
* A mimic of the css method except that this one does nothing but return an empty string.
*
* @remark
* Used to switch off emotion css injection
*/
const cssNoOp: typeof css = () => '';

export interface NodeViewComponentProps<GAttrs = any> extends EditorViewParams {
node: ProsemirrorNode & { attrs: GAttrs };
getPosition: GetPosition;
forwardRef?: (node: HTMLElement) => void | undefined;
}

export interface CreateNodeViewParams<GProps extends PlainObject = {}> {
export interface CreateNodeViewParams<GProps extends PlainObject = {}>
extends Partial<Pick<RemirrorProps, 'withoutEmotion'>> {
Component: ComponentType<NodeViewComponentProps & GProps>;
getPortalContainer: () => NodeViewPortalContainer;
props: GProps;
Expand All @@ -37,9 +47,20 @@ export class ReactNodeView<GProps extends PlainObject = {}> implements NodeView
getPortalContainer,
props,
style,
withoutEmotion,
}: CreateNodeViewParams<GProps>) {
return (node: ProsemirrorNode, view: EditorView, getPosition: GetPosition) =>
new ReactNodeView(node, view, getPosition, getPortalContainer, props, Component, false, style).init();
new ReactNodeView(
node,
view,
getPosition,
getPortalContainer,
props,
Component,
false,
style,
withoutEmotion,
).init();
}

private domRef?: HTMLElement;
Expand All @@ -55,8 +76,16 @@ export class ReactNodeView<GProps extends PlainObject = {}> implements NodeView
private Component: ComponentType<NodeViewComponentProps & GProps>,
private hasContext: boolean = false,
private style: Interpolation = {},
private withoutEmotion: boolean = false,
) {}

/**
* The CSS transformation property depending on whether the emotion is being used or not.
*/
private get css(): typeof css {
return this.withoutEmotion ? cssNoOp : css;
}

/**
* This method exists to move initialization logic out of the constructor,
* so the object can be initialized properly before calling render first time.
Expand All @@ -82,7 +111,7 @@ export class ReactNodeView<GProps extends PlainObject = {}> implements NodeView
}

// Add a fixed class and a dynamic class to this node (allows for custom styles being added in configuration)
this.domRef.classList.add(`${EDITOR_CLASS_NAME}-${this.node.type.name}-node-view`, css(this.style));
this.domRef.classList.add(`${EDITOR_CLASS_NAME}-${this.node.type.name}-node-view`, this.css(this.style));

this.renderReactComponent(() => this.render(this.props, this.handleRef));
return this;
Expand Down
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project will adhere to [Semantic Versioning](https://semver.org/spec/v2

## [Unreleased]

### Added

- `@remirror/react`: Add `withoutEmotion` which, when set to `true`, removes emotion (css-in-js) from the `Remirror` component. This is for those who don't like css-in-js and would like to work directly with the raw editor without random styles injected. Consuming the `@remirror/react-components` or any of the `@remirror/editor-*` packages will require the use of emotion.

### Changed

- **BREAKING `remirror/react-utils`:** Rename `childIsFunction` to `propIsFunction` and make it a _pseudo_ predicate function (returns true when it doesn't throw an error).
Expand Down

0 comments on commit 190702f

Please sign in to comment.