Hyperscript
Hyperscript Options (A and B)
Hyperscript is a new front-end scripting language with syntax patterned after the HyperTalk control language of HyperCard.
The syntax is English prose-like with emphasis on self-documenting code by using familiar phraseology.
HS emphasizes Locality of Behavior (LoB) to keep functionality at the site of intent. LoB also emphasizes understanding the action of code simply by inspection, reducing the cryptic nature of programming logic, improving understanding and code maintenance.
Hyperscript presents some unique features as well as possiblities which are worthy of a brief summary. The official docs are the best place to explort HS in depth, but a review of some of the important topics here will help the facilitate understanding of the example Components in this library.
Hyperscript allows different options for embedding script code into an Astro component, as detailed below.
To assist the library user a brief naming convention is put forward which provide a hint as to which embedding style is being used in that particular example.
Style A: Examples with names ending in _A utilize attribute embedded Hyperscript code
Style B: Examples ending with _B utilize behaviors to embed Hyperscript code
For educational purposes, some examples in this libary are offered in both embedding styles. Whether the A style or B style of Hyperscript embedding is used, the code functions identically.
Below is an explanation of all the options for embedding Hyperscript into your Astro components.
Embedding Hyperscript
There are several ways to embed HS code into your client side markup.
1. As a script="" or data-script="" attribute of any html element
<div script="on click send 'Hello' to me"> Click me to say Hello</div>
<div data-script="on click send 'World' to the next <output/>"> Click me to say Hello</div><output></output>2. Using the shorthand _=" attribute
<div _="on click send 'Hello' to me"> Click me to say Hello</div>3. Traditional <script> tag anywhere within your markup
You must include the type="text/hyperscript" attribute in your <script> tag to tell the browser to interpret the content as Hyperscript.
<script type="text/hyperscript"> on click send 'Hello' to me</script>4. Importing HS code from an external ._hs file.
In Astro projects, these files should be placed in your /public folder and the <script> import placed into the <head> tag of your main layout.
<script src="/assets/scripts/my-hyperscript-file._hs"></script>Using Behaviors
Behaviors are one strengths of Hyperscript. Behaviors allow you to encapsulate functionality in one place that can be used in many other places.
Behaviors are declared with the Behavior keyword. Parameters can be passed into Behaviors.
Behavior Removable on click remove me end endAfter defining a Behavior in a globally accessible HS, you can apply the Behavior to any html element using the install BehaviorName syntax as in:
<div install="Removable"> Click here to use the Behavior </div>The hyperComponents library will use of all the above embedding styles for HS code. Not all code examples will use Behaviors.
In some situations, the same hyperComponent will be presented differently using Behaviors, <script> tags, or script="" attributes.
The shortcut attribute _=" is the most common technique for embedding element level Hyperscipts.
However, the hyperComponents library is principally for instructional purposes so it is the author’s preference to use the more descriptive script="" attribute to explicitly indicate that an element has HS code attached.
Events
The DNA of HS is event management. All actions invoked by HS are in response to an event triggered by an on eventName phrase. Available event modifiers which determine handling of multiple events are:
- on
everyeventName - on eventName
queue all - on eventName
queue first - on eventName
queue last
In addition, an optional event filter allows you to restrict how/when an event is fired, as in:
<div script="on event[key='Escape'] ..."><div script="on mousedown(button==1) ...">The square bracket syntax evaluates an expression which is used to filter the event.
By default an event.detail object is provided to each handler, from which you can destructure the individual properties using parentheses.
You can send custom events to other DOM elements using either send or trigger syntax, as in:
<div script="on thisEvent trigger anotherEvent on the <div.eventTarget/>"><div script="on thisEvent send anotherEvent to the <div.eventTarget/>">Declaring Functions
The def keyword is used to declare a function in HS no matter what embedding strategy you choose. You can pass parameters to any function.
<script> def sayHello(name) send 'Hello ' + name to me end</script>Operator Precedence (not!)
Unlike most programming languages where a defined precedence is established for mathematical operators, Hyperscript expects the programmer to explicitly define the order of operations using parentheses (). This avoids some side-effects typical of other languages where the precedence is baked in and sometimes leads to unexpected results.
Async Transparency
Many commands, including Hyperscripts fetch() command are implemented asynchronously behind the scenes. Hyperscript handles Promise resolution and error management for you. You can expect a Promise to be resolved before the next HS code line is executed, as would be for the async/await syntax in vanilla JS.
You can explicitly designate a function as asynchronous with the async keyword but any system or server side Promise based methods are still resolved before HS proceeds with the next code line.
Using Objects
You can set up key:value
pairs in Hyperscript using the {key:"value"} syntax. You can access properties of an object in HS with -translate-x-6
- x.key
- x[‘key’]
- the key of x
- x’s key
Null Safety
IF you access an object or property the result is null (ie does not throw an error)
Logical Operators
In addition to the standard comparison operators, natural language comparisons are available, such as:
- is less | greater | than
- is equal | not equal to
- exists | matches | is empty
- and | or | not
To test if an element possesses a certain CSS selector, use the matches operator, as in:
Calling Functions
Use the syntax call someFunction() to invoke a either a HS defined function or a native JavaScript function. For example call me.setFocus() invokes the JavaScript function setFocus() on the current element.
Using the js keyword in an event handler creates a command that executes JavaScript, including passing parameters and returning results. The end keyword terminates the block.
To embed JS code into a <script type=text/hyperscript> top level block, there are some additional precautiosn using the end keyword which you can review here.
HS also provides the pseudo-command syntax where you can invoke a function call as a noun instead of a verb, for instance
get the customFunction() then put it into my innerHTMLDOM traversal
In HS, you do not call getElementById, querySelectorAll, etc. Instead you take advtange of a shorthand syntax called DOM literals which are strings (or expressions that yield a string) wrapped with special characters to tell HS you want to access one or more DOM elements. Behind the scenes HS invokes the standard queries for you. You can get or set any value accesed by a DOM literal syntax.
Expressions inside of curly braces are evaluated to yield a string which is then uses as the literal value for DOM access.
.classNameor.{expression}refers to an element by a class name#idor#{'someIdString'}refers to an element by its identifier<selector/>returns an array of all elements matching the specified CSS selector@attributeNamerefers to an element with the specified attribute and/or value*propertyNameget or set a style property of an element
With CSS selectors, HS returns all elements that match, so you will receive an array of elements.
You can traverse the DOM with the additional keywords:
closestclosest element matching a CSS selector you providenearestparentbegins searching at the parent of the current elementnextscans forward from current element looking for specified CSS Selectorpreviousscans backward from current element looking for a specified cSS Selectorfirstthe initial elementlastthe final elementrandomany random elementinlooks inside of the specified elementfrombegins a forward search where you specify, with the current element as defaultwithinrestricted subset of the DOM in which to search (default is the entire document)with wrappingallows the search to wrap around
Special Keywords
HS provides syntax which helps for descriptive senctence structure which is familiar in English sentence structure, such as…
me,my, orIrepresents the current element of an event handlerit,its, orresultrepresents the return value of the last commandeventrepresents the triggering eventbodyrepresents the body of the documenttargetrepresents the target of the current eventdetailcontains meta-data properties for the invoked eventsenderrepresents the element initiating the current eventthe,thenare interpreted as white space and are used for coding sugar.endterminites a code block but is optional if nothing follows anyway.
Arrays
Standard array syntax and access via index works with a few caveats. HS will loop most arrays for you if possible so you don’t need to explicitly call for. The example below loops all .bar elements and adds a .foo class to each.
<div script="on click add .foo to .bar"></div>When a property is an array-like composition, HS will flat-map the results into a single linear array, as in:
set allDivs to <div/> -- returns an array of a div elementsset divChildren to the children of allDivs -- retrieves all children, walking each div elementVariables
Variables are created set or put and accessed with get
YOU can scope variables with the local element or global keyword preceeding the variable name. Also, using a colon prefix is a shorthand for an element scoped variable which remains valid as long as the element is in the DOM. The $ prefix defines a globally scoped variable.