Skip to content

Commit

Permalink
feat(collapse): add the collapse
Browse files Browse the repository at this point in the history
  • Loading branch information
ExFlo committed Oct 10, 2024
1 parent cad0845 commit c20736d
Show file tree
Hide file tree
Showing 45 changed files with 737 additions and 15 deletions.
2 changes: 2 additions & 0 deletions angular/bootstrap/src/agnos-ui-angular.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
import {SliderComponent, SliderHandleDirective, SliderLabelDirective, SliderStructureDirective} from './components/slider/slider.component';
import {ProgressbarComponent, ProgressbarStructureDirective} from './components/progressbar/progressbar.component';
import {ToastBodyDirective, ToastComponent, ToastHeaderDirective, ToastStructureDirective} from './components/toast/toast.component';
import {CollapseDirective} from './components/collapse';
/* istanbul ignore next */
const components = [
SlotDirective,
Expand Down Expand Up @@ -75,6 +76,7 @@ const components = [
ToastStructureDirective,
ToastBodyDirective,
ToastHeaderDirective,
CollapseDirective,
];

@NgModule({
Expand Down
92 changes: 92 additions & 0 deletions angular/bootstrap/src/components/collapse/collapse.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
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 can be dismissed by the user.
* The close button (×) will be displayed and you can be notified of the event with the (close) output.
*
* @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);
},
});
}
2 changes: 2 additions & 0 deletions angular/bootstrap/src/components/collapse/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './collapse.component';
export * from './collapse.gen';
2 changes: 2 additions & 0 deletions angular/bootstrap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export type {AlertContext, AlertProps, AlertState, AlertWidget, AlertApi, AlertD
export {createAlert, getAlertDefaultConfig} from './components/alert';
export * from './components/alert';

export * from './components/collapse';

export type {
ModalContext,
ModalProps,
Expand Down
14 changes: 14 additions & 0 deletions angular/demo/bootstrap/src/app/samples/collapse/default.route.ts
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 {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type {CollapseDirective} from '@agnos-ui/angular-bootstrap';
import {AgnosUIAngularModule} from '@agnos-ui/angular-bootstrap';
import {Component, ViewChild} from '@angular/core';
import {hashChangeHook, provideHashConfig} from '../../utils';

@Component({
standalone: true,
imports: [AgnosUIAngularModule],
providers: provideHashConfig('collapse'),
template: `<div auCollapse #collapse="auCollapse">Visible content</div>`,
})
export default class PlaygroundComponent {
@ViewChild('widget') widget!: CollapseDirective;

constructor() {
hashChangeHook((_props) => {
// TODO
//this.widget._widget.patch({...undefinedConfig, ...props});
});
}
}
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 text-xl font-medium">{{ 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 angular/demo/daisyui/src/app/samples/collapse/default.route.ts
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='0' necessary is already put</p></app-collapse> `,
})
export default class DefaultAlertComponent {
onHidden() {
console.log('Hidden');
}
}
3 changes: 3 additions & 0 deletions core-bootstrap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,8 @@
"dependencies": {
"@agnos-ui/core": "0.0.0"
},
"peerDependencies": {
"@amadeus-it-group/tansu": "^1.0.0"
},
"sideEffects": false
}
24 changes: 24 additions & 0 deletions core-bootstrap/src/components/collapse/collapse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type {CommonCollapseApi, CommonCollapseDirectives, CommonCollapseProps, CommonCollapseState} from './common';
import {createCommonCollapse, getCommonCollapseDefaultConfig} from './common';
import type {Widget, WidgetFactory} from '@agnos-ui/core/types';

export interface CollapseState extends CommonCollapseState {}
export interface CollapseProps extends CommonCollapseProps {}
export interface CollapseApi extends CommonCollapseApi {}
export interface CollapseDirectives extends CommonCollapseDirectives {}
export type CollapseWidget = Widget<CollapseProps, CollapseState, CollapseApi, object, CollapseDirectives>;

/**
* Retrieve a shallow copy of the default collapse config
* @returns the default collapse config
*/
export function getCollapseDefaultConfig(): CollapseProps {
return {...getCommonCollapseDefaultConfig()};
}

/**
* Create an CollapseWidget with given config props
* @param config - an optional collapse config
* @returns an CollapseWidget
*/
export const createCollapse: WidgetFactory<CollapseWidget> = createCommonCollapse;
Loading

0 comments on commit c20736d

Please sign in to comment.