-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: update module to use the latest ver. of ovee.ja and add docs (#65)
* feat: update module to use the latest ver. of ovee.ja and add docs * refactor: update typings a little --------- Co-authored-by: Kamil Kondratowicz <[email protected]> Co-authored-by: Miłosz Mandowski <[email protected]>
- Loading branch information
1 parent
f1c8b9b
commit 5c422be
Showing
6 changed files
with
257 additions
and
47 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# ContentLoader Module | ||
|
||
The ContentLoader module is responsible for loading and transitioning content. It uses resolvers to manage different types of content transitions and handles errors during the content loading process. | ||
|
||
## Constants | ||
|
||
- `DEFAULT_TIMEOUT`: The default timeout value for loading content, set to 20,000 milliseconds (20 seconds). | ||
|
||
## Methods | ||
|
||
### `async loadPage(url, resolverName, target, pushState): Promise<void>` | ||
|
||
Asynchronously loads new content using the specified [resolver](./resolver.md). | ||
|
||
- `url: string` - The URL of the page to load. | ||
- `resolverName: string` - The name of the resolver to use for the content transition. | ||
- `target?: Element | null `- The target DOM element for the content. Defaults to `null`. | ||
- `pushState?: boolean` - Indicates whether to push the state to the history. Defaults to `true`. | ||
|
||
## How it's works | ||
|
||
1. Makes a request to load the content from the specified URL with a timeout. | ||
2. Calls the `contentOut` method on the resolver to manage the transition of the old content. | ||
3. Attempts to fetch and parse the new content. | ||
1. If it occurs error, it calls the `handleError` method and the process ends. | ||
2. If fetch attempt is successfull and the `Resolver` should push the state, it updates the browser's history (calls the `updateHistory` method). | ||
4. Calls the resolver's `updateContent` method to update the DOM with the new content. | ||
5. Finally, calls the `contentIn` method on the resolver to finalize the transition. | ||
|
||
## Types | ||
|
||
### ContentLoaderOptions | ||
|
||
Defines the options that can be passed to the `ContentLoader` module. | ||
|
||
- `resolvers: Record<string, ResolverClass>` - Required. A record of resolver classes keyed by a string identifier. These resolvers are responsible for managing different aspects of content transitions. | ||
- `timeout?: number` - Optional. The timeout duration in milliseconds for content loading requests. | ||
|
||
### ContentLoaderReturn | ||
|
||
The return type of the ContentLoader module, providing a method for loading pages. | ||
|
||
`loadPage: (url: string, resolverName: string, target?: Element | null, pushState?: boolean) => Promise<void>` - Function to load content using the specified resolver and handle the content transition. | ||
|
||
## Example | ||
|
||
::: code-group | ||
```ts [app.ts] | ||
import { createApp } from 'ovee.js'; | ||
import OveeBarba from '@ovee.js/barba'; | ||
|
||
import { ContentLoader } from '@ovee.js/content-loader'; // [!code focus] | ||
import { DefaultResolver } from './DefaultResolver'; | ||
|
||
const root = document.body; | ||
|
||
createApp() | ||
.use('ContentLoader', ContentLoader, { // [!code focus] | ||
timeout: 15000, // [!code focus] | ||
resolvers: { // [!code focus] | ||
'default': DefaultResolver, // [!code focus] | ||
} // [!code focus] | ||
}) // [!code focus] | ||
.run(root); | ||
``` | ||
|
||
```ts [DefaultResolver.ts] | ||
import { Resolver } from '@ovee.js/content-loader'; | ||
import gsap from 'gsap'; | ||
|
||
export class DefaultResolver extends Resolver { | ||
oldContent: HTMLElement | null = null; | ||
newContent: HTMLElement | null = null; | ||
shoudlPushState = true; | ||
|
||
async contentOut() { | ||
this.oldContent = document.querySelector('.content'); | ||
|
||
await gsap.to(this.oldContent, { | ||
autoAlpha: 0, | ||
}); | ||
} | ||
|
||
handleError() { | ||
window.alert('Oops, something went wrong'); | ||
|
||
gsap.set(this.oldContent, { | ||
autoAlpha: 1, | ||
}); | ||
} | ||
|
||
async updateContent(doc: Document) { | ||
this.newContent = doc.querySelector('.content'); | ||
|
||
if(!this.newContent) { | ||
return; | ||
} | ||
|
||
gsap.set(this.oldContent, { | ||
autoAlpha: 0 | ||
}); | ||
|
||
this.oldContent.insertAfter(this.newContent); | ||
this.oldContent.remove(); | ||
} | ||
|
||
async contentIn() { | ||
await gsap.to(this.newContent, { | ||
autoAlpha: 1 | ||
}); | ||
} | ||
} | ||
``` | ||
|
||
```ts [LoadMoreComponent.ts] | ||
export const LoadMore = defineComponent((element) => { | ||
const contentLoader = useModule('ContentLoader', true); | ||
const nextPageUrl = useDataAttr('next-page-url'); | ||
|
||
async function loadMore() { | ||
if(!nextPageUrl) { | ||
return; | ||
} | ||
|
||
await contentLoader?.loadPage(nextPageUrl, 'default', null, false); | ||
} | ||
}) | ||
``` | ||
::: |
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,57 @@ | ||
# Resolver | ||
|
||
The Resolver class is responsible for managing content transitions and history updates. It integrates with the `@barba/core` library for history management. | ||
|
||
## Props | ||
|
||
- `shouldPushState: boolean` - Indicates whether the state should be pushed to the history. | ||
|
||
## Methods | ||
|
||
### `async contentOut(): Promise<void>` | ||
|
||
This asynchronous method is intended to handle the transition of the old content. It's an empty method that can be overridden in subclasses. | ||
|
||
### `async updateContent(doc: Document): Promise<void>` | ||
|
||
Updates the content based on the provided `Document`. This method is asynchronous and is designed to be overridden in subclasses. | ||
|
||
`doc: Document` - The new document content. | ||
|
||
### `updateHistory(title: string, url: string): void` | ||
|
||
Updates the browser's history and document title. | ||
|
||
`title: string` - The new title for the document. | ||
`url: string` - The URL to add to the history. | ||
|
||
Default: | ||
|
||
```ts | ||
updateHistory(title: string, url: string): void { | ||
document.title = title; | ||
history.add(url, 'barba'); | ||
} | ||
``` | ||
|
||
### `handleError(): void` | ||
|
||
Handles errors that may occur during the content update or navigation process. The method is currently a stub and can be implemented in subclasses. | ||
|
||
### `async contentIn(): Promise<void>` | ||
|
||
This asynchronous method is intended to handle the transition of new content. Like `contentOut`, it's an empty method that can be overridden in subclasses. | ||
|
||
## Type Alias | ||
|
||
### `ResolverClass` | ||
|
||
A TypeScript type alias representing the `Resolver` class. | ||
|
||
```ts | ||
export type ResolverClass = typeof Resolver; | ||
``` | ||
|
||
## Example | ||
|
||
[See example](./module.md#example) |
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 |
---|---|---|
@@ -1,68 +1,82 @@ | ||
import Barba from '@barba/core'; | ||
import { Module } from 'ovee.js'; | ||
import barba from '@barba/core'; | ||
import { defineModule } from 'ovee.js'; | ||
|
||
import { ResolverClass } from './Resolver'; | ||
|
||
const { history, dom, request } = Barba; | ||
export const DEFAULT_TIMEOUT = 20000; | ||
|
||
export interface ContentLoaderOptions { | ||
resolvers: Record<string, ResolverClass>; | ||
timeout?: number; | ||
resolvers?: Record<string, ResolverClass>; | ||
} | ||
|
||
export class ContentLoader extends Module<ContentLoaderOptions> { | ||
timeout = DEFAULT_TIMEOUT; | ||
resolvers: Record<string, ResolverClass> = {}; | ||
export interface ContentLoaderReturn { | ||
loadPage: LoadPage; | ||
} | ||
|
||
init(): void { | ||
this.timeout = this.options.timeout ?? DEFAULT_TIMEOUT; | ||
this.resolvers = this.options.resolvers ?? {}; | ||
} | ||
type LoadPage = ( | ||
url: string, | ||
resolverName: string, | ||
target?: Element | null, | ||
pushState?: boolean | ||
) => Promise<void>; | ||
|
||
export const ContentLoader = defineModule<ContentLoaderOptions, ContentLoaderReturn>( | ||
({ app, options }) => { | ||
const timeout = options.timeout ?? DEFAULT_TIMEOUT; | ||
const resolvers: Record<string, ResolverClass> = options.resolvers; | ||
|
||
getResolver(name: string): ResolverClass | false { | ||
if (this.resolvers[name] === undefined) { | ||
console.error(`Resolver not registered for key ${name}`); | ||
function getResolver(name: string): ResolverClass | false { | ||
if (resolvers[name] === undefined) { | ||
console.error(`[ovee.js/ContentLoader] Resolver not registered for key ${name}`); | ||
|
||
return false; | ||
return false; | ||
} | ||
|
||
return resolvers[name]; | ||
} | ||
|
||
return this.resolvers[name]; | ||
} | ||
const loadPage: LoadPage = async (url, resolverName, target = null, pushState = true) => { | ||
const ResolverCtor = getResolver(resolverName); | ||
|
||
async loadPage( | ||
url: string, | ||
resolverName: string, | ||
target: Element | null = null, | ||
pushState = true | ||
): Promise<void> { | ||
const ResolverCtor = this.getResolver(resolverName); | ||
if (!ResolverCtor) { | ||
return; | ||
} | ||
|
||
if (!ResolverCtor) { | ||
return; | ||
} | ||
const resolver = new ResolverCtor(app, target, url, pushState); | ||
const requestPage = barba.request(url, timeout, (reqUrl, reqErr) => { | ||
console.error(`[ovee.js/ContentLoader] Error while requesting ${reqUrl}`, reqErr); | ||
|
||
const resolver = new ResolverCtor(this.$app, target, url, pushState); | ||
const requestPage = request(url, this.timeout, (_url, err) => { | ||
console.error(`[ContentLoader] Error while requesting ${_url}`, err); | ||
return false; | ||
}); | ||
|
||
return false; | ||
}); | ||
await resolver.contentOut(); | ||
|
||
await resolver.contentOut(); | ||
let content: string | null = null; | ||
|
||
const content = dom.toDocument(await requestPage); | ||
try { | ||
content = await requestPage; | ||
} catch { | ||
resolver.handleError(); | ||
} | ||
|
||
if (resolver.pushState && resolver.shouldPushState) { | ||
document.title = content.title; | ||
history.add(url, 'barba'); | ||
} | ||
if (!content) { | ||
return; | ||
} | ||
|
||
await resolver.updateContent(content); | ||
await resolver.contentIn(); | ||
} | ||
const parser = new DOMParser(); | ||
const doc = parser.parseFromString(content, 'text/html'); | ||
|
||
if (resolver.pushState && resolver.shouldPushState) { | ||
resolver.updateHistory(doc.title, url); | ||
} | ||
|
||
static getName(): string { | ||
return 'ContentLoader'; | ||
await resolver.updateContent(doc); | ||
await resolver.contentIn(); | ||
}; | ||
|
||
return { | ||
loadPage, | ||
}; | ||
} | ||
} | ||
); |
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