All Projects → alpine-collective → Alpine Magic Helpers

alpine-collective / Alpine Magic Helpers

Licence: mit
A collection of magic properties and helper functions for use with Alpine.js

Programming Languages

javascript
184084 projects - #8 most used programming language

Labels

Projects that are alternatives of or similar to Alpine Magic Helpers

dababy
Data binding so simple even DaBaby could do it!
Stars: ✭ 27 (-93.54%)
Mutual labels:  alpine
alpine-vagrant
This builds an up-to-date Vagrant Alpine Linux Base Box
Stars: ✭ 22 (-94.74%)
Mutual labels:  alpine
Robox
The tools needed to robotically create/configure/provision a large number of operating systems, for a variety of hypervisors, using packer.
Stars: ✭ 303 (-27.51%)
Mutual labels:  alpine
docker-webtop
Ubuntu, Alpine, Arch, and Fedora based Webtop images, Linux in a web browser supporting popular desktop environments.
Stars: ✭ 498 (+19.14%)
Mutual labels:  alpine
addon-base-python
Docker Python base images (Alpine) - Home Assistant Community Add-ons
Stars: ✭ 12 (-97.13%)
Mutual labels:  alpine
docker-alpine-miniconda3
The smallest Docker image with Miniconda3 (Python 3.7) (~143MB)
Stars: ✭ 94 (-77.51%)
Mutual labels:  alpine
rails5-docker-alpine
Lightweight Docker development environment for Rails using Alpine Linux
Stars: ✭ 71 (-83.01%)
Mutual labels:  alpine
Dockerfiles
Discontinued. Fork at your will.
Stars: ✭ 384 (-8.13%)
Mutual labels:  alpine
docker4ruby
Docker-based Ruby stack (works for Rails)
Stars: ✭ 27 (-93.54%)
Mutual labels:  alpine
Endoflife.date
Informative site with EoL dates of everything
Stars: ✭ 296 (-29.19%)
Mutual labels:  alpine
openssl-alpine
OpenSSL three tier certificate generator
Stars: ✭ 23 (-94.5%)
Mutual labels:  alpine
docker-lemonldap
Docker LemonLDAP-NG Image w/S6 overlay, Zabbix Monitoring based on Debian or Alpine
Stars: ✭ 20 (-95.22%)
Mutual labels:  alpine
docker-laravel-appengine
Laravel dockerized with official Google App Engine flexible php environment + swoole.
Stars: ✭ 66 (-84.21%)
Mutual labels:  alpine
hypercorn-fastapi-docker
Docker image with Hypercorn for FastAPI apps in Python 3.7, 3.8, 3.9. Ready for HTTP2 and HTTPS
Stars: ✭ 18 (-95.69%)
Mutual labels:  alpine
Meinheld Gunicorn Flask Docker
Docker image with Meinheld and Gunicorn for Flask applications in Python. Optionally with Alpine Linux.
Stars: ✭ 336 (-19.62%)
Mutual labels:  alpine
php7-alpine
Docker container for PHP 7 in Alpine Linux, with almost all extensions that you may need
Stars: ✭ 20 (-95.22%)
Mutual labels:  alpine
ob php-fpm
PHP-FPM container for NGINX using Alpine, Opcache, Dynamic Resources, Monitoring, Security
Stars: ✭ 89 (-78.71%)
Mutual labels:  alpine
Php Alpine
PHP APK Repository for Alpine Linux
Stars: ✭ 385 (-7.89%)
Mutual labels:  alpine
Gluetun
VPN client in a thin Docker container for multiple VPN providers, written in Go, and using OpenVPN, DNS over TLS, with a few proxy servers built-in.
Stars: ✭ 346 (-17.22%)
Mutual labels:  alpine
hadoop-docker-lite
Docker build project to setup a lightweight hadoop cluster containing hadoop, pig, zookeeper, hbase, phoenix, storm, kafka, kafka manager
Stars: ✭ 24 (-94.26%)
Mutual labels:  alpine

Magic Helpers

A collection of magic properties and helper functions for use with Alpine.js

GitHub tag (latest by date)

About

Adds the following magic helpers to use with Alpine JS. | Magic Helpers | Description | | --- | --- | | $component/$parent | Natively access and update data from other components or the parent component. | | $fetch | Using Axios, fetch JSON from an external source. | | $interval | Run a function every n milliseconds. Optionally start and stop the timer. | | $range | Iterate over a range of values. | | $refresh | Manually refresh a component. | | $screen | Detect if the current browser width is equal or greater than a given breakpoint. | | $scroll | Scroll the page vertically to a specific position. | | $truncate | Limit a text string to a specific number of characters or words. | | $undo | Track and undo state changes inside your component. |

Adds the following custom directives to use with Alpine JS. | Custom Directives | Description | | --- | --- | | x-unsafe-html | like x-html but allowing new javascript scripts to run. |

More to come!

🚀 If you have ideas for more magic helpers or custom directives, please open a discussion or join us on the AlpineJS Discord

Known issues

Installation

Include the following <script> tag in the <head> of your document (before Alpine):

<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/index.min.js"></script>

Or you can use the specific magic helpers you need:

<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/component.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/fetch.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/interval.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/range.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/refresh.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/screen.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/scroll.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/truncate.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/undo.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/alpine-collective/[email protected]/dist/unsafeHTML.min.js"></script>

Manual

If you wish to create your own bundle:

npm install alpine-magic-helpers --save

Then add the following to your script:

import 'alpine-magic-helpers'
import 'alpinejs'

Or you can import the specific magic helpers you need like so:

import 'alpine-magic-helpers/dist/component'
import 'alpine-magic-helpers/dist/fetch'
import 'alpinejs'

$component

Example:

Arguably more useful, this also adds a $parent magic helper to access parent data

<div x-data="{ color: 'blue' }">
    <p x-data x-text="$parent.color"></p>
    <!-- The text will say blue -->
</div>

Demo

You may watch other components, but you must give them each an id using the 'id' attribute or x-id if you need more flexibility:

<div x-data="{ color: 'blue' }">
    <p
        x-data
        x-text="$component('yellowSquare').color"
        :class="`text-${$parent.color}-700`">
        <!-- This text will have blue background color and the text will say yellow -->
    </p>
</div>

<div x-id="yellowSquare" x-data="{ color: 'yellow' }"></div>

⚠️ Using $component/$parent in x-init

 <!-- This won't populate baz correctly -->
 <div x-data="{ foo: 'bar' }">
   <div x-data="{ baz: null }" x-init="() => baz = $parent.foo">
     <span x-text='baz'></span>
   </div>
 </div>
 <!-- use this instead -->
 <div x-data="{ foo: 'bar' }">
   <div x-data="{ baz: null }" x-init="$nextTick(() => baz = $parent.foo)">
     <span x-text='baz'></span>
   </div>
 </div>
 <!-- or -->
 <div x-data="{ foo: 'bar' }">
   <div x-data="{ baz: null }" x-init="setTimeout(() => baz = $parent.foo)">
     <span x-text='baz'></span>
   </div>
 </div>

When a component is initialised, the observed component may not be ready yet due to the way Alpine starts up. This is always true for $parent and it occurs for $component when the observer is placed before the observed component in the page structure. Previous versions were using a hack to evaluate the missing x-data on the fly but that strategy wasn't allowing to use nested magic properties and it was not syncronising properly in some edge cases. The magic helper since version 1.0 defers the resolution of those properties (resolving temporary to empty strings/noop functions) until the observed component is ready and then refreshes the component: this happens in a few milliseconds and it's not noticable by the final users but refreshing a component won't rerun x-init with the correct values. If developers need to use the magic property inside x-init, they'll need to manually postpone the execution of x-init for one tick either using the Alpine native $nextTick or a setTimeout with no duration (See examples above).


$fetch

Example:

<div x-data="{ url: 'https://jsonplaceholder.typicode.com/todos/1' }"
    x-init="$fetch(url).then(data => console.log(data))">
    <!-- After init, data will be logged to the console -->
</div>

Demo

Optionally pass in an options object

By default, $fetch will return the JSON data object. However, because we are using Axios behind the scenes, you may pass in an object to customize the request See all options.

Example:

<div x-data="{ url: 'https://jsonplaceholder.typicode.com/todos/1' }"
    x-init="$fetch({ url: url, method: 'post' }).then(({ data }) => console.log(data))">
</div>

Note that this will return the entire response object, whereas by default $fetch will only return the data


$interval

Example:

<div
    x-data="{
        timer: 500,
        functionToRun: function() {
            console.log('Hello console')
        }
    }"
    x-init="$interval(functionToRun, timer)">
</div>

Demo

Optionally pass in options

By default, $interval will run your function every nth millisecond when browser provides an animation frame (via requestAnimationFrame). This means that the function will not run if the browser tab is not visible. Optionally, you may pass in the following options as the second parameter: | Property | Description | | --- | --- | | timer | Timer in milliseconds. | | delay | Delay the first run. N.B. The first run is also delayed by the timer time. | | forceInterval | Ignore the browser animation request mechanism. Default is false |

⚠️ We also add a hidden property autoIntervalTest that will clear/stop the timer if set to false, and start the timer if then set to true.

Example:

<div
    x-data="{
        timer: 500,
        autoIntervalTest: true, // optional to start/stop the timer
        funtionToRun: function() {
            console.log('Hi again!')
        }
    }"
    x-init="$interval(funtionToRun, { timer: 1000, delay: 5000, forceInterval: true })">
    <button
        @click="autoIntervalTest = !autoIntervalTest"
        x-text="autoIntervalTest ? 'pause' : 'play'"></button>
</div>

Demo


$range

Example:

The $range helper mostly mimics implementations found in other languages $range(start, stop, step = 1)

<div x-data>
    <template x-for="item in $range(1, 5)">
        ...
    </template>
</div>
<!-- This will output 5 iterations [1, 2, 3, 4, 5], modelled after PHP's implimentation of range() -->

Demo

N.B: You may use $range(10) which will compute to [1...10]


$refresh

Example:

<div x-data>
    <button @click="$refresh()">Refresh <code>Date.now()</code></button>
    <span x-text="Date.now()"></span>
</div>

Demo


$screen

Example:

The $screen helper detects if the current browser width is equal or greater than a given breakpoint and returns true or false based on the result.

<div x-data>
    <span x-show="$screen('lg')">This will be visible if the window width is equal or greater than 1024px.</span>
</div>

By default the $screen helper uses the following endpoint borrowed by Tailwind CSS:

  • xs: 0px
  • sm: 640px
  • md: 768px
  • lg: 1024px
  • xl: 1280px
  • 2xl: 1536px

⚠️ NOTE: A single breakpoint is only going to tell you if the browser width is equal or greater than the given breakpoint. If you want to restrict the check to a specific range, you will need to negate the next endpoint as:

<div x-data>
    <span x-show="$screen('md') && !$screen('lg')">This will be visible if screen width is equal or greater than 768px but smaller then 1024px.</span>
</div>

Custom breakpoints

You can pass a numeric value to use an ad-hoc breakpoint.

<div x-data>
    <span x-show="$screen(999)">This will be visible if screen width is equal or greater than 999px.</span>
</div>

You can also override the default breakpoints including the following <script> tag in the <head> of your document

<!-- this example uses Bulma's breakpoints. -->
<script>
    window.AlpineMagicHelpersConfig = {
        breakpoints: {
            mobile: 0,
            tablet: 769,
            desktop: 1024,
            widescreen: 1216,
            fullhd: 1408
        }
    }
</script>

And using those breakpoints in your page.

<div x-data>
    <span x-show="$screen('tablet')">This will be visible if screen width is equal or greater than 769px.</span>
</div>

Demo


$scroll

Example:

<div x-data>
    <div x-ref="foo">
        ...
    </div>
    <button x-on:click="$scroll($refs.foo)">Scroll to foo</scroll>
</div>

Demo

Alternatively, you can pass a css selector to scroll to an element at any position.

<div id="foo">
</div>
<div x-data>
    <button x-on:click="$scroll('#foo')">Scroll to #foo</scroll>
</div>

$scroll also supports integers to scroll to a specific point of the page.

<button x-data x-on:click="$scroll(0)">Scroll to top</scroll>

Demo (same as above)

$scroll optionally supports a second parameter where it's possible to define the behavior mode, auto|smooth (default smooth):

<div x-data>
    <div x-ref="foo">
        ...
    </div>
    <button x-on:click="$scroll($refs.foo, {behavior: auto})">Jump to foo</scroll>
</div>
...
<div id="foo">
</div>
<div x-data>
    <button x-on:click="$scroll('#foo, {behavior: auto}')">Jump to #foo</scroll>
</div>
...
<button x-data x-on:click="$scroll(0, {behavior: auto}">Jump to top</scroll>

With offset:

<div x-data>
    <div x-ref="foo">
        ...
    </div>
    <button x-on:click="$scroll($refs.foo, {offset: 50})">Scroll to 50px before foo</scroll>
</div>
...
<div id="foo">
</div>
<div x-data>
    <button x-on:click="$scroll('#foo, {offset: 50}')">Scroll to 50px before #foo</scroll>
</div>
...
<button x-data x-on:click="$scroll(0, {offset: 50}">Jump to 50px before top (a bit daft but supported)</scroll>

With both:

<div x-data>
    <div x-ref="foo">
        ...
    </div>
    <button x-on:click="$scroll($refs.foo, {behavior: auto, offset: 50})">Jump to 50px before foo</scroll>
</div>
...
<div id="foo">
</div>
<div x-data>
    <button x-on:click="$scroll('#foo, {behavior: auto, offset: 50}')">Jump to 50px before #foo</scroll>
</div>
...
<button x-data x-on:click="$scroll(0, {behavior: auto, offset: 50}">Jump to 50px before top</scroll>

Demo (same as above)


$truncate

Example:

<div
    x-data="{ characters: 50, string: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'}"
    x-text="$truncate(string, characters)"
    @click="characters = undefined">
    <!-- Text will show 'Lorem ipsum dolor sit amet, consectetur adipiscing…' and will reveal all when clicked-->
</div>

You may also pass a third argument to change the string that will be appended to the end:

<div
    x-data="{ characters: 50, string: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'}"
    x-text="$truncate(string, characters, ' (...)')">
    <!-- Text will show 'Lorem ipsum dolor sit amet, consectetur adipiscing (...)' -->
</div>

Demo

Optionally pass in options

By default, $truncate will return take characters as a parameter. Instead you can pass in an object and trim by words. You may also update the ellipsis.

Example:

<div
    x-data="{ count: 5, string: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'}"
    x-text="$truncate(string, { words: words, ellipsis: ' ...read more' })"
    @click="count = 0">
    <!-- Will start with 5 words, then increase to unlimited when clicked -->
</div>

Demo (same as above)

Behind the scenes, for words, this uses sentence.split(" ").splice(0, words).join(" ") which does not define a word in all languages.


$undo

Example:

<div x-data="{ number: 0 }" x-init="$track()">
    <button @click="number = Math.floor(Math.random() * 10)" x-text="number"></button>
    <button x-show="$history.length" @click="$undo()">undo</button>
</div>

Demo

The $undo helper actually involves three helpers in one. First, add the $track() helper to the x-init directive to start tracking the component state. Next, add a button to $undo() changes as needed. And finally, you can access whether changes have occurred by using $history.length.

Optionally pass in options

By default, $undo will track all properties. Optionally you may limit the properties by passing in a string with the property name, or an array of property names.

Example:

<div x-data="{ number: 0; another: 0 }" x-init="$track('number')">
    <button @click="number = number + 1" x-text="number"></button>
    <button @click="another = another + 1" x-text="another"></button>
    <button x-show="$history.length" @click="$undo()">undo number only</button>
</div>

Use $track(['prop1', 'prop2']) to track multiple properties

Demo


x-unsafe-html

Example:

<div x-data="{ foo: bar }">
    <div x-unsafe-html="foo"></div>
    <button @click="foo = '<p>bar</p><script>alert(1)</script>'">test</button>
</div>

⚠️ Only use on trusted content. ⚠️

Dynamically rendering HTML from third parties can easily lead to XSS vulnerabilities.

Demo


License

Copyright (c) 2020 Alpine Collective

Licensed under the MIT license, see LICENSE.md for details.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].