-
-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Halogen 5 #26
Halogen 5 #26
Conversation
src/Component/Router.purs
Outdated
render { route } = case route of | ||
Home -> | ||
HH.slot' CP.cp1 unit Home.component unit absurd | ||
HH.slot (SProxy :: _ "home") unit Home.component unit absurd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Halogen 4 we used a child path and slot type to identify a particular component among many. In Halogen 5 we use a symbol proxy and a slot type instead.
A symbol proxy is a type-level string. You've seen them before: they're used as labels for row types (and records and variants, which are built on top of rows). In this case we're identifying the component with the label home
in our ChildSlots
row defined at the top of this module.
I've written SProxy :: _ "home"
as a shorthand here, but the full type is SProxy :: SProxy "home"
. That means that at the value level we have just SProxy
, but this value has the type SProxy "home"
, which is how we're able to use the label "home" at the type level.
Unit | ||
Unit | ||
Unit | ||
type ChildSlots = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Halogen 5 we use a row type to describe child components, instead of the old nested either / coproduct pairing. It's quite a bit cleaner and allows you to easily give descriptive names to each component.
A child path used to be a pairing of a component's query type (what a parent can use to trigger behaviors in or request information from one of its child components) and slot type (a unique address when there are multiple components of the same type).
In Halogen 5, we instead have a dedicated Slot
type which uses the child component's query type, message type (what outputs are possible to handle from the component), and slot address.
For example:
-- this parent component has one child component type, labeled `component`, with the query
-- type `ComponentQuery`, outputs of type `ComponentMessage`, and we'll distinguish among
-- multiple copies of the component using an `Int` address.
type MyChildSlots =
( component :: H.Slot ComponentQuery ComponentMessage Int )
Our router deals with page components which raise no output messages and have no public query interface you can use to request information or manipulate them. They simply aren't necessary. So for each of our page components the slot type is just:
type ChildSlots =
( home :: H.Slot (Const Void) Void Unit )
In other words, H.Slot
expects a query type of kind Type -> Type
, a message type of kind Type
, and a slot address of kind Type
. When you need to provide a type but have no possible values that could satisfy the type, you can use Void
-- a type with no accompanying values. And when you need to provide something of kind Type -> Type
but have no possible values, you can use Const Void
. So when we have a component with no queries and no messages we can use Const Void
and Void
to represent that.
This is fairly common in our application, so I've defined a helper type in Component.Utils
for components with no queries or messages:
type OpaqueSlot = H.Slot (Const Void) Void
@@ -48,32 +48,31 @@ type State = | |||
type Input = | |||
{ slug :: Maybe Slug } | |||
|
|||
type ChildQuery m = F.Query Query TagInput.Query Unit EditorFields m | |||
type ChildSlots = | |||
( formless :: F.Slot EditorFields (Const Void) FormChildSlots Article Unit ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formless is the component that has undergone the greatest number of changes as part of the Halogen 5 transition. For the full details, see the Formless library. If you have written a form and you want to extend the form's state, query algebra, actions, messages, child components, or anything else, that information no longer leaks out to the parent component but instead is handled entirely within Formless. Accordingly, any extensions you want to make to the component will show up in its slot type.
The main thing that affects us here is that the Formless slot type now takes:
- Your form type being run in Formless (here,
EditorFields
) - Any queries you wish to extend the component with (here, none, represented with
Const Void
- Any child components the form will have (here,
FormChildSlots
, defined at the end of the module) - Any messages the component will output (here, we'll get an
Article
on successful submission) - The form slot address
( tagInput :: H.Slot (Const Void) TagInput.Message Unit ) | ||
|
||
data FormAction | ||
= HandleTagInput TagInput.Message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formless can now be extended with more actions as you see fit. Here, we'll extend the component with the ability to handle messages being output by the TagInput
component. Notice how the parent component, the Editor
page, doesn't have to care about the tag input anymore because it's encapsulated within the form component.
add bus subscriptions for global state
convert to spago
* Update Formless dependency to Jordan's "exposeInput" branch * Remove unneeded whitespace characters * Migrate Editor page to new Formless * Migrate Login page to new Formless * Migrate Register page to new Formless * Migrate Settings page to new Formless * Convert back to using Thomas' Halogen 5 PR as dependency
Due to the long delay on the Halogen 5 release, I'm leaning towards merging this into master this week. However, if any watchers of this repository have a reason why I shouldn't do this, please feel free to comment! |
I'd say just go ahead and merge it. I don't know when Gary will make the next release, even though it's quite useable as is. |
* Update code for purs 0.13, update halogen to rc5 * Remove override for remotedata as its in the snapshot now * Gitignore VSCode workspace files * Use hash symbol instead of its code
It makes sense to me to merge -- I wanted to use Halogen 5 and having this as an example was useful for understanding what was different. Maybe add a link to this PR in the README or even tag the repo before merging so that it's easy for ppl to see what it looked like at 4 vs. 5? |
That's a good idea -- I think a tag + a link in the readme would help make sure people on Halogen 4 and Halogen 5 are both able to get value from the repo. |
Closes #25 by updating the project for Halogen 5. This update avoids updating any functionality in favor of a simple, direct translation from Halogen 4 to Halogen 5. There was also a major update in the form library, Formless, which required updating most page components more extensively than might be usual for a migration like this.
For more information on what's changed in Halogen 5, please see the Changes in Halogen 5 documentation.
This was a fairly quick & pleasant transition, completed in about 2-3 hours in total.