Coder Social home page Coder Social logo

ashleyw / react-sane-contenteditable Goto Github PK

View Code? Open in Web Editor NEW
51.0 3.0 20.0 2.19 MB

React component with sane defaults to make any element contentEditable

License: MIT License

JavaScript 98.58% HTML 1.42%
contenteditable react react-component text-editor

react-sane-contenteditable's Introduction

react-sane-contenteditable

npm version

React component with sane defaults to make any element contentEditable

Why?

ContentEditable has some well known issues, and the purpose of this component is to deal with them in a sane manner so we don't have to continue re-inventing the wheel! 🔥

  • Clean and sanitise the output
  • Remove rich text formatting when pasting
  • Prevent the cursor from jumping around

Example

import React, { Component } from 'react';
import ContentEditable from 'react-sane-contenteditable';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      title: 'Title here',
    };
  }

  handleChange = (ev, value) => {
    this.setState({ title: value });
  };

  render() {
    return (
      <div className="App">
        <ContentEditable
          tagName="h1"
          className="my-class"
          content={this.state.title}
          editable={true}
          maxLength={140}
          multiLine={false}
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

Develop

Tests

yarn test

Linting

yarn run lint

Dev

Runs the rollup dev server with file watching on both the src and demo

yarn run dev

react-sane-contenteditable's People

Contributors

ahutchings avatar ashleyw avatar dependabot[bot] avatar ethanlee16 avatar jesstelford avatar nijk avatar strass avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-sane-contenteditable's Issues

Maintenance roadmap

General maintenance

  1. PeerDependencies
  2. Remove lodash as a dependency by refactoring its usage to vanilla js. If this isn’t straight-forward then I’d like to limit it’s usage so that consumers of this lib are not weighed down by it - this would be obvious if we bundled the build output which we don’t, currently I think there’s an issue in that we are exposing the es6 import keyword here. Not an issue if you’re using this lib in a project with a bundler, but it may trip some users up. In any case if the deps can be removed entirely then I think this would be the best way forward.
  3. Test the component x-browser and add any necessary fixes, I think that innerText might be an issue on IE. I’m not sure what it has been tested against but it wouldn’t do any harm to do some more testing
  4. Update the documentation to ensure it covers all the bases, for example when I starting looking at this lib it was difficult to understand how to use it with StyledComponents without digging through the code.
  5. Improve the props vs state anti-pattern going on in the component. Bug here

Features

  1. Introduce some XSS mitigation with using the component with props.sanitise
  2. Run the linting & tests on pre-commit using Husky

on paste of multiline text while multiline is false .

Even after using prop multiline as false . on paste of multiline text is creating multi line content( while typing content is not going in multiline as expected but while pasting even with multiline prop as false it's pasting contents on multiline structure as copied ) .

Multiline problem

I am trying to use multiline prop here, but whenever I add that a lot of weird stuff is happening and I'm following the example you guys have, like if I start to enter a text and I press enter the input | goes to the 0 index of the text and also it's writing text in another order if I write "love" it will write "evol".
can someone help me please?

class App extends Component {
  constructor(props) {
    super(props);
 
    this.state = {
      title: 'Title here',
    };
  }
 
  handleChange = (ev, value) => {
    console.log(ev);
    this.setState({ title: value });
  };

  handlePaste = (value) => console.log('paste', value);

  handleEvent = (ev, value) => {
    ev.persist();
    console.log(ev.type, ev, value);
  };
 
  render() {
    return (
      <div className="App">
        <ContentEditable
          tagName="h1"
          content={this.state.title}
          editable
          focus
          multiLine
          maxLength={140}
          multiLine={true}
          onBlur={this.handleEvent}
          onChange={this.handleChange}
          onKeyDown={this.handleEvent}
          onKeyUp={this.handleEvent}
          onPaste={this.handlePaste}
          caretPosition="end"
        />
      </div>
    );
  }
}

export default App;

``

Breaking change in 1.6.0

In 1.6.0, the onChange prop is called with onChange(value). Prior to this version it was called with onChange(event, value).

My use cases for this library don't need the event, but this change does break existing code reading the value from the 2nd parameter position. I have a library which depends on ^1.5.0, so a user of the library will soon install 1.6 and experience the issue.

Per the SemVer FAQ, the thing to do in this case is to publish a new minor version restoring the previous behavior. That will ensure that anyone depending on ^1 won't run into this change. You may also want to deprecate 1.6.0. If the change to the onChange is intentional and still desired, it could then be released as 2.0.0.

Thank you in advance for your prompt attention. It's only been a few hours since 1.6 was released so I'm hoping this can be rectified before users run into this. Please let me know if I can do anything to assist with the process!

Change deps to peerDeps

Change the react, prop-types & lodash dependencies to be peerDependencies, this will allow smaller builds for people using this lib as it won’t include another version of these deps unnecessarily when users bundle this lib into their projects

handleChange not triggering

Hi Ashley!

I just implemented the react-sane into my application but it doesnt trigger the onChange event!

I'm binding the method on the constructor, the method exists and I placed the component on my render method. It renders correctly but doesnt trigger the handleChange! Here's the code!

binding on the constructor

    this.handleChange = this._handleChange.bind(this);

exposing the method

_handleChange(ev, value) {
    console.log('aaaaa'); // won't trigger
    this.setState({ title: value });
}

render

<ContentEditable
    tagName="div"
    styleName="message-field"
    content={ this.state.title }
    editable={ true }
    maxLength={ 10 }
    placeholder="Digite uma mensagem..."
    multiLine={ true }
    onChange={ this.handleChange }
/>

Could you give me a hand, please? :-)

Field loses focus when using useState hook

I have a working component that I'm rewriting to use the new React Hooks. Unfortunately, the rewritten component loses focus with every keystroke.

While using:
[email protected]
[email protected]

The following works great (keeps focus with each keystroke):

import React, { Component } from 'react';

export default class ItemNode extends Component {
  constructor(props) {
    super(props);
    this.state = {
      content: props.content
    };
  }

  handleChange(e, value){
    this.setState({ content: value });
  }
  
  render() {
    return (
      <div>
        <ContentEditable 
          content={this.state.content}
          editable={true}
          multiLine={false}
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

The following breaks (loses focus with each keystroke)

import React, { useState } from 'react';

function App(props){
  const [content, setContent] = useState('blah');
  
  function handleChange(e, value){
    setContent(value);
  }
  return (
    <div>
      <ContentEditable 
        content={content}
        editable={true}
        multiLine={false}
        onChange={handleChange}
      />
    </div>
  );
}

export default App;

Cursor jumps to start with latest v1.3.0 update

First of all, thanks for this component. It's been working great up until this latest update.

Now, whenever I type into the element, the cursor jumps to the front of the element with every key that is entered. I've rolled back to v1.2.0 and everything works fine again. But if I reinstall v1.3.0, the cursor starts behaving funny again. I've locked my dependency back to v1.2.0 for now, so I'm okay for the time being.

I'm not sure what changed in that latest version to cause that behavior, but thought I should report it. Let me know if you need any further info from me.

FYI, this is on Chrome 65.0.3325.181

Remove lodash

Remove lodash as a dependency by refactoring its usage to vanilla js. If this isn’t straight-forward then I’d like to limit it’s usage so that consumers of this lib are not weighed down by it - this would be obvious if we bundled the build output which we don’t, currently I think there’s an issue in that we are exposing the es6 import keyword here.

Not an issue if you’re using this lib in a project with a bundler, but it may trip some users up. In any case if the deps can be removed entirely then I think this would be the best way forward.

Throws error when `sanitise` is a function

    TypeError: Cannot read property 'rangeCount' of undefined

      85 |
      86 |   getRange () {
    > 87 |     return this.selection.rangeCount ? this.selection.getRangeAt(0) : document.createRange();
         |                           ^
      88 |   }
      89 |
      90 |   getCaret() {

      at ContentEditable.rangeCount [as getRange] (src/react-sane-contenteditable.js:87:27)
      at ContentEditable.getRange [as sanitiseValue] (src/react-sane-contenteditable.js:141:35)
      at new sanitiseValue (src/react-sane-contenteditable.js:52:19)

When calling it like so:

<ContentEditable content="Foobar" sanitise={() => {}} />

It looks like this is happening because this.selection is set in the constructor after it is used within this.sanitiseValue() > this.getRange():

https://github.com/ashleyw/react-sane-contenteditable/blob/master/src/react-sane-contenteditable.js#L52-L56

EDIT: Here's a unit test which shows the failure:

  it('calls sanitise function on mount', () => {
    const content = 'foo';
    const sanitise = jest.fn(value => value);
    const wrapper = mount(<ContentEditable content={content} sanitise={sanitise} />);

    expect(sanitise).toHaveBeenCalledWith(content, mockedRange);
  });

Unexpected identifier error

Trying to run this plugin on next.js (SSR) and I got the error below. I inspected the source and I see it still contains import and export statement.

Unexpected identifier
/Users/xyz/Documents/Gitlab/jet/node_modules/react-sane-contenteditable/lib/index.js:29
import React, { Component } from 'react';
       ^^^^^

Get the position of the marker

Hi,
I have a toolbar with some clickable elements and I want to append some text on the position of the marker when a button is clicked in the toolbar. Can I somehow retrieve this from your react-sane-contenteditable
? My Parent component knows the content but can it also track where the input marker is positioned so that it can append stuff in the correct position?

Put cursor at the end o text after updating content property

Hi, first thanks for this package doing awesome stuff with it ;)

I just strugling on how put the cursor at the end of my text, in my scenario many times I open an edit box that after component mount the text is injected on the content property via setState but ideally the cursor need to follow the end of text, is that possible right now?

Using version 1.3.4

Thanks!!!

Support Placeholder

I was thinking of adding support for placeholder because they provide more visual feedback what the rendered component is about (e.g. Typing message, Write a comment, etc.).

One way, and probably the easiest way I have found is using :empty:before pseudo CSS class. But the problem with that is we have to manage an extra CSS file just to get this right. Until now, CSS is absent from this project.

I'm here getting some ideas from maintainers what they thought would be the best thing to do?

Unconnected with state

Plugin does not re-render when you manually edit the state e.g from react dev tools. HOwvere the state changes from the onChange event trigger.

Any other place you try to update the value that holds the state doesn't affect the component, the value remains the same and not equal to the state.

babelHelpers is undefined

What?

  • lib/index.js mentions babelHelpers, but it isn't defined in the component.
  • It breaks usage of the package.

How to fix?

  • Possibly a bad transpilation? Maybe just rerunning the transpilation might help.
  • Otherwise an upgrade to Babel 7 might help.

Workarounds for now

  • I'm just using the src/react-sane-contenteditable.js, copied it into my project and it seems to work!

I've added a PR #10 that fixes the babelHelpers issue, by externalizing the external-helpers package to a .babelrc in the example folder.

shouldComponentUpdate blocks re-render on props not in propTypes

So if I pass a prop that is not in the propTypes for this component, i.e. a prop that I might be passing to a styledComponent that I'm using as the tagName and I happen to pass that prop after the initial render then the current implementation of shouldComponentUpdate returns false.

TypeScript Support

I have some TypeScript typings that I would like to contribute to this project, but I saw that there is a typescript branch that converts the source files over to TS. What is the status of that branch? Would it be helpful to contribute an updated PR converting the project to TS, or would you prefer a PR with the typings alone?

Issues with accessing Synthetic event onKeyDown

Firstly, thanks for providing this component it's really useful and simple to use!

I'm seeing some odd behaviour relating to synthetic events when using this lib, I'm unable to access the event object properties in a onKeyDown handler provided to <ContentEditable />. I believe this is down to React's Event polling, which as far as I can tell works fine for synchronous access to the event but not async access. At present this component is calling this.props.onKeyDown wrapped inside a setTimeout, which I believe is causing my particular issue.

I can't see any detrimental effects from removing the setTimeout and calling this.props.onKeyDown at the end on the _onKeyDown instance method when using this component in a React 16.4.0 project, however I'm sure this code would be here for a good reason, so I'm wondering what the reason is for needing it?

I'm happy to raise a PR for the change as I'd prefer to contribute than rely on a forked lib.

componentWillReceiveProps is deprecated

See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html for details

As of React 16.9, this now displays a warning in the console in dev mode:

react-dom.development.js:12054 Warning: componentWillReceiveProps has been renamed,
and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.

* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

Please update the following components: ContentEditable

Controlled Component Issues

Firstly, thanks for this awesome, lite, and simple component. If I haven't been able to explain the issue correctly please ask, I'll try to be more descriptive.

Codesandbox: https://codesandbox.io/s/24n6xqz6vp

I was trying to use this component into one of my projects. For some reason, I want to keep track of typed text into my redux state. So, I thought it would be best to make this component into a controlled component. But when I started to control the state (which I've passed through content prop) I got myself into some of the issues:

  1. Controlling the state of this component caused it to keep losing focus after each onKeyDown (after which I'm setting the state) event.
  2. I thought that setting focus prop to true will fix this issue but that causes some other problem. Now I'm not losing the focus but after each onKeyDown event my caretPosition is jumping back to the start of the text.
  3. Then again I thought that setting caretPosition to end will fix this issue but that causes some other problem. THE APP BREAKS 🤕

I have mapped the issues through comments in the sandbox link.
Also, If I can help in any sort I would love to. That will also help me for the Hacktoberfest.

When the user erase the text onChange is not trigger

Scenario

User types one letter then he deletes (backspace) the letter

Expected Behavior

onChange prop handler being called with empty value

Actual Behavior

onChange is not being called because of the guard this.state.value !== value

Posible solution

Add and extra condition to trigger onChange prop when the value is empty

I can work on it if you want to

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.