This is a React component which provides a controlled editor for writing logical expressions like
(myVar == 3 || (myVar2 >= 4 && !myVar3)) && myVar4 != 6 && myVar5 == true
It provides:
- semantic highlighting and validation
- auto-completion
- custom styling
Autocomplete:
- it activates automatically when the user types a character
- it can be manually activated with tab even if no characters have been typed
- it can be manually deactivated with escape
- navigate the suggestions with arrow keys, accept with enter, and cancel with escape
Available operators:
| Operator | Description | Type |
|---|---|---|
== |
equal | Binary |
!= |
not equal | Binary |
> |
greater than | Binary |
< |
less than | Binary |
>= |
greater than or equal to | Binary |
<= |
less than or equal to | Binary |
&& |
and | Binary |
|| |
or | Binary |
! |
not | Unary |
+ |
addition | Binary |
- |
subtraction | Binary |
* |
multiplication | Binary |
/ |
division | Binary |
Install the package:
npm install @abidibo/react-expression-editor
Use it
import { ExpressionEditor, Operator } from '@abidibo/react-expression-editor'
// if you don't provide custom classes
import '@abidibo/react-expression-editor/dist/index.esm.css'
function App() {
const [expression, setExpression] = useState('')
const allowedVariables = ['myVar', 'myVar2', 'myVar3', 'myVar4']
// all allowed if empty or undefined
const allowedOperators = [Operator.AND, Operator.OR, Operator.NOT]
return (
<div>
<ExpressionEditor
value={expression}
onChange={setExpression}
variables={allowedVariables}
operators={allowedOperators}
constraintVariables
/>
</div>
)
}The component accepts the following props:
| Name | Type | Default Value | Description |
|---|---|---|---|
value |
string |
The expression (Required) | |
onChange |
function |
A function to call when the expression changes (Required) | |
variables |
string[] |
[] | An array of variable names that can be used in the expression |
operators |
Operator[] |
[] | An array of operators that can be used in the expression (all if empty) |
maxSuggestions |
number |
10 | The maximum number of suggestions to show |
constraintVariables |
boolean |
false | If true, the expression will be validated against the allowed variables |
showValidationText |
boolean |
false | If true, a validation message is always shown under the editor |
classes |
EditorClasses |
A set of classes to apply to the editor and other elements to customize the appearance | |
onValidationChange |
(validation: ValidationResult) => void |
A function to call when the validation changes |
enum Operator {
AND = '&&',
OR = '||',
NOT = '!',
GT = '>',
GTE = '>=',
LT = '<',
LTE = '<=',
EQ = '==',
NEQ = '!=',
PLUS = '+',
MINUS = '-',
MUL = '*',
DIV = '/',
}
type EditorClasses = {
root?: string // The outer wrapper
editor?: string // The contentEditable area
validation?: string // The validation error message
menu?: string // The autocomplete dropdown ul
menuItem?: string // The li items
menuItemActive?: string // The highlighted li item
// Token Highlighting slots
tokenVar?: string // Variables
tokenBinaryOp?: string // Binary operators (&&, ||)
tokenUnaryOp?: string // Unary operators (!)
tokenValue?: string // Numbers
tokenUnknown?: string // Errors
tokenError?: string // Errors
}
interface ValidationResult {
isValid: boolean
error: string | null
errorToken?: Token
errorTokenIndex?: number
errorCharPosition?: number
state?: MachineState
}
enum MachineState {
EXPECT_OPERAND = 'expect operand',
EXPECT_OPERATOR = 'expect operator',
}
interface Token {
type: TokenType
value: string
start: number
end: number
}
export enum TokenType {
VAR = 'variable',
VALUE = 'value',
UNARY_OP = 'unary operator',
BINARY_OP = 'binary operator',
OPEN_P = 'open parenthesis',
CLOSE_P = 'close parenthesis',
SPACE = 'space',
UNKNOWN = 'unknown',
}After cloning the repository and install dependencies (yarn install), you can run the following commands:
| Command | Description |
|---|---|
yarn clean |
Clean the dist folder |
yarn build |
Build the library |
yarn storybook |
Run storybook |
In order to start developing just run the storybook, then make changes to code and the storybook will be updated.