
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@oversword/context
Advanced tools
The Context
component will create an element for you, passing the children and attributes given to the Context
component onto the created element.
<Context className="Some-Class" title="Other Attributes" >
<div>
Child
</div>
<div>
Components!
</div>
</Context>
Results in:
<div class="Some-Class Context-Focus" title="Other Attributes" tabindex="0" data-contextid="42" >
<div>
Child
</div>
<div>
Components!
</div>
</div>
The DataContext
component will not create an element, and should be used only as a wrapper for other elements. The children will be rendered as normal, unaffected.
<DataContext>
<div>
Child
</div>
<div>
Components!
</div>
</DataContext>
Results in:
<div>
Child
</div>
<div>
Components!
</div>
Typically, to make use of the context functionality, you will want to pass one or more of these properties to the Context
or DataContext
components.
Making a context will attach the it to the context tree, with the context containing it becoming the parent. Events will be bubbled up this tree, and configuration will be passed down from this tree.
To avoid this, mark it with the root
flag. This Context will become the root of its own tree.
<Context root >
Contents
</Context>
<DataContext root >
Contents
</DataContext>
The context can be passed in as context
- or by the name of the component: Context
and DataContext
respectively, for special reasons which will not be justified here.
Though not required, the most basic context would only define its own type.
const context = {
type: 'my-label-type',
}
<Context context={context} >
Contents
</Context>
/* OR */
<DataContext context={context} >
Contents
</DataContext>
You can provide the acts
property, which will define which actions are possible for this type.
const context = {
type: 'my-label-type',
acts: {
'some-action': {},
'another-action': {},
}
}
<Context context={context} >
Contents
</Context>
/* OR */
<DataContext context={context} >
Contents
</DataContext>
You can override acts
in parent contexts
const wrapperContext = {
overrides: {
'my-label-type': {
acts: {
'override-action': {}
}
}
}
}
const context = {
type: 'my-label-type',
acts: {
'some-action': {},
'another-action': {
disabled: () => Boolean(Math.round(Math.random()))
},
}
}
<DataContext context={wrappercontext} >
<Context context={context} >
Contents
</Context>
</DataContext>
Acts can have conditions configured, which will determine whether or not they are allowed to fire.
condition
property is false
, or returns false
on evaluation, the action will not exist on the context, and will not be triggerable. Any attempt to trigger this action will result in the UNHANDLED
Symbol.disabled
property is true
, or returns true
on evaluation, the action will exist, but will not trigger. Triggering this action will result in the HANDLED
symbol, preventing other contexts from intercepting the action, and will not trigger the handlers associated with the action.const context = {
type: 'my-label-type',
acts: {
'some-action': {
condition: ({ type, action, path, data, event }) =>
Boolean(Math.round(Math.random()))
},
'another-action': {
disabled: ({ type, action, path, data, event }) =>
Boolean(Math.round(Math.random()))
},
}
}
<Context context={context} >
Contents
</Context>
/* OR */
<DataContext context={context} >
Contents
</DataContext>
const context = {
type: 'my-label-type',
acts: {
'some-action': {
keys: ['Click']
},
'another-action': {},
},
}
<Context context={context} >
Contents
</Context>
You can also override keys
in parent contexts
const wrapperContext = {
overrides: {
'my-label-type': {
acts: {
'some-action': {
keys: ['Click','Enter']
}
}
}
}
}
const context = {
type: 'my-label-type',
acts: {
'some-action': {
keys: ['Ctrl+L']
},
'another-action': {},
},
menu: [
{
action: 'some-action',
label: 'Trigger Some Action',
},
{
action: 'another-action',
label: 'Do Another Action',
}
],
}
<DataContext context={wrappercontext} >
<Context context={context} >
Contents
</Context>
</DataContext>
You can provide the menu
property, which will define the display of the context menu.
const context = {
type: 'my-label-type',
acts: {
'some-action': {},
'another-action': {},
},
menu: [
{
action: 'some-action',
label: 'Trigger Some Action',
},
{
action: 'another-action',
label: 'Do Another Action',
}
]
}
<Context context={context} >
Contents
</Context>
You can override menu
in parent contexts
const wrapperContext = {
overrides: {
'my-label-type': {
menu: [
{
action: 'override-action',
label: 'Overriding Menu Item'
}
]
}
}
}
const context = {
type: 'my-label-type',
acts: {
'some-action': {},
'another-action': {},
},
menu: [
{
action: 'some-action',
label: 'Trigger Some Action',
},
{
action: 'another-action',
label: 'Do Another Action',
}
]
}
<DataContext context={wrappercontext} >
<Context context={context} >
Contents
</Context>
</DataContext>
Menu items can be grouped by using the "section" mode, and providing children
const context = {
type: 'my-label-type',
acts: {
'some-action': {},
'another-action': {},
},
menu: [
{
action: 'some-action',
label: 'Trigger Some Action',
},
{
label: 'Action List',
mode: 'section',
children: [
{
action: 'another-action',
label: 'Do Another Action',
}
]
}
]
}
<Context context={context} >
Contents
</Context>
Menus can be nested by using the "branch" mode, and providing children
const context = {
type: 'my-label-type',
acts: {
'some-action': {},
'another-action': {},
},
menu: [
{
action: 'some-action',
label: 'Trigger Some Action',
},
{
label: 'Additional Actions...',
mode: 'branch',
children: [
{
action: 'another-action',
label: 'Do Another Action',
}
]
}
]
}
<Context context={context} >
Contents
</Context>
Data an be provided to a context, which will become the data available on the action object. This is where you can provide contextual data that will be used when handling the action.
The data should be a normal object with string keys, it may be single-level merged with other data under this assumption. The types of values associated with those keys will not affect the system.
<Context data={{
MyContext_info: 'something-important',
}} >
Contents
</Context>
Using a data-only context is an obvious use-case for a DataContext
component, this example also removes the burden of the sub-component holding the key
metadata.
The data given here can later be used to identify the source component's model.
<Component>
{someList.map(({ label, key }) => (
<DataContext
key={key}
data={{
MyContext_info: 'something-important',
MyContext_key: key,
}} >
<SubComponent name={label} />
</DataContext>
))}
</Component>
The data can also be provided by a generator function, this can also be used for custom merging strategies if the default merging strategy is not desired. The generator will not be evaluated until an action is triggered.
<Context data={({ action, type, path, event }, currentData) => ({
...currentData,
Existing_key: undefined,
MyContext_info: 'something-important',
})} >
Contents
</Context>
An intercept
property can be provided to the context in order to catch and handle actions bubbling up from child components.
const subComponentContext = {
type: 'sub-component',
acts: {
'some-action': {
keys: ['Click','Enter']
}
},
}
const SubComponent = ({ name }) => (
<Context context={subComponentContext}>
{name}
</Context>
)
const parentIntercept = {
'sub-component.some-action': ({ type, path, action, data, event }) => {
console.log(data)
/*
{
MyContext_info: 'something-important',
MyContext_key: key,
}
*/
}
}
<DataContext intercept={parentIntercept} >
{someList.map(({ label, key }) => (
<DataContext
key={key}
data={{
MyContext_info: 'something-important',
MyContext_key: key,
}} >
<SubComponent name={label} />
</DataContext>
))}
</DataContext>
Intercepts can also be defined as other actions, triggering them from the intercepting context.
const subComponentContext = {
type: 'sub-component',
acts: {
'some-action': {
keys: ['Click','Enter']
}
},
}
const SubComponent = ({ name }) => (
<Context context={subComponentContext}>
{name}
</Context>
)
const parentContext = {
type: 'parent-component',
acts: {
'parent-action': {}
},
}
const parentIntercept = {
'sub-component.some-action': 'parent-action'
}
<Context context={parentContext} intercept={parentIntercept} >
{someList.map(({ label, key }) => (
<DataContext
key={key}
data={{
MyContext_info: 'something-important',
MyContext_key: key,
}} >
<SubComponent name={label} />
</DataContext>
))}
</Context>
Using the outercept
property will be effectively the same as the intercept
property, except that action priorities will "bubble down". Everything else should behave as if the action has "bubbled up", but the order in which actions are caught will start at the root ancestor and work down (the opposite of intercept
), allowing you to completely override descendant behaviour from any ancestor context.
Outercepts will always be prioritised over intercepts unless the outercepts go unhandled.
const subComponentContext = {
type: 'sub-component',
acts: {
'some-action': {
keys: ['Click','Enter']
}
},
}
const subComponentIntercept = {
'sub-component.some-action': ({ type, path, action, data, event }) => {
// Handles it's own action?
}
}
const SubComponent = ({ name }) => (
<Context context={subComponentContext} intercept={subComponentIntercept} >
{name}
</Context>
)
const parentOutercept = {
'sub-component.some-action': ({ type, path, action, data, event }) => {
// Action is overriden by ancestor!
// Descendant handler will never call
}
}
<DataContext outercept={parentOutercept} >
{someList.map(({ label, key }) => (
<DataContext
key={key}
data={{
MyContext_info: 'something-important',
MyContext_key: key,
}} >
<SubComponent name={label} />
</DataContext>
))}
</DataContext>
outercept
feature is overpowered, ripe for contraversy, and may one day be removedThe following properties should only be passed to the Context
component, as they all imply the existence of an element the context is associated with.
This is not true for the DataContext
component, which should only (but always) be used when there is no associated element.
element
The component that is rendered can be customised using the element
property.
<Context element="button" >
Button Label
</Context>
Results in:
<button class="Context-Focus" tabindex="0" data-contextid="42" >
Button Label
</button>
You can also use existing React components, passing down any properties in the same way as attributes.
<Context element={ReactComponent} property="Component Property" >
Component Contents
</Context>
Results in:
<ReactComponent className="Context-Focus" property="Component Property" tabindex="0" data-contextid="42" >
Component Contents
</ReactComponent>
focus
You can make the element unfocussable by switching off the focus
property, which is true
by default.
<Context focus={false} >
Contents
</Context>
Results in:
<div data-contextid="42" >
Contents
</div>
tabIndex
You can customise the focus order of elements by passing in the tabIndex
property, this will be 0
by default.
<Context tabIndex={3} >
Contents
</Context>
Results in:
<div tabindex="3" data-contextid="42" >
Contents
</div>
This feature is redundant, and not recomended. You should configure mouse events to trigger actions by configuring context keys in the same way as keyboard "buttons". Valid mouse "keys" are Click
, DoubleClick
, Button1
, Button2
, Button3
, Button4
, Button5
.
These properties can be used to bind actions directly to the rendered element events. When the event occurs, the action will be triggered.
onChangeAction
onClickAction
onDoubleClickAction
onMouseDownAction
onMouseUpAction
onMouseMoveAction
The action can be defined as:
onDoubleClickAction="action-name"
onClickAction={({ data, type, path, event }) => 'action-name'}
condition
property and action
property, which may itself be a string or a function.
onMouseDownAction={{
condition: someVar > 7,
action: 'action-name'
}}
onMouseDownAction={{
condition: ({ data, type, path, event }) =>
Boolean(event.target.closest('.target-element')),
action: ({ data, type, path, event }) =>
'action-name'
}}
Properties that will be intercepted, and not passed through to the rendered component:
root
focus
element
Context/context
data
intercept
outercept
onClickAction
onDoubleClickAction
onMouseDownAction
onMouseUpAction
onMouseMoveAction
Properties that may be modfied before passing them through to the rendered component:
tabIndex
onFocus
className
ref
Properties that will be overridden, even if they are passed through to the rendered component:
apiRef
data-contextid
onContextMenu (if the Context is focussable)
onClick (if onClickAction is provided)
onDoubleClick (if onDoubleClickAction is provided)
onMouseMove (if onMouseMoveAction is provided)
onMouseDown (if onMouseDownAction is provided)
onMouseUp (if onMouseUpAction is provided)
These keys, "buttons" or "symbols" will be available for configuring the keys
property of a context
, and can all be used in combination with each other to define key combinations that trigger actions.
Click
DoubleClick
Button1 (left mouse button)
Button2 (middle mouse button, press scroll button)
Button3 (right mouse button)
Button4 (uncommon; scrolling up/down or browser back/forth)
Button5 (uncommon; scrolling up/down or browser back/forth)
These symbols will not depend on positional key information e.g. CtrlLeft/CtrlRight
Ctrl
Shift
CapsLock
Meta (windows key, or command on mac)
Alt (option on mac)
Enter
Space
Tab
Delete
Backspace
ArrowLeft
ArrowRight
ArrowUp
ArrowDown
IntlBackslash (unadvised: the position, appearance, and expected behaviour of this key are not predictable between keyboards)
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
1 2 3 4 5 6 7 8 9 0
- = [ ] ; ' \ ` , . /
+ *
FAQs
React context menu system
We found that @oversword/context demonstrated a healthy version release cadence and project activity because the last version was released less than 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
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.