upsiflu / less-ui

Write your views across several screen regions, and hide all Ui state in the Url.
https://package.elm-lang.org/packages/upsiflu/less-ui/latest
BSD 3-Clause "New" or "Revised" License
6 stars 1 forks source link

Non-`href` Links #28

Closed upsiflu closed 1 year ago

upsiflu commented 1 year ago

Motivation

Some state transition patterns cannot be implemented with only the href attribute (which circumvents the message loop):

Functionality Event Url transition History? Link type Preview
Toggle a flag or bounce between paths - href
- Hotkey
From current state
when in same tab;
From initial state to "active" when in new tab
Link.Toggle, Link.Bounce image
Open a link - href
- Hotkey
From current state pushState Link.GoTo
Share the current state (Url) href Set the state pushState Link.Share
Tab, Sequence, and ViewModeRadio navigation -
- Hotkey
Replace all category= values Link.Assign
Search term input input Replace all q=category= search terms Protected Link.Filter
Viewport manipulation Follow Selection? Assignment Protected Link.Assign
Hover-state / Preload mouseOver Assignment Protected Link.Assign
Drag&Drop .. .. Protected Link.Assign

Since a restricted application has no access to the Url, we need to provide a lever, for example extending the Link type to construct these patterns.

Discussion

Perhaps this will make the whole library too complex. All these things can be implemented inside the app if we can do without altering the Url. Storing this state in the Url only has three advantages:

Antipatterns When does the Url state lose its utility?

Patterns

Implementation approaches

(a) The layout module (in our case, Html) maps any user-provided Html msg to an Html (Msg msg) (b) The Ui consists of a mix of html and htmlWithMsg.

Which one is better?

Api difference: In (a), singleton is in the Html module, next to the Wrapper and link functions and the Ui type alias. You'd only import Ui if you want at. In (b), singleton is in Ui besides at. So you'd have to import both modules. Another difference is that in (a), you could theoretically add Msg to your Html yourself.

Code niceness: In (a), we have ugly types in the Html module but nice types in Ui. In (b), we get additional type parameters for the already quite overloaded layout.

Problem with b: As we wrap the Uis, we are renderingUi htmltohtmlWithMsg`. Then, we need to wrap that. Let's see.

Nest
        { regions : List region
        , narrowLayout : Layout region narrowHtml narrowHtml narrowWrapper narrowWrapper
        , combine : { makeInnerHtml : Ui region narrowHtml narrowWrapper -> Maybe narrowHtml } -> html
        }

becomes

Nest
        { regions : List region
        , narrowLayout : Layout region narrowHtml narrowHtml narrowWrapper narrowWrapper
        , combine : { makeInnerHtml : Ui region narrowHtml narrowWrapper -> Maybe narrowHtmlWithMsg } -> htmlWithMsg
        }

so we have multiplied the html types from 2 to 4 👎 which means Ui.Wrapper needs 2 additional type parameters which means Ui.Layout also needs those, and now has 7 instead of 5. This was why we didn't implement (a).

upsiflu commented 1 year ago

Closing with 1c8fb7c

upsiflu commented 1 year ago

Reopening with