Surface - A component-based library for Phoenix LiveView

Hi @zimt28!

It will be possible to use stateless components in dead views as soon we have a the next LV version released. You can follow Use new `component/3` macro for stateless components · Issue #400 · surface-ui/surface · GitHub for updates.

4 Likes

Wow, I’ll definitely be checking this out this weekend!!! Well done and I wish you continued success with the project. :pray:t5::+1:t5:

I was looking into Surface recently and I noticed some interesting behavior on the website and I’m wondering if this is potentially a bug with Surface or LV since Surface itself is used for the page.

If you go-to the Surface docs, there are links in the sidebar. If you click between links in the sidebar you transition between pages as expected.

But, if you click between any 2 links (I can repeat this 100% of the time) reasonably quickly then the page never transitions and you wind up staying on the current page you’re on.

It doesn’t even need to be really fast clicking too. Even if you wait ~200ms it happens. I believe this is standard behavior on most sites (even non-LV sites) because if you click faster than the network request I guess the browser knows to not bother transitioning pages but I normally don’t notice this on non-LV sites, but it happened through regular usage twice normally clicking around the Surface site so maybe there’s an extra delay or something happening that’s unattended. I’m not sure but I thought I’d report it.

If you want me to record a video let me know. It’s reproduceable in every major browser on Windows.

What do you mean by “between links”? I am not reproducing this in Vivaldi on Windows.

  1. Glance at the “Documentation” sidebar
  2. Click the “Data” link
  3. Now click the “Events” link very quickly before the data page has a chance to load
  4. Repeat this click pattern

I can very quickly get into a loop of clicks where each click cancels the previous one out and you never move to the next page. My unscientific gut tells me it has a tolerance of about 200-250ms too, meaning if you click this fast or faster it gets cancelled out but the network latency I have to the server is 40ms based on seeing that reported as the response time in Chrome’s dev tools.

What I see is clicking “Data” then “Events” loads the Events page without any flicker of the Data page showing up. Are you saying that the Events page never loads for you? Maybe I don’t click fast enough.

It never loads if you click fast enough, but it happened twice just using the site normally because I went to click somewhere when in reality I really wanted to go somewhere else so I quickly clicked the other link. But the takeaway is it’s repeatable and seems to have a much “worse” latency tolerance than a non-LV / non-Surface site for not registering clicks.

Could it be the topbar that the surface site is using? I always find the extra latency from the javascript topbar is a disservice to LiveView.

It could be, I notice in general sites that use that bar or similar bars always feel like they are super delayed between making the click and seeing the transition.

@msaraiva Thanks for a great library. Assuming, one has a familiarity with LiveView component - how does one start thinking in Surface? Is it a one-to-one mapping between LiveView Components and Surface Components? Or does the approach to solution is different in both cases?

Hi @cvkmohan!

Under the hood, since Surface is built on top of LiveView, it will always be a one-to-one mapping.

From the design perspective, however, I believe there are differences. The main one is that, since Surface provides a higher level declarative approach that standardizes the way you define components, it fosters splitting the view into more fine-grained components that will have a more predictable and safer way to compose with other components, especially through the use of slots.

In my experience, users tend to avoid creating components when they don’t have a standard way to declare their public interface (properties, exposed events, slots, etc.). They know it might be a pain to maintain or simply reuse a component in the future when they don’t remember exactly how it behaves or interacts with other components.

To remove or at least mitigate that hesitation, it’s imperative to provide a declarative API with at least a minimal set of compile-time checks that can give the user confidence to take a step further and start thinking about the whole view as a tree of reusable components instead of a set of opaque pieces of templates.

I’m confident LiveView will move in that direction too. When that happen (if that happen), the model will become more similar, consequently, the way we design components will also get closer or even the same.

3 Likes

Thanks @msaraiva for the detailed answer. In line with some of my thoughts. Once libraries like GitHub - surface-ui/surface_bootstrap and surface-ui/surface_tailwind · GitHub mature - probably both developer experience and productivity will reach the top of the ladder. Exciting times to be a Web Application Developer.

2 Likes

Might be a long shot, but did anyone manage to convert the VSCode syntax highlighting definition Marlus created to something that Sublime Text can read? Been trying a few automatic converters and they all fail.

@cschmatzler feel free to open an issue at Issues · msaraiva/vscode-surface · GitHub and provide more information about the errors you get when running those converters. Maybe it’s something we can fix at the grammar level.

After using Surface for a little bit I’m still wondering why the syntax

prop name, :string

was chosen over

prop :name, :string

It feels quite “unnatural”, is there a technical reason?

1 Like

When passing prop name to a component or dom node it is name="value" not :name="value" since props are =~ html attributes, it makes sense imo.

and attributes/props like :if have special meaning in the context of surface.

3 Likes

Possible, I just think that it looks very unfamiliar :slight_smile:

Another question, I’ve built a table component as described here and it’s working well, but I cannot find a way to combine this with dynamic columns:

<Table data={resource <- @resources}>
  {#for col <- table_columns()}
    <Column label={col.label}>
      {Map.get(resource, col.attribute)}
    </Column>
  {/for}
</Table>

It’s telling me that
a) The default slot wasn’t defined, when I define one it tells me that
b) resource is undefined

I’m not sure what I’m missing here :man_shrugging:

Hi @zimt28!

Defining props in Surface is as common as defining functions. You already define functions as:

def name, do: ...

So it shouldn’t be so unfamiliar :wink:

Unfortunately, you can’t assign slots dynamically. The problem is that LV doesn’t have support for slots yet so in order to make it work, we need to know upfront how many blocks are being passed at compile-time to generate the proper case clauses in the component’s body. This is a limitation that can only be solved when Phoenix adds built-in support for slots, which is already on the roadmap.

6 Likes

@msaraiva Question: Does surface 0.5.2 work out of box with LiveView 0.16?

No. We’ll release a new v0.6 after Phoenix v1.6 is released. In the meantime, if you want to try Surface with LV 0.16, you need to use the Surface version on master.

2 Likes