-
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.
feat(collapse): add the collapse (#911)
- Loading branch information
Showing
42 changed files
with
704 additions
and
15 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
91 changes: 91 additions & 0 deletions
91
angular/bootstrap/src/components/collapse/collapse.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,91 @@ | ||
import {auBooleanAttribute, BaseWidgetDirective, useDirectiveForHost} from '@agnos-ui/angular-headless'; | ||
import type {CollapseWidget} from '@agnos-ui/core-bootstrap/components/collapse'; | ||
import {createCollapse} from '@agnos-ui/core-bootstrap/components/collapse'; | ||
import {Directive, EventEmitter, Input, Output} from '@angular/core'; | ||
import {callWidgetFactory} from '../../config'; | ||
|
||
@Directive({ | ||
selector: '[auCollapse]', | ||
standalone: true, | ||
exportAs: 'auCollapse', | ||
}) | ||
export class CollapseDirective extends BaseWidgetDirective<CollapseWidget> { | ||
/** | ||
* If `true`, collapse opening will be animated at init time. | ||
* | ||
* @defaultValue `false` | ||
*/ | ||
@Input({alias: 'auAnimatedOnInit', transform: auBooleanAttribute}) animatedOnInit: boolean | undefined; | ||
|
||
/** | ||
* If `true`, collapse closing and opening will be animated. | ||
* | ||
* @defaultValue `true` | ||
*/ | ||
@Input({alias: 'auAnimated', transform: auBooleanAttribute}) animated: boolean | undefined; | ||
|
||
/** | ||
* CSS classes to be applied on the widget main container | ||
* | ||
* @defaultValue `''` | ||
*/ | ||
@Input('auClassName') className: string | undefined; | ||
|
||
/** | ||
* If `true`, collapse will be done horizontally. | ||
* | ||
* @defaultValue `false` | ||
*/ | ||
@Input({alias: 'auHorizontal', transform: auBooleanAttribute}) horizontal: boolean | undefined; | ||
|
||
/** | ||
* If `true` the collapse is visible to the user | ||
* | ||
* @defaultValue `true` | ||
*/ | ||
@Input({alias: 'auVisible', transform: auBooleanAttribute}) visible: boolean | undefined; | ||
|
||
/** | ||
* Callback called when the collapse visibility changed. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
@Output('auVisibleChange') visibleChange = new EventEmitter<boolean>(); | ||
|
||
/** | ||
* Callback called when the collapse is hidden. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
@Output('auHidden') hidden = new EventEmitter<void>(); | ||
|
||
/** | ||
* Callback called when the collapse is shown. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
@Output('auShown') shown = new EventEmitter<void>(); | ||
|
||
readonly _widget = callWidgetFactory({ | ||
factory: createCollapse, | ||
widgetName: 'collapse', | ||
defaultConfig: {}, | ||
events: { | ||
onVisibleChange: (event) => this.visibleChange.emit(event), | ||
onShown: () => this.shown.emit(), | ||
onHidden: () => this.hidden.emit(), | ||
}, | ||
afterInit: () => { | ||
useDirectiveForHost(this._widget.directives.transitionDirective); | ||
}, | ||
}); | ||
} |
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 './collapse.component'; | ||
export * from './collapse.gen'; |
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
14 changes: 14 additions & 0 deletions
14
angular/demo/bootstrap/src/app/samples/collapse/default.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,14 @@ | ||
import {AgnosUIAngularModule} from '@agnos-ui/angular-bootstrap'; | ||
import {Component} from '@angular/core'; | ||
|
||
@Component({ | ||
standalone: true, | ||
imports: [AgnosUIAngularModule], | ||
template: ` | ||
<button class="btn btn-primary m-2" type="button" (click)="collapse.api.open()">Open collapse</button> | ||
<button class="btn btn-primary m-2" type="button" (click)="collapse.api.close()">Close collapse</button> | ||
<button class="btn btn-primary m-2" type="button" (click)="collapse.api.toggle()">Toggle collapse</button> | ||
<div auCollapse #collapse="auCollapse">Visible content</div> | ||
`, | ||
}) | ||
export default class DefaultCollapseComponent {} |
22 changes: 22 additions & 0 deletions
22
angular/demo/bootstrap/src/app/samples/collapse/playground.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,22 @@ | ||
import type {CollapseDirective} from '@agnos-ui/angular-bootstrap'; | ||
import {AgnosUIAngularModule, getCollapseDefaultConfig} from '@agnos-ui/angular-bootstrap'; | ||
import {Component, ViewChild} from '@angular/core'; | ||
import {getUndefinedValues, hashChangeHook, provideHashConfig} from '../../utils'; | ||
|
||
const undefinedConfig = getUndefinedValues(getCollapseDefaultConfig()); | ||
|
||
@Component({ | ||
standalone: true, | ||
imports: [AgnosUIAngularModule], | ||
providers: provideHashConfig('collapse'), | ||
template: `<div auCollapse #widget="auCollapse">Visible content</div>`, | ||
}) | ||
export default class PlaygroundComponent { | ||
@ViewChild('widget') widget!: CollapseDirective; | ||
|
||
constructor() { | ||
hashChangeHook((props) => { | ||
this.widget._widget.patch({...undefinedConfig, ...props}); | ||
}); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
angular/demo/daisyui/src/app/samples/collapse/collapse.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,42 @@ | ||
import {createSimpleClassTransition, createTransition, UseDirective} from '@agnos-ui/angular-headless'; | ||
import {ChangeDetectionStrategy, Component, input, output} from '@angular/core'; | ||
/** | ||
* You can create easily your own collapse component with the help of the `createTransition` function | ||
* you will be able to plug the transition event of DaisyUI to your component. | ||
* The `createSimpleClassTransition` is a helper to create a transition that will add a class to the element but you don't have to add classes as this | ||
* DaisyUI CSS is not using this feature. | ||
*/ | ||
@Component({ | ||
selector: 'app-collapse', | ||
imports: [UseDirective], | ||
standalone: true, | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
template: ` | ||
<div | ||
tabindex="0" | ||
class="collapse bg-base-200" | ||
[auUse]="transition.directives.directive" | ||
(blur)="transition.api.hide()" | ||
(focus)="transition.api.show()" | ||
> | ||
<div class="collapse-title font-medium text-xl">{{ title() }}</div> | ||
<div class="collapse-content"><ng-content /></div> | ||
</div> | ||
`, | ||
}) | ||
export class CollapseDaisyComponent { | ||
readonly title = input('Focus me to see content'); | ||
|
||
// The advantage of AgnosUI here is that it plug the transition state to some possible callbacks | ||
onShown = output(); | ||
onHidden = output(); | ||
|
||
transition = createTransition({ | ||
props: { | ||
visible: false, // could be something in an input that also add the collapse-open class | ||
transition: createSimpleClassTransition({}), | ||
onShown: () => this.onShown.emit(), | ||
onHidden: () => this.onHidden.emit(), | ||
}, | ||
}); | ||
} |
13 changes: 13 additions & 0 deletions
13
angular/demo/daisyui/src/app/samples/collapse/default.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,13 @@ | ||
import {Component} from '@angular/core'; | ||
import {CollapseDaisyComponent} from './collapse.component'; | ||
|
||
@Component({ | ||
standalone: true, | ||
imports: [CollapseDaisyComponent], | ||
template: ` <app-collapse (onHidden)="onHidden()"><p>tabindex necessary is already put</p></app-collapse> `, | ||
}) | ||
export default class DefaultAlertComponent { | ||
onHidden() { | ||
console.log('Hidden'); | ||
} | ||
} |
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,169 @@ | ||
import {createTransition} from '@agnos-ui/core/services/transitions/baseTransitions'; | ||
import type {ConfigValidator, Directive, PropsConfig, Widget} from '@agnos-ui/core/types'; | ||
import {stateStores, writablesForProps} from '@agnos-ui/core/utils/stores'; | ||
import {bindDirectiveNoArg} from '@agnos-ui/core/utils/directive'; | ||
import {typeBoolean} from '@agnos-ui/core/utils/writables'; | ||
import {collapseHorizontalTransition, collapseVerticalTransition} from '../../services/transitions/collapse'; | ||
import {asWritable, computed} from '@amadeus-it-group/tansu'; | ||
|
||
export interface CollapseCommonPropsAndState { | ||
/** | ||
* CSS classes to be applied on the widget main container | ||
* | ||
* @defaultValue `''` | ||
*/ | ||
className: string; | ||
/** | ||
* If `true`, collapse will be done horizontally. | ||
* | ||
* @defaultValue `false` | ||
*/ | ||
horizontal: boolean; | ||
/** | ||
* If `true` the collapse is visible to the user | ||
* | ||
* @defaultValue `true` | ||
*/ | ||
visible: boolean; | ||
} | ||
|
||
export interface CollapseState extends CollapseCommonPropsAndState { | ||
/** | ||
* Is `true` when the collapse is hidden. Compared to `visible`, this is updated after the transition is executed. | ||
*/ | ||
hidden: boolean; | ||
} | ||
|
||
export interface CollapseProps extends CollapseCommonPropsAndState { | ||
/** | ||
* Callback called when the collapse visibility changed. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
onVisibleChange: (visible: boolean) => void; | ||
|
||
/** | ||
* Callback called when the collapse is hidden. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
onHidden: () => void; | ||
|
||
/** | ||
* Callback called when the collapse is shown. | ||
* | ||
* @defaultValue | ||
* ```ts | ||
* () => {} | ||
* ``` | ||
*/ | ||
onShown: () => void; | ||
|
||
/** | ||
* If `true`, collapse opening will be animated at init time. | ||
* | ||
* @defaultValue `false` | ||
*/ | ||
animatedOnInit: boolean; | ||
/** | ||
* If `true`, collapse closing and opening will be animated. | ||
* | ||
* @defaultValue `true` | ||
*/ | ||
animated: boolean; | ||
} | ||
|
||
export interface CollapseApi { | ||
/** | ||
* Triggers collapse closing programmatically. | ||
*/ | ||
close(): void; | ||
|
||
/** | ||
* Triggers the collapse content to be displayed for the user. | ||
*/ | ||
open(): void; | ||
|
||
/** | ||
* Toggles the collapse content visibility. | ||
*/ | ||
toggle(): void; | ||
} | ||
|
||
export interface CollapseDirectives { | ||
/** | ||
* the transition directive, piloting what is the visual effect of going from hidden to visible | ||
*/ | ||
transitionDirective: Directive; | ||
} | ||
|
||
export type CollapseWidget = Widget<CollapseProps, CollapseState, CollapseApi, object, CollapseDirectives>; | ||
|
||
const defaultCollapseConfig: CollapseProps = { | ||
visible: true, | ||
horizontal: false, | ||
onVisibleChange: () => {}, | ||
onShown: () => {}, | ||
onHidden: () => {}, | ||
animated: true, | ||
animatedOnInit: false, | ||
className: '', | ||
}; | ||
|
||
/** | ||
* Retrieve a shallow copy of the default collapse config | ||
* @returns the default collapse config | ||
*/ | ||
export function getCollapseDefaultConfig(): CollapseProps { | ||
return {...defaultCollapseConfig}; | ||
} | ||
|
||
const commonCollapseConfigValidator: ConfigValidator<CollapseProps> = { | ||
horizontal: typeBoolean, | ||
}; | ||
|
||
/** | ||
* Create an CollapseWidget with given config props | ||
* @param config - an optional collapse config | ||
* @returns an CollapseWidget | ||
*/ | ||
export function createCollapse(config?: PropsConfig<CollapseProps>): CollapseWidget { | ||
const [{animatedOnInit$, animated$, visible$: requestedVisible$, onVisibleChange$, onHidden$, onShown$, horizontal$, ...stateProps}, patch] = | ||
writablesForProps(defaultCollapseConfig, config, commonCollapseConfigValidator); | ||
|
||
const currentTransitionFn$ = asWritable(computed(() => (horizontal$() ? collapseHorizontalTransition : collapseVerticalTransition))); | ||
|
||
const transition = createTransition({ | ||
props: { | ||
transition: currentTransitionFn$, | ||
visible: requestedVisible$, | ||
animated: animated$, | ||
animatedOnInit: animatedOnInit$, | ||
onVisibleChange: onVisibleChange$, | ||
onHidden: onHidden$, | ||
onShown: onShown$, | ||
}, | ||
}); | ||
|
||
const visible$ = transition.stores.visible$; | ||
const hidden$ = transition.stores.hidden$; | ||
return { | ||
...stateStores({...stateProps, visible$, hidden$, horizontal$}), | ||
patch, | ||
api: { | ||
open: transition.api.show, | ||
close: transition.api.hide, | ||
toggle: transition.api.toggle, | ||
}, | ||
directives: { | ||
transitionDirective: bindDirectiveNoArg(transition.directives.directive), | ||
}, | ||
actions: {}, | ||
}; | ||
} |
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 './collapse'; |
Oops, something went wrong.