forked from wagtail/wagtail
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate autosize jQuery to stimulus controller w-autosize
- Closes wagtail#10170
- Loading branch information
1 parent
cc23aa6
commit e72e454
Showing
14 changed files
with
210 additions
and
318 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { Application } from '@hotwired/stimulus'; | ||
import autosize from 'autosize'; | ||
import { AutosizeController } from './AutosizeController'; | ||
|
||
jest.mock('autosize'); | ||
jest.useFakeTimers(); | ||
|
||
describe('AutosizeController', () => { | ||
let application; | ||
const resizeObserverMockObserve = jest.fn(); | ||
const resizeObserverMockUnobserve = jest.fn(); | ||
const resizeObserverMockDisconnect = jest.fn(); | ||
|
||
const ResizeObserverMock = jest.fn().mockImplementation(() => ({ | ||
observe: resizeObserverMockObserve, | ||
unobserve: resizeObserverMockUnobserve, | ||
disconnect: resizeObserverMockDisconnect, | ||
})); | ||
|
||
global.ResizeObserver = ResizeObserverMock; | ||
|
||
describe('basic behaviour', () => { | ||
beforeAll(() => { | ||
document.body.innerHTML = ` | ||
<textarea | ||
data-controller="w-autosize" | ||
id="text" | ||
></textarea> | ||
`; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
afterAll(() => { | ||
application.stop(); | ||
}); | ||
|
||
it('calls autosize when connected', async () => { | ||
expect(autosize).not.toHaveBeenCalled(); | ||
expect(ResizeObserverMock).not.toHaveBeenCalled(); | ||
expect(resizeObserverMockObserve).not.toHaveBeenCalled(); | ||
|
||
application = Application.start(); | ||
application.register('w-autosize', AutosizeController); | ||
|
||
// await next tick | ||
await Promise.resolve(); | ||
|
||
const textarea = document.getElementById('text'); | ||
|
||
expect(autosize).toHaveBeenCalledWith(textarea); | ||
expect(ResizeObserverMock).toHaveBeenCalledWith(expect.any(Function)); | ||
expect(resizeObserverMockObserve).toHaveBeenCalledWith(textarea); | ||
}); | ||
|
||
it('cleans up on disconnect', async () => { | ||
expect(autosize.destroy).not.toHaveBeenCalled(); | ||
expect(resizeObserverMockUnobserve).not.toHaveBeenCalled(); | ||
|
||
const textarea = document.getElementById('text'); | ||
|
||
textarea.remove(); | ||
|
||
await Promise.resolve(); | ||
|
||
expect(autosize.destroy).toHaveBeenCalledWith(textarea); | ||
expect(resizeObserverMockDisconnect).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe('using actions to dispatch methods', () => { | ||
beforeAll(() => { | ||
document.body.innerHTML = ` | ||
<textarea | ||
id="text" | ||
data-controller="w-autosize" | ||
data-action="some:event->w-autosize#resize" | ||
></textarea>`; | ||
|
||
application = Application.start(); | ||
application.register('w-autosize', AutosizeController); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
afterAll(() => { | ||
application.stop(); | ||
}); | ||
|
||
it('calls autosize update from resize method', async () => { | ||
// await next tick | ||
await Promise.resolve(); | ||
|
||
expect(autosize.update).not.toHaveBeenCalled(); | ||
|
||
const textarea = document.getElementById('text'); | ||
|
||
textarea.dispatchEvent(new CustomEvent('some:event')); | ||
jest.runAllTimers(); // resize is debounced | ||
|
||
expect(autosize.update).toHaveBeenCalledWith(textarea); | ||
|
||
// fire multiple events - confirm that the function is debounced | ||
|
||
expect(autosize.update).toHaveBeenCalledTimes(1); | ||
textarea.dispatchEvent(new CustomEvent('some:event')); | ||
textarea.dispatchEvent(new CustomEvent('some:event')); | ||
textarea.dispatchEvent(new CustomEvent('some:event')); | ||
textarea.dispatchEvent(new CustomEvent('some:event')); | ||
jest.runAllTimers(); // resize is debounced | ||
|
||
expect(autosize.update).toHaveBeenCalledTimes(2); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Controller } from '@hotwired/stimulus'; | ||
import autosize from 'autosize'; | ||
import { debounce } from '../utils/debounce'; | ||
|
||
/** | ||
* Adds the ability for a text area element to be auto-sized as the user | ||
* types in the field so that it expands to show all content. | ||
* | ||
* @example | ||
* <textarea data-controller="w-autosize"></textarea> | ||
*/ | ||
export class AutosizeController extends Controller<HTMLTextAreaElement> { | ||
resizeObserver?: ResizeObserver; | ||
|
||
resize() { | ||
autosize.update(this.element); | ||
} | ||
|
||
initialize() { | ||
this.resize = debounce(this.resize.bind(this), 50); | ||
} | ||
|
||
connect() { | ||
autosize(this.element); | ||
this.resizeObserver = new ResizeObserver(this.resize); | ||
this.resizeObserver.observe(this.element); | ||
} | ||
|
||
disconnect() { | ||
this.resizeObserver?.disconnect(); | ||
autosize.destroy(this.element); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.