Commit graph

21 commits

Author SHA1 Message Date
Mitchell Hanberg db231e7b6b
Align component model with HEEx/Surface (#182)
* Align component model with HEEx/Surface

This change aligns the component model with HEEx/Surface. This shoudl
allow one to interop components created in any syntax with any other
syntax.

The advantage of this is folks can utilize component packages created
using a different syntax.

This includes several enhancements and breaking changes, please see the changelog and the migration guide for further details.

Closes #130
2022-10-12 09:17:23 -04:00
Mitchell Hanberg 99cbb42962
SVG (#181)
This basically just adds svg elements as void and nonvoid element
aliases and it works, will test on a real proejct before releasing the
next release.

Also, fixed the weird behaviour problem by defining types for each of the ast
nodes and then referencing those types when defining the ast type.

Unclear why this works, but I imagine it has to do with the types not
being a big part of the compilation process or something.

This also uses the typed_struct library to do so. Seems pretty slick and
does what it claims it does.
2022-09-19 20:35:45 -04:00
Mitchell Hanberg f942817994
Utilize the EEx Engine instead of creating an EEx string (#177) 2022-04-19 23:56:46 -04:00
Mitchell Hanberg c965048f40
Better whitespace handling and control (#145)
* Fine tune whitespace

The EEx outut now emits more human-readable and predictable formatting.
This includes proper indenting, at least for each "root" template.

* Internal whitespace control

You can now use a bang version of any nonvoid tag to emit the markup
witout the internal whitespace. This means that there will not be a
newline emitted after the opening tag and before the closing tag.
2021-08-29 17:45:07 -04:00
Mitchell Hanberg 851f6415fe Slots!
Integration test for slots

Format integration test project

Hide slots assign in temple prefixed key

Won't compile temple related assigns when calling Utils.runtime_attrs

Update component docs with slots usage
2021-05-13 00:21:43 -04:00
Mitchell Hanberg 07a1d5d451 Rename ast properties to align with given ast
The properties were either not needed at all, or were named back when
there was only one node type. now that each node is it's own struct,
they really don't need to share any common properties.
2021-04-10 11:08:06 -04:00
Mitchell Hanberg fe3aed5df7 Some cleanup 2021-04-09 00:16:30 -04:00
Mitchell Hanberg b35b9b6d91 Rename a dir and shrink the test matrix 2021-04-09 00:16:30 -04:00
Mitchell Hanberg 41f9b94d0f Hook the AST generation in to the temple macros
- Removes the old way
- Removes the ability to compact an element
2021-04-09 00:16:30 -04:00
Mitchell Hanberg 4e9c7e95b4 Generate AST 2021-04-09 00:16:30 -04:00
Mitchell Hanberg 358b5ea4cc Start porting parsers to use AST 2021-04-09 00:16:30 -04:00
Mitchell Hanberg ced2f6ab66 feat: New Component API 2021-01-02 13:22:03 -05:00
Mitchell Hanberg 5c5edfa67f case expressions 2020-11-04 19:58:35 -05:00
Mitchell Hanberg 265c413960 Allow element attrs to be evaluated at runtime
Before this change, only keyword list literals could be passed to
elements. If they had non-literals as values, then those would compile
to EEx expressions.

This allows a non-literal to be passed as attrs and have the entire thing
compile to an EEx expression, which will pass the non-literal to a
"runtime_attrs" function, which evaluates a keyword list into a safe
string.

That last part might need to be reworked if the user is not using
the Phoenix.HTML.Engine EEx Engine.
2020-08-09 10:07:27 -04:00
Mitchell Hanberg d4b81d60de Account for the third arg of AST being an atom 2020-07-24 21:27:53 -04:00
Mitchell Hanberg 59e64dce3b Parser abstraction
This implements a Temple.Parser behavior. This contracts requires a
`applicable/1` and `run/2` functions to be defined.

`applicable/1` is passed the unparsed AST, and returns true or false
as to whether this parser module should be run.

`run/2` is passed the unparsed AST as well as the buffer. It should add
parsed markup to the buffer.

The function either returns `:ok` if the AST is done, or
`{:component_applied, ast}`. If the latter is returned, the parser pass
starts over with the return ast.
2020-07-23 20:59:10 -04:00
Mitchell Hanberg 7bf649c4b5 Correctly parse do blocks
Did not correctly parse expressions with do blocks
where the expression had two or more arguments before
the block.
2020-07-22 21:34:50 -04:00
Mitchell Hanberg f5ad95642a Only split args when list is a keyword list 2020-07-16 00:19:57 -04:00
Mitchell Hanberg 1f599f5f6d Handle expressions with do blocks that aren't if/unless/for 2020-07-15 23:23:12 -04:00
Mitchell Hanberg 1a5837d1b7 Components API
Components work very similarly to how they worked before, but with a few
differences.

To define a component, you can create a file in your configured temple
components directory, which defaults to `lib/components`. You would
probably want ot change that to be `lib/my_app_web/components` if you
are building a phoenix app.

This file should be of the `.exs` extension, and contain any temple
compatible code.

You can then use this component in any other temple template.

For example, if I were to define a `flex` component, I would create a
file called `lib/my_app_web/components/flex.exs`, with the following
contents.

```elixir
div class: "flex #{@temple[:class]}", id: @id do
  @children
end
```

And we could use the component like so

```elixir
flex class: "justify-between items-center", id: "arnold" do
  div do: "Hi"
  div do: "I'm"
  div do: "Arnold"
  div do: "Schwarzenegger"
end
```

We've demonstated several features to components in this example.

We can pass assigns to our component, and access them just like we would
in a normal phoenix template. If they don't match up with any assigns we
passed to our component, they will be rendered as-is, and will become a
normal Phoenix assign.

You can also access a special `@temple` assign. This allows you do
optionally pass an assign, and not have the `@my_assign` pass through.
If you didn't pass it to your component, it will evaluate to nil.

The block passed to your component can be accessed as `@children`. This
allows your components to wrap a body of markup from the call site.

In order for components to trigger a recompile when they are changed,
you can call `use Temple.Recompiler` in your `lib/my_app_web.ex` file,
in the `view`, `live_view`, and `live_component` functions

```elixir
def view do
  quote do
    # ...
    use Temple.Recompiler
    # ...
  end
end
```
2020-07-15 22:32:27 -04:00
Mitchell Hanberg f8f1ec623f Plugin architecture for parsers 2020-07-15 22:32:27 -04:00