Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
react-marks
Advanced tools
React component for combine editable text with any component using annotated text
A React component that lets you combine editable text with any component using annotated text.
Install the package via npm:
npm install rc-marked-input
A lot of examples can be seen in the storybook. You can also try a template on CodeSandbox.
Here is some examples to get you started.
import {MarkedInput} from "rc-marked-input";
const Mark = (props) => <mark onClick={_ => alert(props.value)}>{props.label}</mark>
const Marked = () => {
const [value, setValue] = useState("Hello, clickable marked @[world](Hello! Hello!)!")
return <MarkedInput Mark={Mark} value={value} onChange={setValue}/>
}
The library allows you to configure the MarkedInput
component in two ways.
Let's declare markups and suggestions data:
const Data = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth"]
const AnotherData = ["Seventh", "Eight", "Ninth"]
const Primary = "@[__label__](primary:__value__)"
const Default = "@[__label__](default)"
Using the components
import {MarkedInput, Option} from "rc-marked-input";
export const App = () => {
const [value, setValue] = useState(
"Enter the '@' for creating @[Primary Mark](primary:Hello!) or '/' for @[Default mark](default)!"
)
return (
<MarkedInput Mark={Button} value={value} onChange={setValue}>
<Option
markup={Primary}
data={Data}
initMark={({label, value}) => ({label, primary: true, onClick: () => alert(value)})}
/>
<Option
markup={Default}
trigger="/"
data={AnotherData}
/>
</MarkedInput>
)
}
Using the createMarkedInput
:
import {createMarkedInput} from "rc-marked-input";
const ConfiguredMarkedInput = createMarkedInput(Button, [{
markup: Primary,
data: Data,
initMark: ({label, value}) => ({label, primary: true, onClick: () => alert(value)})
}, {
trigger: '/',
markup: Default,
data: AnotherData
}])
const App = () => {
const [value, setValue] = useState(
"Enter the '@' for creating @[Primary Mark](primary:Hello!) or '/' for @[Default mark](default)!"
)
return <ConfiguredMarkedInput value={value} onChange={setValue}/>
}
Marks can be dynamic: editable, removable, etc. via the useMark
hook helper.
import {MarkedInput, useMark} from "rc-marked-input";
const Mark = () => {
const {label, onChange} = useMark()
const handleInput = (e) =>
onChange({label: e.currentTarget.textContent ?? "", value: " "}, {silent: true})
return <mark contentEditable onInput={handleInput} children={label}/>
}
export const Dynamic = () => {
const [value, setValue] = useState("Hello, dynamical mark @[world]( )!")
return <MarkedInput Mark={Mark} value={value} onChange={setValue}/>
}
Note: The silent option used to prevent re-rendering itself.
const RemovableMark = () => {
const {label, onRemove} = useMark()
return <mark onClick={onRemove} children={label}/>
}
export const Removable = () => {
const [value, setValue] = useState("I @[contain]( ) @[removable]( ) by click @[marks]( )!")
return <MarkedInput Mark={RemovableMark} value={value} onChange={setValue}/>
}
If passed the reg
prop of the useMark
hook in ref of a component then it component can be focused by key operations.
A default overlay is the suggestion component, but it can be easily replaced for any other.
export const DefaultOverlay = () => {
const [value, setValue] = useState("Hello, default - suggestion overlay by trigger @!")
return <MarkedInput Mark={Mark} value={value} onChange={setValue}>
<Option data={['First', 'Second', 'Third']}/>
</MarkedInput>
}
const Overlay = () => <h1>I am the overlay</h1>
export const CustomOverlay = () => {
const [value, setValue] = useState("Hello, custom overlay by trigger @!")
return <MarkedInput Mark={Mark} Overlay={Overlay} value={value} onChange={setValue}/>
}
export const CustomTrigger = () => {
const [value, setValue] = useState("Hello, custom overlay by trigger /!")
return <MarkedInput Mark={Mark} Overlay={Overlay} value={value} onChange={setValue}>
<Option trigger='/'/>
</MarkedInput>
}
The OverlayProps
has a left and right absolute coordinate of a current caret position in the style
prop.
const Tooltip = (props: OverlayProps) => <div style={{position: 'absolute', ...props.style}}>I am the overlay</div>
export const PositionedOverlay = () => {
const [value, setValue] = useState("Hello, positioned overlay by trigger @!")
return <MarkedInput Mark={Mark} Overlay={Tooltip} value={value} onChange={setValue}/>
}
The OverlayProps
provide some methods like onSelect
for creating a new annotation.
const List = (props: OverlayProps) => <ul>
<li onClick={() => props.onSelect({label: 'First'})}>Clickable First</li>
<li onClick={() => props.onSelect({label: 'Second'})}>Clickable Second</li>
</ul>
export const SelectableOverlay = () => {
const [value, setValue] = useState("Hello, suggest overlay by trigger @!")
return <MarkedInput Mark={Mark} Overlay={List} value={value} onChange={setValue}/>
}
Note: Recommend to use the
React.forwardRef
for an overlay component. It used to detect outside click.
The onContainer
prop allows to forward any of div events to a container of text.
<ConfiguredMarkedInput
value={value}
onChange={setValue}
onContainer={{
onClick: (e) => console.log('onCLick'),
onInput: (e) => console.log('onInput'),
onBlur: (e) => console.log('onBlur'),
//...
onFocus: (e) => console.log('onFocus'),
onKeyDown: (e) => console.log('onKeyDown'),
}}
/>
<MarkedInput Mark={Mark} Overlay={Overlay} value={value} onChange={setValue}>
<Option
trigger='@'
markup='@[__label__](__value__)'
data={Data}
initMark={getCustomMarkProps}
initOverlay={getCustomOverlayProps}
/>
<Option
trigger='/'
markup='@(__label__)[__value__]'
data={AnotherData}
initMark={getAnotherCustomMarkProps}
initOverlay={getAnotherCustomOverlayProps}
/>
</MarkedInput>
Or
const MarkedInput = createMarkedInput(Mark, Overlay, [{
trigger: '@',
markup: '@[__label__](__value__)',
data: Data,
initMark: getCustomMarkProps,
initOverlay: getCustomOverlayProps,
}, {
trigger: '/',
markup: '@(__label__)[__value__]',
data: AnotherData,
initMark: getAnotherCustomMarkProps,
initOverlay: getAnotherCustomOverlayProps,
}])
const App = () => <MarkedInput value={value} onChange={setValue}/>
Name | Type | Default | Description |
---|---|---|---|
value | string | Annotated text with markups for mark | |
onChange | (value: string) => void | Change event | |
Mark | ComponentType<T = MarkProps> | Component that used for render markups | |
Overlay | ComponentType<T = OverlayProps> | Suggestions | Component that is rendered by trigger |
readOnly | boolean | undefined | Prevents from changing the value |
onContainer | DivEvents | undefined | Forward any div events to a text container |
Name | Type | Default | Description |
---|---|---|---|
markup | string | @[__label__](__value__) | Template string instead of which the mark is rendered Must contain placeholders: __label__ and optional __value__ __value__ For example: @[__label__](__value__) |
trigger | string | "@" | Sequence of symbols for calling the overlay. |
data | string[] | [] | Data for a overlay component. By default, it is suggestions. |
initMark | (props: MarkProps) => T | undefined | Function to initialize props for mark render. Gets arguments from found markup |
initOverlay | (props: OverlayProps) => T1 | undefined | Function to initialize overlay props to your requirements. If missing then passed overlay props directly. |
Name | Type | Description |
---|---|---|
createMarkedInput | (Mark: ComponentType, options: OptionProps[]): ConfiguredMarkedInput (Mark: ComponentType, Overlay: ComponentType, options: OptionProps<T, T1>[]): ConfiguredMarkedInput | Create the configured MarkedInput component. |
annotate | (markup: Markup, label: string, value?: string) => string | Make annotation from the markup |
denote | (value: string, callback: (mark: Mark) => string, ...markups: Markup[]) => string | Transform the annotated text |
useMark | () => DynamicMark | Allow to use dynamic mark |
interface MarkProps {
label: string
value?: string
}
interface OverlayProps {
/**
* Style with caret absolute position. Used for placing an overlay.
*/
style: {
left: number
top: number
}
/**
* Used for close overlay.
*/
onClose: () => void
/**
* Used for insert an annotation instead a triggered value.
*/
onSelect: (value: MarkProps) => void
/**
* Trigger details
*/
trigger: Trigger
}
type Trigger = {
/**
* Found value via a trigger
*/
value: string,
/**
* Triggered value
*/
source: string,
/**
* Piece of text, in which was a trigger
*/
span: string,
/**
* Html element, in which was a trigger
*/
node: Node,
/**
* Start position of a trigger
*/
index: number,
/**
* Trigger's option
*/
option: OptionType
}
If you want to contribute, you are welcome! Create an issue or start a discussion.
FAQs
React component for combine editable text with any component using annotated text
The npm package react-marks receives a total of 2 weekly downloads. As such, react-marks popularity was classified as not popular.
We found that react-marks demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.