Grammar
As discussed previously, reSTYLE UI patterns are built around a concept of natural language. This natural language is converted into the grammar that describes the UI pattern.
For example, you might have a button
definition, as well as a variant like a small primary button
.
This is the basis for our grammar.
Parsing Grammar
reSTYLE has a built-in grammar engine that parses the natural language sentence in a grammar representation.
The first phase of grammar parsing is to understand what we’re talking about. This is known as the type
.
In our example of a small primary button
, we can determine that the thing we’re talking about is the button
. So we say the type
is button
.
The rest of the sentence is known as the description
. So in this case, our description
is small primary
.
The internal representation of this is:
{
type: "button",
description: ["small", "primary"]
}
Type
The type is determined as the first word that matches a UI definition identifier. So in this case, restyle-define(button, ...)
let’s us know that button
is a thing that we can talk about. The grammar engine doesn’t recognize small
or primary
as a valid type, but it recognizes button
, so we’ve determined our type to be a button
.
Description
The rest of the sentence is put into the description. The description then goes through a second phase of parsing.
Ignored words
The first thing we do on the description is to remove words that don’t have any real meaning. This list of words includes: a
, also
, an
, and
, is
, it
, or
, that
, the
, this
, was
These words are discarded from the description.
Contextual words
The next step is to parse all of the contextual cues within the sentence. Contextual cues include in
and within
. For example, button in a dialog
.
When a contextual cue is encountered, we rewrite the description to make sense.
For example, if we had a button in a large dialog
, we have to identify that large
applies to the dialog
rather than to the button
. This is a context shift.
in
vs within
When the in
contextual cue is used, it signifies that the element must be a direct descendent of the context. That is, button in a dialog
, the button
must be a direct descendant of dialog
.
However, the within
cue applies an any descendent. That is, button within a dialog
will be valid if any of the ancestors of button
are a dialog
.
Placement words
Finally, we handle a few words that change the placement or attribution. These words include: on
, with
, without
.
For example button with a shadow
.
Adding custom grammar engines
While the built-in grammar parser is quite robust, you may have a specific need to extend it. Here’s a quick example of doing just that (in your build pipeline):
var Eyeglass = require("eyeglass").Eyeglass;
var eyeglass = new Eyeglass({
restyle: {
// grammarEngines takes an array of functions
grammarEngines: [function() {
...
}]
}
});
The custom grammar engine function will have access to this.description
and this.type
. this.description
may either be null
or an array of strings while this.type
is a string. Any changes you make here should be applied back onto the properties.
Here’s an example of a custom grammar engine:
function() {
this.type = "my-prefix-" + this.type;
if (this.description) {
this.description = this.description.filter(...);
}
}
From an eyeglass module
If you’ve authored a reSTYLE eyeglass module but don’t have access to the build environment, you can still add grammar engines via the plugin interface. In your eyeglass-exports.js
file, you’d do something like…
module.exports = function(eyeglass, sass) {
eyeglass.options.restyle.addGrammarEngine(function() { ... });
};