-
Notifications
You must be signed in to change notification settings - Fork 13
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
1 parent
de19c38
commit dae3cbc
Showing
43 changed files
with
1,749 additions
and
1 deletion.
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,2 @@ | ||
export * from './tree.component'; | ||
export * from './tree.gen'; |
271 changes: 271 additions & 0 deletions
271
angular/bootstrap/src/components/tree/tree.component.ts
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,271 @@ | ||
import type {SlotContent} from '@agnos-ui/angular-headless'; | ||
import {BaseWidgetDirective, callWidgetFactory, ComponentTemplate, SlotDirective, UseDirective} from '@agnos-ui/angular-headless'; | ||
import { | ||
ChangeDetectionStrategy, | ||
Component, | ||
ContentChild, | ||
Directive, | ||
EventEmitter, | ||
inject, | ||
Input, | ||
Output, | ||
TemplateRef, | ||
ViewChild, | ||
} from '@angular/core'; | ||
import type {TreeContext, TreeItem, TreeSlotItemContext, TreeWidget} from './tree.gen'; | ||
import {createTree} from './tree.gen'; | ||
|
||
/** | ||
* Directive to provide a template reference for tree structure. | ||
* | ||
* This directive uses a template reference to render the {@link TreeContext}. | ||
*/ | ||
@Directive({selector: 'ng-template[auTreeStructure]', standalone: true}) | ||
export class TreeStructureDirective { | ||
public templateRef = inject(TemplateRef<TreeContext>); | ||
static ngTemplateContextGuard(_dir: TreeStructureDirective, context: unknown): context is TreeContext { | ||
return true; | ||
} | ||
} | ||
|
||
@Component({ | ||
standalone: true, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
imports: [UseDirective, TreeStructureDirective, SlotDirective], | ||
template: ` | ||
<ng-template auTreeStructure #structure let-state="state" let-directives="directives" let-api="api"> | ||
<ul role="tree" class="au-tree {{ state.className() }}" [auUse]="directives.navigationDirective"> | ||
@for (node of state.normalizedNodes(); track node) { | ||
<ng-template [auSlot]="state.root()" [auSlotProps]="{state, api, directives, item: node}"></ng-template> | ||
} | ||
</ul> | ||
</ng-template> | ||
`, | ||
}) | ||
class TreeDefaultStructureSlotComponent { | ||
@ViewChild('structure', {static: true}) readonly structure!: TemplateRef<TreeContext>; | ||
} | ||
|
||
/** | ||
* A constant representing the default slot for tree structure. | ||
*/ | ||
export const treeDefaultSlotStructure: SlotContent<TreeContext> = new ComponentTemplate(TreeDefaultStructureSlotComponent, 'structure'); | ||
|
||
/** | ||
* Directive to provide a template reference for tree item toggle. | ||
* | ||
* This directive uses a template reference to render the {@link TreeSlotItemContext}. | ||
*/ | ||
@Directive({selector: 'ng-template[auTreeToggle]', standalone: true}) | ||
export class TreeToggleDirective { | ||
public templateRef = inject(TemplateRef<TreeSlotItemContext>); | ||
static ngTemplateContextGuard(_dir: TreeToggleDirective, context: unknown): context is TreeSlotItemContext { | ||
return true; | ||
} | ||
} | ||
|
||
@Component({ | ||
standalone: true, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
imports: [UseDirective, TreeToggleDirective], | ||
template: ` | ||
<ng-template auTreeToggle #toggle let-directives="directives" let-item="item"> | ||
@if (item.children!.length > 0) { | ||
<button [auUse]="[directives.itemToggleDirective, {item}]"></button> | ||
} @else { | ||
<span class="au-tree-expand-icon-placeholder"></span> | ||
} | ||
</ng-template> | ||
`, | ||
}) | ||
class TreeDefaultToggleSlotComponent { | ||
@ViewChild('toggle', {static: true}) readonly toggle!: TemplateRef<TreeSlotItemContext>; | ||
} | ||
|
||
/** | ||
* A constant representing the default slot for tree item toggle. | ||
*/ | ||
export const treeDefaultSlotToggle: SlotContent<TreeSlotItemContext> = new ComponentTemplate(TreeDefaultToggleSlotComponent, 'toggle'); | ||
|
||
/** | ||
* Directive to provide a template reference for tree item content. | ||
* | ||
* This directive uses a template reference to render the {@link TreeSlotItemContext}. | ||
*/ | ||
@Directive({selector: 'ng-template[auTreeItem]', standalone: true}) | ||
export class TreeItemDirective { | ||
public templateRef = inject(TemplateRef<TreeSlotItemContext>); | ||
static ngTemplateContextGuard(_dir: TreeItemDirective, context: unknown): context is TreeSlotItemContext { | ||
return true; | ||
} | ||
} | ||
|
||
@Component({ | ||
standalone: true, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
imports: [UseDirective, SlotDirective, TreeItemDirective], | ||
template: ` | ||
<ng-template auTreeItem #treeItem let-state="state" let-directives="directives" let-item="item" let-api="api"> | ||
<span class="au-tree-item"> | ||
<ng-template [auSlot]="state.toggle()" [auSlotProps]="{state, api, directives, item}"></ng-template> | ||
{{ item.label }} | ||
</span> | ||
</ng-template> | ||
`, | ||
}) | ||
class TreeDefaultItemSlotComponent { | ||
@ViewChild('treeItem', {static: true}) readonly treeItem!: TemplateRef<TreeSlotItemContext>; | ||
} | ||
|
||
/** | ||
* A constant representing the default slot for tree item. | ||
*/ | ||
export const treeDefaultSlotItem: SlotContent<TreeSlotItemContext> = new ComponentTemplate(TreeDefaultItemSlotComponent, 'treeItem'); | ||
|
||
/** | ||
* Directive to provide a template reference for tree item. | ||
* | ||
* This directive uses a template reference to render the {@link TreeSlotItemContext}. | ||
*/ | ||
@Directive({selector: 'ng-template[auTreeRoot]', standalone: true}) | ||
export class TreeRootDirective { | ||
public templateRef = inject(TemplateRef<TreeSlotItemContext>); | ||
static ngTemplateContextGuard(_dir: TreeRootDirective, context: unknown): context is TreeSlotItemContext { | ||
return true; | ||
} | ||
} | ||
|
||
@Component({ | ||
standalone: true, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
imports: [UseDirective, SlotDirective, TreeRootDirective], | ||
template: ` | ||
<ng-template auTreeRoot #treeRoot let-state="state" let-directives="directives" let-item="item" let-api="api"> | ||
<li [auUse]="[directives.itemAttributesDirective, {item}]"> | ||
<ng-template [auSlot]="state.item()" [auSlotProps]="{state, api, directives, item}"></ng-template> | ||
@if (state.expandedMap().get(item)) { | ||
<ul role="group"> | ||
@for (child of item.children; track child) { | ||
<ng-template [auSlot]="state.root()" [auSlotProps]="{state, api, directives, item: child}"></ng-template> | ||
} | ||
</ul> | ||
} | ||
</li> | ||
</ng-template> | ||
`, | ||
}) | ||
class TreeDefaultRootSlotComponent { | ||
@ViewChild('treeRoot', {static: true}) readonly treeRoot!: TemplateRef<TreeSlotItemContext>; | ||
} | ||
|
||
/** | ||
* A constant representing the default slot for tree item. | ||
*/ | ||
export const treeDefaultSlotRoot = new ComponentTemplate(TreeDefaultRootSlotComponent, 'treeRoot'); | ||
|
||
@Component({ | ||
selector: '[auTree]', | ||
standalone: true, | ||
imports: [SlotDirective], | ||
template: ` <ng-template [auSlot]="state.structure()" [auSlotProps]="{state, api, directives}"></ng-template> `, | ||
}) | ||
export class TreeComponent extends BaseWidgetDirective<TreeWidget> { | ||
constructor() { | ||
super( | ||
callWidgetFactory({ | ||
factory: createTree, | ||
widgetName: 'tree', | ||
defaultConfig: { | ||
structure: treeDefaultSlotStructure, | ||
root: treeDefaultSlotRoot, | ||
item: treeDefaultSlotItem, | ||
toggle: treeDefaultSlotToggle, | ||
}, | ||
events: { | ||
onExpandToggle: (item: TreeItem) => this.expandToggle.emit(item), | ||
}, | ||
slotTemplates: () => ({ | ||
structure: this.slotStructureFromContent?.templateRef, | ||
root: this.slotRootFromContent?.templateRef, | ||
item: this.slotItemFromContent?.templateRef, | ||
toggle: this.slotToggleFromContent?.templateRef, | ||
}), | ||
}), | ||
); | ||
} | ||
/** | ||
* Optional accessibility label for the tree if there is no explicit label | ||
* | ||
* @defaultValue `''` | ||
*/ | ||
@Input('auAriaLabel') ariaLabel: string | undefined; | ||
/** | ||
* Array of the tree nodes to display | ||
* | ||
* @defaultValue `[]` | ||
*/ | ||
@Input('auNodes') nodes: TreeItem[] | undefined; | ||
/** | ||
* CSS classes to be applied on the widget main container | ||
* | ||
* @defaultValue `''` | ||
*/ | ||
@Input('auClassName') className: string | undefined; | ||
/** | ||
* Retrieves expand items of the TreeItem | ||
* | ||
* @param node - HTML element that is representing the expand item | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* (node: HTMLElement) => node.querySelectorAll('button') | ||
* ``` | ||
*/ | ||
@Input('auNavSelector') navSelector: ((node: HTMLElement) => NodeListOf<HTMLButtonElement>) | undefined; | ||
/** | ||
* Return the value for the 'aria-label' attribute of the toggle | ||
* @param label - tree item label | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* (label: string) => `Toggle ${label}` | ||
* ``` | ||
*/ | ||
@Input('auAriaLabelToggleFn') ariaLabelToggleFn: ((label: string) => string) | undefined; | ||
|
||
/** | ||
* An event emitted when the user toggles the expand of the TreeItem. | ||
* | ||
* Event payload is equal to the TreeItem clicked. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
@Output('auExpandToggle') expandToggle = new EventEmitter<TreeItem>(); | ||
|
||
/** | ||
* Slot to change the default tree item | ||
*/ | ||
@Input('auItem') item: SlotContent<TreeSlotItemContext>; | ||
@ContentChild(TreeItemDirective, {static: false}) slotItemFromContent: TreeItemDirective | undefined; | ||
|
||
/** | ||
* Slot to change the default display of the tree | ||
*/ | ||
@Input('auStructure') structure: SlotContent<TreeContext>; | ||
@ContentChild(TreeStructureDirective, {static: false}) slotStructureFromContent: TreeStructureDirective | undefined; | ||
|
||
/** | ||
* Slot to change the default tree item toggle | ||
*/ | ||
@Input('auToggle') toggle: SlotContent<TreeSlotItemContext>; | ||
@ContentChild(TreeToggleDirective, {static: false}) slotToggleFromContent: TreeToggleDirective | undefined; | ||
|
||
/** | ||
* Slot to change the default tree root | ||
*/ | ||
@Input('auRoot') root: SlotContent<TreeSlotItemContext>; | ||
@ContentChild(TreeRootDirective, {static: false}) slotRootFromContent: TreeRootDirective | undefined; | ||
} |
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
35 changes: 35 additions & 0 deletions
35
angular/demo/bootstrap/src/app/samples/tree/basic.route.ts
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,35 @@ | ||
import type {TreeItem} from '@agnos-ui/angular-bootstrap'; | ||
import {TreeComponent} from '@agnos-ui/angular-bootstrap'; | ||
import {Component} from '@angular/core'; | ||
|
||
@Component({ | ||
standalone: true, | ||
template: ` <au-component auTree [auNodes]="nodes"></au-component> `, | ||
imports: [TreeComponent], | ||
}) | ||
export default class BasicTreeComponent { | ||
readonly nodes: TreeItem[] = [ | ||
{ | ||
label: 'Node 1', | ||
isExpanded: true, | ||
children: [ | ||
{ | ||
label: 'Node 1.1', | ||
children: [ | ||
{ | ||
label: 'Node 1.1.1', | ||
}, | ||
], | ||
}, | ||
{ | ||
label: 'Node 1.2', | ||
children: [ | ||
{ | ||
label: 'Node 1.2.1', | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
]; | ||
} |
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 @@ | ||
export * from './tree'; |
Oops, something went wrong.