diff --git a/packages/resize/builds/cdn.js b/packages/resize/builds/cdn.js new file mode 100644 index 000000000..b8a3f5b76 --- /dev/null +++ b/packages/resize/builds/cdn.js @@ -0,0 +1,5 @@ +import resize from '../src/index.js' + +document.addEventListener('alpine:init', () => { + window.Alpine.plugin(resize) +}) diff --git a/packages/resize/builds/module.js b/packages/resize/builds/module.js new file mode 100644 index 000000000..fc370a076 --- /dev/null +++ b/packages/resize/builds/module.js @@ -0,0 +1,5 @@ +import resize from './../src/index.js' + +export default resize + +export { resize } diff --git a/packages/resize/package.json b/packages/resize/package.json new file mode 100644 index 000000000..f0dd6d313 --- /dev/null +++ b/packages/resize/package.json @@ -0,0 +1,17 @@ +{ + "name": "@alpinejs/resize", + "version": "3.14.1", + "description": "Trigger JavaScript when an element is resized on the page", + "homepage": "https://alpinejs.dev/plugins/intersect", + "repository": { + "type": "git", + "url": "https://github.com/alpinejs/alpine.git", + "directory": "packages/resize" + }, + "author": "Caleb Porzio", + "license": "MIT", + "main": "dist/module.cjs.js", + "module": "dist/module.esm.js", + "unpkg": "dist/cdn.min.js", + "dependencies": {} +} diff --git a/packages/resize/src/index.js b/packages/resize/src/index.js new file mode 100644 index 000000000..24d647595 --- /dev/null +++ b/packages/resize/src/index.js @@ -0,0 +1,59 @@ +export default function (Alpine) { + Alpine.directive('resize', Alpine.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { + let evaluator = evaluateLater(expression) + + let evaluate = (width, height) => { + evaluator(() => {}, { scope: { '$width': width, '$height': height }}) + } + + let off = modifiers.includes('document') + ? onDocumentResize(evaluate) + : onElResize(el, evaluate) + + cleanup(() => off()) + })) +} + +function onElResize(el, callback) { + let observer = new ResizeObserver((entries) => { + let [width, height] = dimensions(entries) + + callback(width, height) + }) + + observer.observe(el) + + return () => observer.disconnect() +} + +let documentResizeObserver +let documentResizeObserverCallbacks = new Set + +function onDocumentResize(callback) { + documentResizeObserverCallbacks.add(callback) + + if (! documentResizeObserver) { + documentResizeObserver = new ResizeObserver((entries) => { + let [width, height] = dimensions(entries) + + documentResizeObserverCallbacks.forEach(i => i(width, height)) + }) + + documentResizeObserver.observe(document.documentElement) + } + + return () => { + documentResizeObserverCallbacks.delete(callback) + } +} + +function dimensions(entries) { + let width, height + + for (let entry of entries) { + width = entry.borderBoxSize[0].inlineSize + height = entry.borderBoxSize[0].blockSize + } + + return [width, height] +} diff --git a/scripts/build.js b/scripts/build.js index e02d07733..c7421ab44 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -9,8 +9,9 @@ let zlib = require('zlib'); // 'history', - removed because this plugin has been moved to livewire/livewire until it's stable... // 'navigate', - remove because this plugin has been moved to livewire/livewire until it's stable... 'intersect', - 'persist', 'collapse', + 'persist', + 'resize', 'anchor', 'morph', 'focus', diff --git a/scripts/release.js b/scripts/release.js index a9624d1e0..a94624aaa 100644 --- a/scripts/release.js +++ b/scripts/release.js @@ -45,6 +45,9 @@ function writeNewAlpineVersion() { writeToPackageDotJson('intersect', 'version', version) console.log('Bumping @alpinejs/intersect package.json: '+version) + writeToPackageDotJson('resize', 'version', version) + console.log('Bumping @alpinejs/resize package.json: '+version) + writeToPackageDotJson('persist', 'version', version) console.log('Bumping @alpinejs/persist package.json: '+version) @@ -92,6 +95,9 @@ function publish() { console.log('Publishing @alpinejs/intersect on NPM...'); runFromPackage('intersect', 'npm publish --access public') + console.log('Publishing @alpinejs/resize on NPM...'); + runFromPackage('resize', 'npm publish --access public') + console.log('Publishing @alpinejs/persist on NPM...'); runFromPackage('persist', 'npm publish --access public') diff --git a/tests/cypress/integration/plugins/resize.spec.js b/tests/cypress/integration/plugins/resize.spec.js new file mode 100644 index 000000000..6004ef31b --- /dev/null +++ b/tests/cypress/integration/plugins/resize.spec.js @@ -0,0 +1,48 @@ +import { haveText, test, html, notHaveText } from '../../utils' + +test('can react to the resizing of an element', + [html` +
+

+

+ +
+
+ + + +
+ `], + ({ get }) => { + get('h1').should(haveText('100')) + get('h2').should(haveText('100')) + get('button#1').click() + get('h1').should(haveText('50')) + get('h2').should(haveText('100')) + get('button#2').click() + get('h1').should(haveText('50')) + get('h2').should(haveText('50')) + }, +) + +test('can react to the resizing of the document', + [html` +
+

+

+ +
+
+ `], + ({ get }) => { + get('h1').should(notHaveText('0')) + get('h2').should(notHaveText('0')) + get('h1').should(notHaveText('100')) + get('h2').should(notHaveText('100')) + + cy.viewport(550, 750) + + get('h1').should(haveText('550')) + get('h2').should(haveText('750')) + }, +) diff --git a/tests/cypress/spec.html b/tests/cypress/spec.html index 5c939f48d..c61eb2d8b 100644 --- a/tests/cypress/spec.html +++ b/tests/cypress/spec.html @@ -12,6 +12,7 @@ +