mirror of
https://github.com/flarum/core.git
synced 2025-08-06 08:27:42 +02:00
start
This commit is contained in:
@@ -1,27 +1,61 @@
|
||||
import type Mithril from 'mithril';
|
||||
|
||||
import app from '../../common/app';
|
||||
import Component from '../Component';
|
||||
import Component, { ComponentAttrs } from '../Component';
|
||||
import icon from '../helpers/icon';
|
||||
import listItems from '../helpers/listItems';
|
||||
|
||||
export interface IDropdownAttrs extends ComponentAttrs{
|
||||
/**
|
||||
* A class name to apply to the dropdown toggle button.
|
||||
*/
|
||||
buttonClassName?: string;
|
||||
|
||||
/**
|
||||
* A class name to apply to the dropdown menu.
|
||||
*/
|
||||
menuClassName?: string;
|
||||
|
||||
/**
|
||||
* The name of an icon to show in the dropdown toggle button.
|
||||
*/
|
||||
icon?: string;
|
||||
|
||||
/**
|
||||
* The name of an icon to show on the right of the button.
|
||||
*/
|
||||
caretIcon?: string;
|
||||
|
||||
/**
|
||||
* The label of the dropdown toggle button. Defaults to 'Controls'.
|
||||
*/
|
||||
label?: Mithril.Children;
|
||||
|
||||
/**
|
||||
* The label used to describe the dropdown toggle button to assistive readers.
|
||||
* Defaults to 'Toggle dropdown menu'.
|
||||
*/
|
||||
accessibleToggleLabel?: string;
|
||||
|
||||
/**
|
||||
* A callback to run when the dropdown is shown.
|
||||
*/
|
||||
onshow?: () => void;
|
||||
|
||||
/**
|
||||
* A callback to run when the dropdown is hidden.
|
||||
*/
|
||||
onhide?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Dropdown` component displays a button which, when clicked, shows a
|
||||
* dropdown menu beneath it.
|
||||
*
|
||||
* ### Attrs
|
||||
*
|
||||
* - `buttonClassName` A class name to apply to the dropdown toggle button.
|
||||
* - `menuClassName` A class name to apply to the dropdown menu.
|
||||
* - `icon` The name of an icon to show in the dropdown toggle button.
|
||||
* - `caretIcon` The name of an icon to show on the right of the button.
|
||||
* - `label` The label of the dropdown toggle button. Defaults to 'Controls'.
|
||||
* - `accessibleToggleLabel` The label used to describe the dropdown toggle button to assistive readers. Defaults to 'Toggle dropdown menu'.
|
||||
* - `onhide`
|
||||
* - `onshow`
|
||||
*
|
||||
* The children will be displayed as a list inside of the dropdown menu.
|
||||
*/
|
||||
export default class Dropdown extends Component {
|
||||
static initAttrs(attrs) {
|
||||
export default class Dropdown<CustomAttrs extends IDropdownAttrs = IDropdownAttrs> extends Component<CustomAttrs> {
|
||||
static initAttrs(attrs: IDropdownAttrs) {
|
||||
attrs.className = attrs.className || '';
|
||||
attrs.buttonClassName = attrs.buttonClassName || '';
|
||||
attrs.menuClassName = attrs.menuClassName || '';
|
||||
@@ -30,13 +64,9 @@ export default class Dropdown extends Component {
|
||||
attrs.accessibleToggleLabel = attrs.accessibleToggleLabel || app.translator.trans('core.lib.dropdown.toggle_dropdown_accessible_label');
|
||||
}
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
protected showing = false;
|
||||
|
||||
this.showing = false;
|
||||
}
|
||||
|
||||
view(vnode) {
|
||||
view(vnode: Mithril.VnodeDOM<CustomAttrs, this>) {
|
||||
const items = vnode.children ? listItems(vnode.children) : [];
|
||||
const renderItems = this.attrs.lazyDraw ? this.showing : true;
|
||||
|
||||
@@ -48,7 +78,7 @@ export default class Dropdown extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
oncreate(vnode) {
|
||||
oncreate(vnode: Mithril.VnodeDOM<CustomAttrs, this>) {
|
||||
super.oncreate(vnode);
|
||||
|
||||
// When opening the dropdown menu, work out if the menu goes beyond the
|
||||
@@ -80,13 +110,13 @@ export default class Dropdown extends Component {
|
||||
|
||||
$menu.removeClass('Dropdown-menu--top Dropdown-menu--right');
|
||||
|
||||
$menu.toggleClass('Dropdown-menu--top', $menu.offset().top + $menu.height() > $(window).scrollTop() + $(window).height());
|
||||
$menu.toggleClass('Dropdown-menu--top', $menu.offset()!.top + $menu.height()! > $(window).scrollTop()! + $(window).height()!);
|
||||
|
||||
if ($menu.offset().top < 0) {
|
||||
if ($menu.offset()!.top < 0) {
|
||||
$menu.removeClass('Dropdown-menu--top');
|
||||
}
|
||||
|
||||
$menu.toggleClass('Dropdown-menu--right', isRight || $menu.offset().left + $menu.width() > $(window).scrollLeft() + $(window).width());
|
||||
$menu.toggleClass('Dropdown-menu--right', isRight || $menu.offset()!.left + $menu.width()! > $(window).scrollLeft()! + $(window).width()!);
|
||||
});
|
||||
|
||||
this.$().on('hidden.bs.dropdown', () => {
|
||||
@@ -102,11 +132,8 @@ export default class Dropdown extends Component {
|
||||
|
||||
/**
|
||||
* Get the template for the button.
|
||||
*
|
||||
* @return {*}
|
||||
* @protected
|
||||
*/
|
||||
getButton(children) {
|
||||
protected getButton(children: Mithril.Children): Mithril.Children {
|
||||
return (
|
||||
<button
|
||||
className={'Dropdown-toggle ' + this.attrs.buttonClassName}
|
||||
@@ -122,11 +149,8 @@ export default class Dropdown extends Component {
|
||||
|
||||
/**
|
||||
* Get the template for the button's content.
|
||||
*
|
||||
* @return {*}
|
||||
* @protected
|
||||
*/
|
||||
getButtonContent(children) {
|
||||
protected getButtonContent(children: Mithril.Children): Mithril.Children {
|
||||
return [
|
||||
this.attrs.icon ? icon(this.attrs.icon, { className: 'Button-icon' }) : '',
|
||||
<span className="Button-label">{this.attrs.label}</span>,
|
||||
@@ -134,7 +158,7 @@ export default class Dropdown extends Component {
|
||||
];
|
||||
}
|
||||
|
||||
getMenu(items) {
|
||||
protected getMenu(items: Mithril.Children): Mithril.Children {
|
||||
return <ul className={'Dropdown-menu dropdown-menu ' + this.attrs.menuClassName}>{items}</ul>;
|
||||
}
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
import Dropdown from './Dropdown';
|
||||
import type Mithril from 'mithril';
|
||||
import Dropdown, { IDropdownAttrs } from './Dropdown';
|
||||
import icon from '../helpers/icon';
|
||||
import { ModdedVnode } from '../helpers/listItems';
|
||||
|
||||
/**
|
||||
* Determines via a vnode is currently "active".
|
||||
@@ -9,8 +11,8 @@ import icon from '../helpers/icon';
|
||||
*
|
||||
* This is a temporary patch, and as so, is not exported / placed in utils.
|
||||
*/
|
||||
function isActive(vnode) {
|
||||
const tag = vnode.tag;
|
||||
function isActive(vnode: ModdedVnode<{}>) {
|
||||
const tag = vnode.tag as VnodeElementTag;
|
||||
|
||||
// Allow non-selectable dividers/headers to be added.
|
||||
if (typeof tag === 'string' && tag !== 'a' && tag !== 'button') return false;
|
||||
@@ -19,21 +21,29 @@ function isActive(vnode) {
|
||||
tag.initAttrs(vnode.attrs);
|
||||
}
|
||||
|
||||
return 'isActive' in tag ? tag.isActive(vnode.attrs) : vnode.attrs.active;
|
||||
return 'isActive' in tag ? tag.isActive(vnode.attrs) : (vnode.attrs as any).active;
|
||||
}
|
||||
|
||||
export interface ISelectDropdownAttrs extends IDropdownAttrs {
|
||||
/**
|
||||
* An icon for the select dropdown's caret.
|
||||
*/
|
||||
caretIcon?: string;
|
||||
|
||||
/**
|
||||
* The default label if no child is active.
|
||||
*/
|
||||
defaultLabel?: Mithril.Children;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The `SelectDropdown` component is the same as a `Dropdown`, except the toggle
|
||||
* button's label is set as the label of the first child which has a truthy
|
||||
* `active` prop.
|
||||
*
|
||||
* ### Attrs
|
||||
*
|
||||
* - `caretIcon`
|
||||
* - `defaultLabel`
|
||||
*/
|
||||
export default class SelectDropdown extends Dropdown {
|
||||
static initAttrs(attrs) {
|
||||
export default class SelectDropdown<CustomAttrs extends ISelectDropdownAttrs = ISelectDropdownAttrs> extends Dropdown<CustomAttrs> {
|
||||
static initAttrs(attrs: ISelectDropdownAttrs) {
|
||||
attrs.caretIcon = typeof attrs.caretIcon !== 'undefined' ? attrs.caretIcon : 'fas fa-sort';
|
||||
|
||||
super.initAttrs(attrs);
|
||||
@@ -41,12 +51,12 @@ export default class SelectDropdown extends Dropdown {
|
||||
attrs.className += ' Dropdown--select';
|
||||
}
|
||||
|
||||
getButtonContent(children) {
|
||||
const activeChild = children.find(isActive);
|
||||
let label = (activeChild && activeChild.children) || this.attrs.defaultLabel;
|
||||
protected getButtonContent(children: Mithril.Children): Mithril.ChildArray {
|
||||
const activeChild = Array.isArray(children) ? children.find(isActive) : children;
|
||||
let label = (activeChild && typeof activeChild === 'object' && 'children' in activeChild && activeChild.children) || this.attrs.defaultLabel;
|
||||
|
||||
if (label instanceof Array) label = label[0];
|
||||
|
||||
return [<span className="Button-label">{label}</span>, icon(this.attrs.caretIcon, { className: 'Button-caret' })];
|
||||
return [<span className="Button-label">{label}</span>, icon(this.attrs.caretIcon!, { className: 'Button-caret' })];
|
||||
}
|
||||
}
|
@@ -1,20 +1,25 @@
|
||||
import Dropdown from './Dropdown';
|
||||
import type Mithril from 'mithril';
|
||||
import Dropdown, { IDropdownAttrs } from './Dropdown';
|
||||
import Button from './Button';
|
||||
import icon from '../helpers/icon';
|
||||
|
||||
export interface ISplitDropdownAttrs extends IDropdownAttrs {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The `SplitDropdown` component is similar to `Dropdown`, but the first child
|
||||
* is displayed as its own button prior to the toggle button.
|
||||
*/
|
||||
export default class SplitDropdown extends Dropdown {
|
||||
static initAttrs(attrs) {
|
||||
export default class SplitDropdown<CustomAttrs extends ISplitDropdownAttrs = ISplitDropdownAttrs> extends Dropdown<CustomAttrs> {
|
||||
static initAttrs(attrs: ISplitDropdownAttrs) {
|
||||
super.initAttrs(attrs);
|
||||
|
||||
attrs.className += ' Dropdown--split';
|
||||
attrs.menuClassName += ' Dropdown-menu--right';
|
||||
}
|
||||
|
||||
getButton(children) {
|
||||
getButton(children: Mithril.ChildArray): Mithril.Children {
|
||||
// Make a copy of the attrs of the first child component. We will assign
|
||||
// these attrs to a new button, so that it has exactly the same behaviour as
|
||||
// the first child.
|
||||
@@ -39,11 +44,8 @@ export default class SplitDropdown extends Dropdown {
|
||||
/**
|
||||
* Get the first child. If the first child is an array, the first item in that
|
||||
* array will be returned.
|
||||
*
|
||||
* @return {*}
|
||||
* @protected
|
||||
*/
|
||||
getFirstChild(children) {
|
||||
protected getFirstChild(children: Mithril.Children): Mithril.Vnode {
|
||||
let firstChild = children;
|
||||
|
||||
while (firstChild instanceof Array) firstChild = firstChild[0];
|
Reference in New Issue
Block a user