GithubHelp home page GithubHelp logo

milesj / interweave Goto Github PK

View Code? Open in Web Editor NEW
1.0K 9.0 38.0 9.29 MB

๐ŸŒ€ React library to safely render HTML, filter attributes, autowrap text with matchers, render emoji characters, and much more.

Home Page: https://interweave.dev

License: MIT License

JavaScript 0.94% HTML 0.20% CSS 2.81% TypeScript 85.48% MDX 10.58%
react html-parsing emoji-unicode matcher react-elements interpolation autolink emoji emoji-picker

interweave's Introduction

Interweave

Build Status npm version npm deps

Interweave is a robust React library that can...

  • Safely render HTML without using dangerouslySetInnerHTML.
  • Safely strip HTML tags.
  • Automatic XSS and injection protection.
  • Clean HTML attributes using filters.
  • Interpolate components using matchers.
  • Autolink URLs, IPs, emails, and hashtags.
  • Render Emoji and emoticon characters.
  • And much more!
<Interweave content="This string contains <b>HTML</b> and will safely be rendered!" />
<Interweave
	content="This contains a URL, https://github.com/milesj/interweave, and a hashtag, #interweave, that will be converted to an anchor link!"
	matchers={[new UrlMatcher('url'), new HashtagMatcher('hashtag')]}
/>

Requirements

  • React 16.8+ / 17+
  • IE 11+
  • Emoji support: fetch, sessionStorage

Installation

Interweave requires React as a peer dependency.

yarn add interweave react
// Or
npm install interweave react

Documentation

https://interweave.dev

interweave's People

Contributors

abinshoby avatar adauleu avatar alecklandgraf avatar arcataroger avatar arsinclair avatar bryndyment avatar ci7lus avatar dependabot[bot] avatar elieux avatar fforres avatar mattheu avatar michaelkantor avatar milesj avatar rmccue avatar trysound 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  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  avatar  avatar  avatar  avatar  avatar  avatar

interweave's Issues

Conditionally styled emoji

Hi, first of all, this is damn great work, respect, and i don't know why this repo doesn't have a millions stars yet.

Now to my question. Basically what I need to do is to render Slack-like jumboji, e.g. if chat message consists of a single emoji - render is larger. And ofc performance is important.

Right now I achieve that by detecting single emoji in onAfterParse and re-rendering message component. This is not ideal so I am thinking of ways to implement it in PR so that you would consider it useful and accept it.

Thoughts?

srcset not supported attribute on img

img supports src, but not srcset or sizes. This means that we're not able to progressively load image sizes, and can lead to inconsistency with using Interweave as a replacement for regular HTML parsing.

For example:

<img
    src="//placehold.it/300x147"
    srcset="//placehold.it/1024x501 1024w"
    sizes="(max-width: 1099px) 100vw, 1099px"
    width="1099"
    height="539"
/>

Expected: see "1024 x 501" image.
Actual: see "300 x 147" image.

Use custom whitelist

It's at least not clear from the documentation, or maybe even not possible - but how can I provide a custom whitelist of tags, and allow e.g. only <b> and <i> and remove everything else?

Allow using Fragment for tagName

It would be great if the top-level Element could be any React component rather than specifically just a DOM string. In particular, it'd be nice to be able to use React.Fragment in order to avoid having any wrapper at all with React 16.2+.

Save just rich text from Interweave?

I'm using Interweave along with Kendo Editor in React. It is working great and binding to the Kendo Editor just fine.
The issue is that I need to just save the rich text without the Interweave elements or comments. I have a limited amount of characters I can use and Interweave takes up a lot of extra space.
When I use editor.value() I get something like this:

<p class="interweave interweave"><strong class="interweave interweave"><!-- react-text: 1060 -->dasd&nbsp; this is bold<!-- /react-text --></strong></p>

I really just want < strong >this is bold< /strong >
Can I get just the rich text out of the Interweave component somehow?

I really like the component. Super easy to use so far. Thanks so much for it!

Support for disabling tag / attribute filtering and / or creating custom filter lists

Interweave is a solid library that is fairly flexible. However, we currently use sanitize for filtering tags and attributes with a more permissive list for our use case. Unfortunately, when we apply interweave currently those more permissive items are removed... we need to either disable filtering in interweave or expand the list to be more permissive. I was initially thinking disabling would be better, but I do like the performance benefits of doing both filtering and autolinking in a single pass.

I am happy to implement the feature, but want to be sure to do it in a way that is helpful to the library and likely to be merged back in. Do you have any thoughts or suggestions on how to best approach the problem?

Thanks

Valid boolean attributes are stripped

I have HTML content which looks like:

<video controls muted src="http://example.com">

Interweave treats these attributes as false when casting to boolean. It also treats "true" as truthy.

Per the HTML specification:

If the attribute is present, its value must either be the empty string or a value that is an ASCII case-insensitive match for the attribute's canonical name, with no leading or trailing whitespace.
Note: The values "true" and "false" are not allowed on boolean attributes. To represent a false value, the attribute has to be omitted altogether.

Add option to disable user-provided HTML

It'd be nice if there was a way for Interweave to block user-provided HTML (html coming through
the content prop), but allow HTML generated from matchers. This can be useful if you don't want users to put in HTML, but you still want interweave to render emojis, links, etc. noHtml acts as a pass-through and doesn't hit the matchers.

Allow specifying large emoji em size

Right now the large emoji is just 3 * the emojiSize prop. It'd be nice to specify an emojiSizeLarge prop that you can use to overwrite this behavior and set how large you want your large emojis to be.

Allow component refs for factories

new UrlMatcher('url', {}, ComponentRef) instead of new UrlMatcher('url', {}, (match, props) => <Component {...props}>{match}</Component>).

<em>{MyMatchString}</em> is never fed into the matchers

Not sure why, but any type of tags in this list:

  'a',
  'abbr',
  'b',
  'br',
  'button',
  'canvas',
  'cite',
  'code',
  'del',
  'dfn',
  'em',
  'i',
  'iframe',
  'img',
  'ins',
  'kbd',
  'label',
  'mark',
  'output',
  'q',
  's',
  'samp',
  'script',
  'source',
  'span',
  'strong',
  'sub',
  'sup',

Is not being parsed by the matchers. But in div and some other tag types my content gets parsed. Trying to understand why.

Error: Invalid size returned for cell 0 of value NaN

Hi, I'm trying to use this EmojiPicker like explained here https://milesj.gitbook.io/interweave/extensions/emoji-picker and no matter what I do, I always get this error:
Uncaught (in promise) Error: Invalid size returned for cell 0 of value NaN
at CellSizeAndPositionManager.getSizeAndPositionOfCell (CellSizeAndPositionManager.js:92)
at CellSizeAndPositionManager.getUpdatedOffsetForIndex (CellSizeAndPositionManager.js:165)
at ScalingCellSizeAndPositionManager.getUpdatedOffsetForIndex (ScalingCellSizeAndPositionManager.js:114)
at Function._getCalculatedScrollTop (Grid.js:1260)
at Function._getScrollTopForScrollToRowStateUpdate (Grid.js:1274)
at updateScrollOffsetForScrollToIndex (Grid.js:1125)
at calculateSizeAndPositionDataAndUpdateScrollOffset (calculateSizeAndPositionDataAndUpdateScrollOffset.js:22)
at getDerivedStateFromProps (Grid.js:1113)
at applyDerivedStateFromProps (react-dom.development.js:11016)
at mountClassInstance (react-dom.development.js:11368)
at updateClassComponent (react-dom.development.js:14347)
at beginWork (react-dom.development.js:15222)
at performUnitOfWork (react-dom.development.js:18789)
at workLoop (react-dom.development.js:18829)
at renderRoot (react-dom.development.js:18912)
at performWorkOnRoot (react-dom.development.js:19809)
at performWork (react-dom.development.js:19721)
at performSyncWork (react-dom.development.js:19695)
at requestWork (react-dom.development.js:19564)
at scheduleWork (react-dom.development.js:19373)
at Object.enqueueSetState (react-dom.development.js:11051)
at WithEmojiData../node_modules/react/cjs/react.development.js.Component.setState (react.development.js:335)
at WithEmojiData.setEmojis (withEmojiData.js:98)
at withEmojiData.js:133

It is just a simple empty react project. Is there anything I am missing?

Fix node array types

TS doens't really like React.ReactNode[] usage. Try and use React.ReactNode itself.

Picker declaration file is super wrong

Is doing a ton of local imports which break everything:

declare const _default: {
    new (props: Readonly<PickerProps & import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps>): {
        state: {
            emojis: never[];
            source: {
                compact: boolean;
                locale: string;
                version: string;
            };
        };
        componentDidMount(): void;
        componentDidUpdate(prevProps: import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps): void;
        /** Icon to display within the clear commonly used button. Omit the icon to hide the button. */
        getDataInstance(): import("../../emoji/lib/EmojiDataManager").default;
        setEmojis(emojis?: import("../../../node_modules/emojibase/lib/types").Emoji[] | undefined): void;
        loadEmojis(): Promise<void>;
        render(): JSX.Element | null;
        setState<K extends "source" | "emojis">(state: import("../../emoji/lib/withEmojiData").WithEmojiDataState | Pick<import("../../emoji/lib/withEmojiData").WithEmojiDataState, K> | ((prevState: Readonly<import("../../emoji/lib/withEmojiData").WithEmojiDataState>, props: Readonly<PickerProps & import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps>) => import("../../emoji/lib/withEmojiData").WithEmojiDataState | Pick<import("../../emoji/lib/withEmojiData").WithEmojiDataState, K> | null) | null, callback?: (() => void) | undefined): void;
        forceUpdate(callBack?: (() => void) | undefined): void;
        readonly props: Readonly<{
            children?: React.ReactNode;
        }> & Readonly<PickerProps & import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps>;
        context: any;
        refs: {
            [key: string]: React.ReactInstance;
        };
    };
    new (props: PickerProps & import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps, context?: any): {
        state: {
            emojis: never[];
            source: {
                compact: boolean;
                /** Hide group headers within the list. */
                locale: string;
                version: string;
            };
        };
        componentDidMount(): void;
        componentDidUpdate(prevProps: import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps): void;
        getDataInstance(): import("../../emoji/lib/EmojiDataManager").default; /** Mapping of custom translation messages. */
        setEmojis(emojis?: import("../../../node_modules/emojibase/lib/types").Emoji[] | undefined): void;
        loadEmojis(): Promise<void>;
        render(): JSX.Element | null;
        setState<K extends "source" | "emojis">(state: import("../../emoji/lib/withEmojiData").WithEmojiDataState | Pick<import("../../emoji/lib/withEmojiData").WithEmojiDataState, K> | ((prevState: Readonly<import("../../emoji/lib/withEmojiData").WithEmojiDataState>, props: Readonly<PickerProps & import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps>) => import("../../emoji/lib/withEmojiData").WithEmojiDataState | Pick<import("../../emoji/lib/withEmojiData").WithEmojiDataState, K> | null) | null, callback?: (() => void) | undefined): void;
        forceUpdate(callBack?: (() => void) | undefined): void;
        readonly props: Readonly<{
            children?: React.ReactNode;
        }> & Readonly<PickerProps & import("../../emoji/lib/withEmojiData").WithEmojiDataWrapperProps>;
        context: any;
        refs: {
            [key: string]: React.ReactInstance;
        };
    };
    propTypes: {
        compact: PropTypes.Requireable<any>;
        emojis: PropTypes.Requireable<any>;
        locale: PropTypes.Requireable<any>;
        version: PropTypes.Requireable<any>;
    }; /** Custom props to pass to react-virtualized list component. */
    defaultProps: {
        compact: boolean;
        emojis: never[];
        locale: string;
        version: string;
    };
};
export default _default;

URL parsing fails on Facebook links

Facebook links with the form https://www.facebook.com/abcde.fge.3?ref=br_rs are not correctly parsed. https://www.facebook.com/abcde.fge is treated as a hyperlink, and the remaining .3?ref=br_rs is treated as plain text trailing the hyperlink.

Swap out HTML component for another

Iโ€™d like to be able to swap out certain components for others. As far as I can tell, matchers only let you do this inside the text content of nodes, not adjust the nodes themselves.

(Specifically, I want to match lists with a class and swap them out for an interactive React component instead, to enable GitHub-style task lists.)

Add an emptyContent prop

For instances where a content string is empty, or produces no output, allow an "empty content" element to be rendered.

Add parent parser setting

Right now we can whitelist the children an element can have (ul can only have lis) but we don't do the reverse. We should support this.

'type' attribute should be whitelisted for 'source' element

The <source> element inside <video> or <audio> can have a type attribute:

The type attribute may be present. If present, the value must be a valid MIME type string.

Without this, browsers may not (and indeed, Firefox at least does not) load the source. type should be declared as FILTER_ALLOW in the attribute list.

Dealing with blacklisted tags

I have some content which has embedded media in it. These embeds almost entirely use blacklisted elements, typically iframe.

I don't expect Interweave to handle these, but I'd like to be able to build in custom functionality on this, so that we can whitelist specific embeds from external sources, and embed these ourselves with custom React elements.

For example, a Spotify embed:

<iframe src="https://open.spotify.com/embed/track/6wg8nDWs3MAUEYEd8tO6Hf" width="300" height="380" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe>

We can match this to a SpotifyEmbed component, except that there's no way of disabling the blacklist, or handling these in transform.

Not sure what the best solution to this should be, but interested in discussing possible paths towards sorting this out.

Sidenote: Some embeds (e.g. Twitter) use a HTML element + script tag. These can be sorted nicely with a transform already, because we can match the HTML element. We can also manage this with a custom container wrapper.

Picker issues

Done

  • emojis prop needs to be an array.
  • emoji.primary_shortcode needs to be a string, not an array.
  • Picker render list needs keys.
  • Dashed words arent capitalized. Europe-australia, etc.
  • Let messages be nodes.
  • Defocus selected emoji once selected.

Todo

  • tab/arrow/enter/etc should work while searching.

Documentation improvements

Hello, the documentation provided is comprehensive, but quite dry. This is a fantastic library, but its difficult to use until you give people a jump start with examples of actual code snippets and how to use.

Couple of month ago, I could not figure out how to actually use it to render HTML, nothing in the doc gave even a simple example. Finally I found just one example on this thread https://stackoverflow.com/a/47159227 and used it successfully. The Markup component is not even mentioned in your documentation.

Now I wanted to use autolinking for URLs. Again there are no examples of how one can actually accomplish this. I had to hack it together by reading https://milesj.gitbook.io/interweave/extensions/autolink and https://github.com/milesj/interweave/blob/master/tests/bundle.tsx and https://github.com/humanmade/interweave.

Thanks.

Allow null for content

Sometimes variables passed to content can be null or undefined, which in turn throws prop type warnings. Let's just allow an empty content and default it to an empty string.

loader HOC doesnt work with locales

The loaded var is global, but locales can change, so this can be problematic. Set loaded based on locale + compact combos.

data/emoji also doesnt allow for multiple locales.

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.