-
-
Notifications
You must be signed in to change notification settings - Fork 837
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
190 additions
and
70 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,55 @@ | ||
import ItemListUtil from '../utils/ItemList'; | ||
import Component from '../Component'; | ||
import type Mithril from 'mithril'; | ||
import listItems from '../helpers/listItems'; | ||
|
||
export interface IItemListAttrs { | ||
/** Unique key for the list. Use the convention of `componentName.listName` */ | ||
key: string; | ||
/** The context of the list. Usually the component instance. Will be automatically set if not provided. */ | ||
context?: any; | ||
/** Optionally, the element tag to wrap each item in. Defaults to none. */ | ||
wrapper?: string; | ||
} | ||
|
||
export default class ItemList<CustomAttrs extends IItemListAttrs = IItemListAttrs> extends Component<CustomAttrs> { | ||
view(vnode: Mithril.Vnode<CustomAttrs>) { | ||
const items = this.items(vnode.children).toArray(); | ||
|
||
return vnode.attrs.wrapper ? listItems(items, vnode.attrs.wrapper) : items; | ||
} | ||
|
||
items(children: Mithril.ChildArrayOrPrimitive | undefined): ItemListUtil<Mithril.Children> { | ||
const items = new ItemListUtil<Mithril.Children>(); | ||
|
||
let priority = 10; | ||
|
||
this.validateChildren(children) | ||
.reverse() | ||
.forEach((child: Mithril.Vnode<any, any>) => { | ||
items.add(child.key!.toString(), child, (priority += 10)); | ||
}); | ||
|
||
return items; | ||
} | ||
|
||
private validateChildren(children: Mithril.ChildArrayOrPrimitive | undefined): Mithril.Vnode<any, any>[] { | ||
if (!children) return []; | ||
|
||
children = Array.isArray(children) ? children : [children]; | ||
children = children.filter((child: Mithril.Children) => child !== null && child !== undefined); | ||
|
||
// It must be a Vnode array | ||
children.forEach((child: Mithril.Children) => { | ||
if (typeof child !== 'object' || !('tag' in child!)) { | ||
throw new Error(`[${this.attrs.key}] The ItemList component requires a valid mithril Vnode array. Found: ${typeof child}.`); | ||
} | ||
|
||
if (!child.key) { | ||
throw new Error('The ItemList component requires a unique key for each child in the list.'); | ||
} | ||
}); | ||
|
||
return children as Mithril.Vnode<any, any>[]; | ||
} | ||
} |
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,89 @@ | ||
import type IExtender from './IExtender'; | ||
import type { IExtensionModule } from './IExtender'; | ||
import type Application from '../Application'; | ||
import type Mithril from 'mithril'; | ||
import type { IItemObject } from '../utils/ItemList'; | ||
import { extend } from '../extend'; | ||
import ItemListComponent from '../components/ItemList'; | ||
|
||
type LazyContent<T> = (context: T) => Mithril.Children; | ||
|
||
/** | ||
* The `ItemList` extender allows you to add, remove, and replace items in an | ||
* `ItemList` component. Each ItemList has a unique key, which is used to | ||
* identify it. | ||
* | ||
* @example | ||
* ```tsx | ||
* import Extend from 'flarum/common/extenders'; | ||
* | ||
* export default [ | ||
* new Extend.ItemList<PageStructure>('PageStructure.mainItems') | ||
* .add('test', (context) => app.forum.attribute('baseUrl'), 400) | ||
* .setContent('hero', (context) => <div>My new content</div>) | ||
* .setPriority('hero', 0) | ||
* .remove('hero') | ||
* ] | ||
* ``` | ||
*/ | ||
export default class ItemList<T = Component<any>> implements IExtender { | ||
protected key: string; | ||
protected additions: Array<IItemObject<LazyContent<T>>> = []; | ||
protected removals: string[] = []; | ||
protected contentReplacements: Record<string, LazyContent<T>> = {}; | ||
protected priorityReplacements: Record<string, number> = {}; | ||
|
||
constructor(key: string) { | ||
this.key = key; | ||
} | ||
|
||
add(itemName: string, content: LazyContent<T>, priority: number = 0) { | ||
this.additions.push({ itemName, content, priority }); | ||
|
||
return this; | ||
} | ||
|
||
remove(itemName: string) { | ||
this.removals.push(itemName); | ||
|
||
return this; | ||
} | ||
|
||
setContent(itemName: string, content: LazyContent<T>) { | ||
this.contentReplacements[itemName] = content; | ||
|
||
return this; | ||
} | ||
|
||
setPriority(itemName: string, priority: number) { | ||
this.priorityReplacements[itemName] = priority; | ||
|
||
return this; | ||
} | ||
|
||
extend(app: Application, extension: IExtensionModule) { | ||
const { key, additions, removals, contentReplacements, priorityReplacements } = this; | ||
|
||
extend(ItemListComponent.prototype, 'items', function (this: ItemListComponent, items) { | ||
if (key !== this.attrs.key) return; | ||
|
||
const safeContent = (content: Mithril.Children) => (typeof content === 'string' ? [content] : content); | ||
|
||
for (const itemName of removals) { | ||
items.remove(itemName); | ||
} | ||
|
||
for (const { itemName, content, priority } of additions) { | ||
items.add(itemName, safeContent(content(this.attrs.context)), priority); | ||
} | ||
|
||
for (const [itemName, content] of Object.entries(contentReplacements)) { | ||
items.setContent(itemName, safeContent(content(this.attrs.context))); | ||
} | ||
|
||
for (const [itemName, priority] of Object.entries(priorityReplacements)) { | ||
items.setPriority(itemName, priority); | ||
} | ||
}); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,10 @@ | |
|
||
&-sidebar { | ||
margin-top: 0; | ||
|
||
&-main { | ||
height: 100%; | ||
} | ||
} | ||
} | ||
} | ||
|