mirror of
https://github.com/bigskysoftware/hypermedia-systems.git
synced 2025-12-15 00:05:07 -05:00
reply to some editing feedback
This commit is contained in:
parent
4892fe180b
commit
4861df6fe5
@ -41,6 +41,7 @@ Thus, developers are naturally led into a SPA-like pattern for developing mobile
|
||||
- The frontend on the mobile device, runs code to create and update the UI
|
||||
- The backend is an API, called by the frontend
|
||||
|
||||
TODO: think about list formatting?
|
||||
Just like with SPAs on the web, this architecture has a big downside: the app's logic gets spread across the frontend and backend.
|
||||
Sometimes, logic needs to be duplicated (like to validate form data).
|
||||
Other times, the frontend and backend each implement one part of the app's overall logic.
|
||||
@ -61,7 +62,7 @@ The answer is yes!
|
||||
Just like on the web, we can use Hypermedia formats on mobile and let it serve as the engine of application state.
|
||||
All of the logic is controlled from the backend, rather than being spread between two codebases.
|
||||
Hypermedia architecture also solves the annoying problem of API churn on mobile apps.
|
||||
Since the backend servs a Hypermedia response containing both data and actions, there's no way for the data and UI to get out of sync.
|
||||
Since the backend serves a Hypermedia response containing both data and actions, there's no way for the data and UI to get out of sync.
|
||||
No more worries about backwards compatibility or maintaining multiple API versions.
|
||||
|
||||
So how can you use Hypermedia for your mobile app?
|
||||
@ -106,14 +107,6 @@ We wanted to avoid using the typical SPA architecture of native mobile app devel
|
||||
The web view allows us to use good-old hypermedia-based HTML.
|
||||
But to get the desired look & feel of a mobile app, we end up building a SPA in JS, losing the benefits of Hypermedia in the process.
|
||||
|
||||
Many mobile apps on iOS and Android are implemented as web views, and they work perfectly fine.
|
||||
If you already have a responsive web app, perhaps wrapping it in a Web view and distributing it through app stores is an easy proposition.
|
||||
But I tend to believe: "let the web be the web, and let mobile be mobile".
|
||||
Your responsive web app already works perfectly fine when accessed through Mobile Chrome or Mobile Safari.
|
||||
Progressive web app support has come a long way on iOS and Android.
|
||||
Users can "install" your web app to their home screen, and launch it with a single tap.
|
||||
Does your web app need to be in the app store too?
|
||||
|
||||
To build a hypermedia-based mobile app that feels and acts native, HTML isn't going to cut it.
|
||||
We need a format designed to represent the interactions and patterns of native mobile apps.
|
||||
That's exactly what Hyperview does.
|
||||
@ -131,9 +124,12 @@ Hyperview is an open-source framework that provides:
|
||||
HXML was designed to feel familiar to web developers, used to working with HTML.
|
||||
Thus the choice of XML for the base format.
|
||||
In addition to familiar ergonomics, XML is compatible with server-side rendering libraries.
|
||||
For example, Jinja2 is perfectly suited as a templating library to render HXML, as we'll see in the next chapter.
|
||||
For example, Jinja2 is perfectly suited as a templating library to render HXML.
|
||||
The familiarity of XML and the ease of integration on the backend make it simple to adopt in both new and existing codebases.
|
||||
Take a look at a "Hello World" app written in HXML.
|
||||
The syntax should be familiar to anyone who's worked with HTML:
|
||||
|
||||
.Hello World
|
||||
[source,xml]
|
||||
----
|
||||
<doc xmlns="https://hyperview.org/hyperview">
|
||||
@ -151,15 +147,15 @@ The familiarity of XML and the ease of integration on the backend make it simple
|
||||
</doc>
|
||||
----
|
||||
|
||||
htmx fill in the "missing parts of HTML" to enable rich web app experiences.
|
||||
If HTML was designed today, I believe the ideas of htmx would be part of the standrd spec, and natively supported by every browser without the need for a 3rd party JS library.
|
||||
Well, HXML was designed today!
|
||||
The HXML format has built-in support for htmx-like interactions.
|
||||
But HXML is not just a straight port of HTML with differently named tags.
|
||||
In previous chapters, we've seen how htmx enhances HTML with a handful of new attributes.
|
||||
These additions maintain the declaritive nature of HTML, while giving developers the power to create rich web apps.
|
||||
In HXML, the concepts of htmx (and IntercoolerJS before it) are built into the spec.
|
||||
Specifically, HXML is not limited to "click to navigate" and "press to submit" interactions like basic HTML.
|
||||
It supports a range of triggers and actions for modifying the content on a screen.
|
||||
These interactions are bundled together in a powerful concept of "behaviors".
|
||||
Developers can even define new behavior actions to add new capabilities to their app, without the need for scripting.
|
||||
We will learn more about behaviors in later sections of this chapter.
|
||||
We will learn more about behaviors later in this chapter.
|
||||
|
||||
==== The client
|
||||
Web developers are lucky.
|
||||
@ -186,6 +182,9 @@ That's why Hyperview provides an open-source client library, written in React Na
|
||||
This library can be used to bootstrap a new mobile app, or it can be embedded in an existing app.
|
||||
In either case, developers get a full "HXML browser" without needing to write it from scratch.
|
||||
|
||||
|
||||
.The Benefits of Maintaining Your Own Client
|
||||
----
|
||||
At first, it might seem like the Hyperview approach requires extra work to write and maintain the mobile app client.
|
||||
But there is a benefit when the developer controls both the server and client.
|
||||
Did you ever wish you could fix a web browser bug?
|
||||
@ -206,6 +205,8 @@ There are extension points for custom UI elements and custom behaviors.
|
||||
By extending the format and client itself, there's no need for Hyperview to include a scripting layer in HTMX.
|
||||
Features that require client-side logic get "built-in" to the client browser.
|
||||
HTMX responses remain pure, with UI and interactions represented in declarative XML.
|
||||
----
|
||||
|
||||
|
||||
=== Which Hypermedia architecture should I use?
|
||||
|
||||
@ -241,6 +242,7 @@ Then, we'll re-build our contacts app in Hyperview.
|
||||
HXML was designed to feel natural to web developers coming from HTML.
|
||||
Let's take a closer look at the "Hello World" app defined in HXML:
|
||||
|
||||
.Hello World, revisited
|
||||
[source,xml]
|
||||
----
|
||||
<doc xmlns="https://hyperview.org/hyperview"> <1>
|
||||
@ -265,7 +267,6 @@ Let's take a closer look at the "Hello World" app defined in HXML:
|
||||
<6> The text content shown on the screen
|
||||
|
||||
Nothing too strange here, right?
|
||||
The base syntax should be immediately familiar.
|
||||
Just like HTML, the syntax defines a tree of elements using start tags (`<screen>`) and end tags (`</screen>`).
|
||||
Elements can contain other elements (`<view>`) or text (`Hello World!`).
|
||||
Elements can also be empty, represented with an empty tag (`<styles />`).
|
||||
@ -321,6 +322,7 @@ The physical properties of a phone screen (long & vertical) and the intuitive ge
|
||||
|
||||
HXML has dedicated elements for representing lists and items.
|
||||
|
||||
.List element
|
||||
[source,xml]
|
||||
----
|
||||
<list> <1>
|
||||
@ -357,38 +359,40 @@ These APIs know which part of the list is currently on-screen. To save memory, t
|
||||
By using explicit `<list>` and `<item>` elements in HXML, the Hyperview client knows to use these optimized list APIs to make your app more performant.
|
||||
|
||||
It's also worth mentioning that HXML supports section lists.
|
||||
Section lists are useful for building screens like a list of contacts, where contacts are alphabetized and grouped in a section by their starting letter.
|
||||
Section lists are useful for building list-based UIs, where the items in the list can be grouped for the user's convenience.
|
||||
For example, a UI showing a restaurant menu could group the offerings by dish type:
|
||||
|
||||
.Section list element
|
||||
[source,xml]
|
||||
----
|
||||
<section-list> <1>
|
||||
<section> <2>
|
||||
<section-title> <3>
|
||||
<text>A</text>
|
||||
<text>Appetizers</text>
|
||||
</section-title>
|
||||
<item key="1"> <4>
|
||||
<text>Aaron</text>
|
||||
<text>French Fries</text>
|
||||
</item>
|
||||
<item key="2">
|
||||
<text>Adam</text>
|
||||
<text>Onion Rings</text>
|
||||
</item>
|
||||
</section>
|
||||
|
||||
<section> <5>
|
||||
<section-title>
|
||||
<text>B</text>
|
||||
<text>Entrees</text>
|
||||
</section-title>
|
||||
<item key="3">
|
||||
<text>Bart</text>
|
||||
<text>Burger</text>
|
||||
</item>
|
||||
</section>
|
||||
</section-list>
|
||||
----
|
||||
<1> Element representing a list with sections
|
||||
<2> The first section of contacts with names that begin with the letter "A"
|
||||
<3> Element for the title of the section, rendering text of the letter "A"
|
||||
<4> An item representing a contact that belongs to this section.
|
||||
<5> A section for contacts with names that begin with "B".
|
||||
<2> The first section of appetizer offerings
|
||||
<3> Element for the title of the section, rendering the text "Appetizers"
|
||||
<4> An item representing an appetizer
|
||||
<5> A section for entree offerings
|
||||
|
||||
You'll notice a couple of differences between `<list>` and `<section-list>`.
|
||||
The section list element only contains `<section>` elements, representing a group of items.
|
||||
@ -400,6 +404,7 @@ Finally, `<item>` elements act the same as in the regular list, but can only app
|
||||
|
||||
Showing images in Hyperview is pretty similar to HTML, but there are a few differences.
|
||||
|
||||
.Image element
|
||||
[source,xml]
|
||||
----
|
||||
<image source="/profiles/1.jpg" style="avatar" />
|
||||
@ -411,6 +416,7 @@ Additionally, the source can be an encoded data URI, for example `data:image/png
|
||||
However, the source can also be a "local" URL, refering to an image that is bundled as an asset in the mobile app.
|
||||
The local URL is prefixed with `./`:
|
||||
|
||||
.Image element, pointing to local source
|
||||
[source,xml]
|
||||
----
|
||||
<image source="./logo.png" style="logo" />
|
||||
@ -435,6 +441,7 @@ There's a lot to cover about inputs in Hyperview.
|
||||
Since this is meant to be an introduction and not an exhaustive resource, I'll highlight just a few types of inputs.
|
||||
Let's start with an example of the simplest type of input, a text field.
|
||||
|
||||
.Text field element
|
||||
[source,xml]
|
||||
----
|
||||
<text-field
|
||||
@ -464,6 +471,7 @@ Also, unlike radio buttons on desktop, mobile OSes don't provide a strong standa
|
||||
Most mobile apps use richer, custom UIs for these interactions.
|
||||
So in HXML, we implement this UI using an element called `<select-single>`:
|
||||
|
||||
.Select-single element
|
||||
[source,xml]
|
||||
----
|
||||
<select-single name="choice"> <1>
|
||||
@ -512,6 +520,7 @@ So far, we haven't mentioned how to apply styling to all of the HXML elements.
|
||||
We've seen from the Hello World app that each `<screen>` can contain a `<styles>` element.
|
||||
Let's re-visit the Hello World app and fill out the `<styles>` element.
|
||||
|
||||
.UI styling example
|
||||
[source,xml]
|
||||
----
|
||||
<doc xmlns="https://hyperview.org/hyperview">
|
||||
@ -573,6 +582,7 @@ Let's translate these requirements into XML:
|
||||
|
||||
Using these custom XML elements, an instance of the map in our app might look like this:
|
||||
|
||||
.Custom elements in HXML
|
||||
[source,xml]
|
||||
----
|
||||
<doc xmlns="https://hyperview.org/hyperview">
|
||||
@ -611,6 +621,7 @@ This namespace could be anything, but remember the goal is to use something uniq
|
||||
Using your company/app domain is a good way to guarantee uniqueness.
|
||||
Now that we have a namespace and prefix, we need to use it for our elements:
|
||||
|
||||
.Namespacing the custom elements
|
||||
[source,xml]
|
||||
----
|
||||
<doc xmlns="https://hyperview.org/hyperview" xmlns:map="https://mycompany.com/hyperview-map"> <1>
|
||||
@ -635,7 +646,7 @@ That's it! If we introduced a custom charting library with "area" and "marker" e
|
||||
|
||||
At this point you might be wondering, "how does the Hyperview client know to render a map when my doc includes `<map:area>`"?
|
||||
It's true, so far we only defined the custom element format, but we haven't implemented the element as a feature in our app.
|
||||
We will get into the details of implementing custom elements later in the next chapter.
|
||||
We will get into the details of implementing custom elements in the next chapter.
|
||||
|
||||
|
||||
=== Behaviors
|
||||
@ -668,6 +679,7 @@ We call these interactions "behaviors".
|
||||
We use a special `<behavior>` element to define then.
|
||||
Here's an example of a simple behavior that pushes a new mobile screen onto the navigation stack:
|
||||
|
||||
.Basic behavior
|
||||
[source,xml]
|
||||
----
|
||||
<text>
|
||||
@ -709,6 +721,7 @@ It would be nice to have a simpler syntax for the common case.
|
||||
Luckily, `trigger` and `action` attributes have default values of `press` and `push`, respectively.
|
||||
Therefore, they can be ommitted to clean up the syntax:
|
||||
|
||||
.Basic behavior with defaults
|
||||
[source,xml]
|
||||
----
|
||||
<text>
|
||||
@ -741,6 +754,7 @@ Behavior actions in Hyperview fall into 3 general categories:
|
||||
- Navigation actions, which load new screens and move between them
|
||||
- Update actions, which modify the HXML of the current screen
|
||||
- System actions, which interact with with OS-level capabilities.
|
||||
- Custom actions, which can execute any code you add to the client.
|
||||
|
||||
===== Navigation Actions
|
||||
We've already seen the simplest type of action, `push`.
|
||||
@ -765,6 +779,7 @@ However, if you want to replace the screen with a different one, you can provide
|
||||
|
||||
Let's look at an example that uses several navigation actions on one screen:
|
||||
|
||||
.Navigation action examples
|
||||
[source,xml]
|
||||
----
|
||||
<screen>
|
||||
@ -797,6 +812,8 @@ Let's look at an example that uses several navigation actions on one screen:
|
||||
<3> Reloads the content of the screen, showing new widgets from the backend
|
||||
<4> Pushes a new screen with details for a specific widget
|
||||
|
||||
TODO: wrap-up nav actions section to make a smoother transition
|
||||
|
||||
===== Update Actions
|
||||
|
||||
Behavior actions are not just limited to navigating between screens.
|
||||
@ -819,6 +836,7 @@ Hyperview supports the current update actions, representing different ways to in
|
||||
Let's look at some examples to make this more concrete.
|
||||
For these examples, let's assume our backend accepts `GET` requests to `/fragment`, and the response is a fragment of HXML that looks like `<text>My fragment</text>`.
|
||||
|
||||
.Update action examples
|
||||
[source,xml]
|
||||
----
|
||||
<screen>
|
||||
@ -883,6 +901,7 @@ Instead, the fragment will be added either after (in the case of `append`) or be
|
||||
|
||||
For completeness, let's look at the state of the screen after a user presses all four buttons:
|
||||
|
||||
.Update actions, after pressing buttons
|
||||
[source,xml]
|
||||
----
|
||||
<screen>
|
||||
@ -940,6 +959,7 @@ The most common state to change for an element is its visibility.
|
||||
Hyperview has `hide`, `show`, and `toggle` actions that do just that.
|
||||
Like the other update actions, `hide`, `show`, and `toggle` use the `target` attribute to apply the action to an element on the current screen.
|
||||
|
||||
.Show, hide, and toggle actions
|
||||
[source,xml]
|
||||
----
|
||||
<screen>
|
||||
@ -990,6 +1010,7 @@ This UI allows sharing URLs and messages from one app to another app.
|
||||
Hyperview has a `share` action to support this interaction.
|
||||
It involves a custom namespace, and share-specific attributes.
|
||||
|
||||
.System Share action
|
||||
[source,xml]
|
||||
----
|
||||
<behavior
|
||||
@ -1021,6 +1042,7 @@ This dialog needs configuration for a title and message, but also for customized
|
||||
Each button needs to then trigger another behavior when pressed.
|
||||
This level of configuration cannot be done with just attributes, so we use custom child elements to represent the behavior of each button.
|
||||
|
||||
.System alert action
|
||||
[source,xml]
|
||||
----
|
||||
<behavior
|
||||
@ -1069,13 +1091,14 @@ In the next chapter, we will create a custom behavior action to enhance our mobi
|
||||
|
||||
We've already seen the simplest type of trigger, a `press` on an element. Hyperview supports many other common triggers used in mobile apps.
|
||||
|
||||
===== `longPress`
|
||||
===== longPress
|
||||
Closely related to a press is a long-press.
|
||||
A behavior with `trigger="longPress"` will trigger when the user presses and holds on the element.
|
||||
"Long-press" interactions are often used for shortcuts and power features.
|
||||
Sometimes, elements will support different actions for both a `press` and `longPress`.
|
||||
This is done using multiple `<behavior>` elements on the same UI element.
|
||||
|
||||
.Long-press trigger example
|
||||
[source,xml]
|
||||
----
|
||||
<text>
|
||||
@ -1093,11 +1116,12 @@ This is a contrived example for the sake of brevity.
|
||||
A better UX would be for the long-press to bring up a contextual menu of shortcuts and advanced options.
|
||||
This could be achieved by using `action="alert"` and opening a system dialog box with the shortcuts.
|
||||
|
||||
===== `load`
|
||||
===== load
|
||||
Sometimes we want an action to trigger as soon as the screen loads.
|
||||
`trigger="load"` does exactly this.
|
||||
One use case is to quickly load a shell of the screen, and then fill in the main content on the screen with a second update action.
|
||||
|
||||
.Load trigger example
|
||||
[source,xml]
|
||||
----
|
||||
<body>
|
||||
@ -1120,18 +1144,19 @@ As soon as this screen loads, the behavior with `trigger="load"` fires off the `
|
||||
It requests content from the `/content` path and replaces the container view with the response.
|
||||
|
||||
|
||||
===== `visible`
|
||||
===== visible
|
||||
Unlike `load`, the `visible` trigger will only execute the behavior when the element with the behavior is scrolled into the viewport on the mobile device.
|
||||
This allows us to
|
||||
The `visible` action is commonly used to implement an infinite-scroll interaction on a `<list>` of `<item>` elements.
|
||||
The last item in the list includes a behavior with `trigger="visible"`.
|
||||
The `append` action will fetch the next page of items and append them to the list.
|
||||
|
||||
===== `refresh`
|
||||
===== refresh
|
||||
This trigger captures a "pull to refresh" action on `<list>` and `<view>` items.
|
||||
This interaction is associated with fetching up-to-date content from the backend.
|
||||
Thus, it's typically paired with an update or reload action to show the latest data on the screen.
|
||||
|
||||
.Pull-to-refresh trigger example
|
||||
[source,xml]
|
||||
----
|
||||
<body>
|
||||
@ -1162,6 +1187,11 @@ But there's no such limitation in Hyperview; elements can define multiple behavi
|
||||
We already saw an example where a single element had different actions triggered on `press` and `longPress`.
|
||||
But we can also trigger multiple actions on the same trigger.
|
||||
|
||||
In this admittedly contrived example, we want to hide 2 elements on the screen when pressing the "Hide" button.
|
||||
The two elements are far apart in the HXML, and cannot be hidden by hiding a common parent element.
|
||||
But, we can trigger two behaviors at the same time, each one executing a "hide" action but targeting different elements.
|
||||
|
||||
.Multiple behaviors triggering on press
|
||||
[source,xml]
|
||||
----
|
||||
<screen>
|
||||
@ -1181,20 +1211,12 @@ But we can also trigger multiple actions on the same trigger.
|
||||
<1> Hide element with ID "area1" when pressed
|
||||
<2> Hide element with ID "area2" when pressed
|
||||
|
||||
In this admittedly contrived example, we want to hide 2 elements on the screen when pressing the "Hide" button.
|
||||
The two elements are far apart in the HXML, and cannot be hidden by hiding a common parent element.
|
||||
But, we can trigger two behaviors at the same time, each one executing a "hide" action but targeting different elements.
|
||||
TODO: restate the solution shown above
|
||||
|
||||
|
||||
== Summary
|
||||
At the beginning of this chapter, I made a case for developing mobile apps using a Hypermedia architecture.
|
||||
I also explained why using HTML & web views is not the best approach to deliver a native-feeling mobile experience.
|
||||
Hyperview as a framework allow us to develop native mobile apps without giving up the Hypermedia architecture.
|
||||
Unlike HTML, HXML is a mobile-first format with first-class support for the interactions and patterns users expect on mobile.
|
||||
HXML has built-in rich Hypermedia functionality inspired by htmx and IntercoolerJS.
|
||||
However, HXML takes things a step further with the concept of behaviors and custom elements/actions.
|
||||
By controlling the Hyperview client, developers are free to extend HXML to suit their needs.
|
||||
All this can be done without writing and shipping scripts embedded in HXML.
|
||||
In fact, the concept of scripting doesn't exist in the format!
|
||||
This allows HXML to remain pure and declarative, while the client evolves new capabilites over time.
|
||||
|
||||
In the next chapter, we will put the ideas of Hyperview into action, by porting the Contacts App from a web app to a native mobile application.
|
||||
- HTML & web views are not the best approach to deliver a native-feeling mobile experience. But that doesn't mean the Hypermedia architecture is not a good fit for mobile apps.
|
||||
- Hyperview is a framework for building native mobile apps using the Hypermedia architecture. The Hyperview project provides an embeddable client, and a hypermedia format called HXML.
|
||||
- HXML makes it easy to define mobile app UIs using a declarative syntax that clearly expresses mobile UI patterns and interactions.
|
||||
- The extensibility in HXML and the Hyperview client make it easy for developers to define custom element and behaviors. Developers can evolve Hyperview to suit the requirements of their app, without giving up the benefits of a Hypermedia architecture.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user