Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/morph.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Tests - morph

on:
push:
branches: [ main ]
paths:
- 'src/morph/**'
- '.github/workflows/morph.yml'
pull_request:
branches: [ main ]
paths:
- 'src/morph/**'
- '.github/workflows/morph.yml'
workflow_dispatch:

jobs:
test_suite:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
- run: npm ci
working-directory: ./src/morph
- run: npm test
working-directory: ./src/morph
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ As we were adding more extensions, this also meant more support to provide, with
As we worked on htmx 2, we decided to move the extensions to a separate repository, to clearly split apart the core library from its extensions and simplify their maintenance.\
We decided to keep the already existing extensions in, that we will keep providing support for.\
As we are a small team, we hope you'll understand that we can't do that with all extensions!\
This is why, you will find most core extensions sources in this repository (except [idiomorph](https://github.com/bigskysoftware/idiomorph) which has its own), and *some* of the community extensions along. That's htmx 1's legacy!
This is why, you will find most core extensions sources in this repository, and *some* of the community extensions along. That's htmx 1's legacy!

## Have a cool extension to suggest?
Feel free to create any extension to fit your project and needs! This system was designed with this goal in mind.\
Expand Down
1 change: 1 addition & 0 deletions src/morph/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/test
14 changes: 14 additions & 0 deletions src/morph/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
BSD Zero Clause License

Copyright (c) 2023, Alexander Petros

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55 changes: 55 additions & 0 deletions src/morph/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
This extension allows you to use [Idiomorph](https://github.com/bigskysoftware/idiomorph) as the swapping mechanism in htmx.

Idiomorph is not bundled with this extension; load it alongside.

## Install

```html
<script src="https://unpkg.com/htmx-ext-morph@2.0.0/morph.js"></script>
```

### Usage

```html
<header>
<script src="https://unpkg.com/htmx.org@2"></script>
<script src="https://unpkg.com/idiomorph@0.7.4"></script>
<script src="https://unpkg.com/htmx-ext-morph@2.0.0/morph.js"></script>
</header>

<body>
<div hx-ext="morph">
<button hx-get="/example" hx-swap="morph:innerHTML">
Morph My Inner HTML
</button>

<button hx-get="/example" hx-swap="morph:outerHTML">
Morph My Outer HTML
</button>

<button hx-get="/example" hx-swap="morph">
Morph My Outer HTML
</button>
</div>
</body>
```

## Configuring

This extension supports three different syntaxes for specifying behavior:

* `hx-swap='morph'` - This will perform a morph on the outerHTML of the target
* `hx-swap='morph:outerHTML'` - This will perform a morph on the outerHTML of the target (explicit)
* `hx-swap='morph:innerHTML'` - This will perform a morph on the innerHTML of the target (i.e. the children)
* `hx-swap='morph:<expr>'` - In this form, `<expr>` can be any valid JavaScript expression. The results of the expression
will be passed into the `Idiomorph.morph()` method as the configuration.

The last form gives you access to all the configuration options of Idiomorph. So, for example, if you wanted to ignore the input value in a given morph, you could use the following swap specification:

```html
<button hx-get="/example"
hx-swap="morph:{ignoreActiveValue:true}"
hx-target="closest form">
Morph The Closest Form But Ignore The Active Input Value
</button>
```
24 changes: 24 additions & 0 deletions src/morph/morph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(function() {
function createMorphConfig(swapStyle) {
if (swapStyle === 'morph' || swapStyle === 'morph:outerHTML') {
return { morphStyle: 'outerHTML' }
} else if (swapStyle === 'morph:innerHTML') {
return { morphStyle: 'innerHTML' }
} else if (swapStyle.startsWith('morph:')) {
return Function('return (' + swapStyle.slice(6) + ')')()
}
}

htmx.defineExtension('morph', {
isInlineSwap: function(swapStyle) {
let config = createMorphConfig(swapStyle)
return config?.morphStyle === 'outerHTML' || config?.morphStyle == null
},
handleSwap: function(swapStyle, target, fragment) {
let config = createMorphConfig(swapStyle)
if (config) {
return Idiomorph.morph(target, fragment.children, config)
}
}
})
})()
Loading