Skip to content

Commit

Permalink
feat: transition directive with no arg (#984)
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinderoubaix authored Oct 29, 2024
1 parent 648c8c6 commit 926df6a
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ChangeDetectionStrategy, Component, booleanAttribute, input} from '@angular/core';
import {ChangeDetectionStrategy, Component, effect, input, model} from '@angular/core';
import {UseDirective, collapseVerticalTransition, createTransition, toAngularSignal} from '@agnos-ui/angular-bootstrap';

@Component({
Expand All @@ -15,19 +15,19 @@ import {UseDirective, collapseVerticalTransition, createTransition, toAngularSig
(click)="transition.api.toggle()"
class="btn toggle-button"
aria-controls="collapse-content"
[attr.aria-expanded]="state().visible"
[attr.aria-expanded]="expanded()"
>
{{ headerText() }}
<span class="ms-1 collapse-icon" [class.expanded]="state().visible">
<span class="ms-1 collapse-icon" [class.expanded]="expanded()">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 100 100">
<rect class="horizontal" x="20" y="45" width="60" height="10" fill="currentColor" />
<rect class="vertical" x="45" y="20" width="10" height="60" fill="currentColor" />
</svg>
</span>
</button>
</div>
@if (!state().hidden) {
<div [auUse]="[transition.directives.directive, {visible: expanded()}]" id="collapse-content">
@if (!hidden()) {
<div [auUse]="transition.directives.directive" id="collapse-content">
<div class="card-body">
<ng-content />
</div>
Expand All @@ -38,13 +38,23 @@ import {UseDirective, collapseVerticalTransition, createTransition, toAngularSig
styles: "@import '@agnos-ui/common/samples/transition/collapse.scss';",
})
export default class CollapseComponent {
readonly headerText = input<string>();
readonly expanded = model(false);

readonly transition = createTransition({
props: {
transition: collapseVerticalTransition,
onVisibleChange: (visible) => this.expanded.set(visible),
},
});
readonly state = toAngularSignal(this.transition.state$);
readonly hidden = toAngularSignal(this.transition.stores.hidden$);

readonly headerText = input<string>();
readonly expanded = input(false, {transform: booleanAttribute});
constructor() {
effect(
() => {
this.transition.patch({visible: this.expanded()});
},
{allowSignalWrites: true},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import CollapseComponent from './collapse.component';
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CollapseComponent],
template: ` <app-collapse headerText="Toggle content" expanded> Content to display / hide. </app-collapse> `,
template: ` <app-collapse headerText="Toggle content" [expanded]="true"> Content to display / hide. </app-collapse> `,
})
export default class CollapseDemoComponent {}
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@ const paramRemoveFromDom$ = writable(true);
</ul>
@if ((paramRemoveFromDom$ | async) === false || state().hidden === false) {
<div
[auUse]="[transition.directives.directive, {transition: (paramTransition$ | async)!, animated: (paramAnimated$ | async)!}]"
style="max-width: 300px;"
>
<div [auUse]="transition.directives.directive" style="max-width: 300px;">
<div class="card" style="width: 300px;">
<div class="card-body">You can collapse this card by clicking Toggle</div>
</div>
Expand All @@ -117,6 +114,7 @@ export class InnerComponent {
animatedOnInit: paramAnimatedOnInit$,
animated: paramAnimated$,
visible: paramVisible$,
transition: paramTransition$,
},
});
state = toAngularSignal(this.transition.state$);
Expand Down
4 changes: 2 additions & 2 deletions core-bootstrap/src/components/collapse/collapse.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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, createAttributesDirective, mergeDirectives} from '@agnos-ui/core/utils/directive';
import {createAttributesDirective, mergeDirectives} from '@agnos-ui/core/utils/directive';
import {typeBoolean, typeFunction, typeString} from '@agnos-ui/core/utils/writables';
import {collapseHorizontalTransition, collapseVerticalTransition} from '../../services/transitions/collapse';
import {asWritable, computed} from '@amadeus-it-group/tansu';
Expand Down Expand Up @@ -178,7 +178,7 @@ export function createCollapse(config?: PropsConfig<CollapseProps>): CollapseWid
},
directives: {
collapseDirective: mergeDirectives(
bindDirectiveNoArg(transition.directives.directive),
transition.directives.directive,
createAttributesDirective(() => ({
attributes: {
id: computed(() => id$() || undefined),
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/accordion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {asWritable, computed, readable, writable} from '@amadeus-it-group/tansu'
import {noop} from '../../utils/internal/func';
import type {WidgetsCommonPropsAndState} from '../commonProps';
import {typeBoolean, typeFunction, typeString} from '../../utils/writables';
import {bindDirectiveNoArg, createAttributesDirective, directiveSubscribe, mergeDirectives, registrationArray} from '../../utils/directive';
import {createAttributesDirective, directiveSubscribe, mergeDirectives, registrationArray} from '../../utils/directive';
import {generateId} from '../../utils/internal/dom';

function adjustItemsCloseOthers(items: AccordionItemWidget[], openItems: string[], oldOpen?: string): AccordionItemWidget[] {
Expand Down Expand Up @@ -446,7 +446,7 @@ export function createAccordionItem(config?: PropsConfig<AccordionItemProps>): A
},
},
}));
const transitionDirective = bindDirectiveNoArg(transition.directives.directive);
const transitionDirective = transition.directives.directive;
const bodyContainerAttrsDirective = createAttributesDirective(() => ({
attributes: {
id: computed(() => `${id$()}-body-container`),
Expand Down
3 changes: 1 addition & 2 deletions core/src/components/alert/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type {WidgetsCommonPropsAndState} from '../commonProps';
import type {ConfigValidator, Directive, PropsConfig, Widget} from '../../types';
import {noop} from '../../utils/internal/func';
import {stateStores, writablesForProps} from '../../utils/stores';
import {bindDirectiveNoArg} from '../../utils/directive';
import {typeBoolean, typeFunction, typeString} from '../../utils/writables';

export interface CommonAlertCommonPropsAndState extends WidgetsCommonPropsAndState {
Expand Down Expand Up @@ -198,7 +197,7 @@ export function createCommonAlert(config?: PropsConfig<CommonAlertProps>): Commo
close: transition.api.hide,
},
directives: {
transitionDirective: bindDirectiveNoArg(transition.directives.directive),
transitionDirective: transition.directives.directive,
},
};
}
10 changes: 2 additions & 8 deletions core/src/components/modal/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {noop} from '../../utils/internal/func';
import {removeScrollbars, revertScrollbars} from '../../utils/internal/scrollbars';
import {
bindDirective,
bindDirectiveNoArg,
browserDirective,
createAttributesDirective,
directiveSubscribe,
Expand Down Expand Up @@ -472,13 +471,8 @@ export function createModal(config$?: PropsConfig<ModalProps>): ModalWidget {
directives: {
modalPortalDirective,
backdropPortalDirective,
backdropDirective: mergeDirectives(bindDirectiveNoArg(backdropTransition.directives.directive), backdropAttributeDirective),
modalDirective: mergeDirectives(
bindDirectiveNoArg(modalTransition.directives.directive),
sliblingsInert,
directiveSubscribe(action$),
modalAttributeDirective,
),
backdropDirective: mergeDirectives(backdropTransition.directives.directive, backdropAttributeDirective),
modalDirective: mergeDirectives(modalTransition.directives.directive, sliblingsInert, directiveSubscribe(action$), modalAttributeDirective),
closeButtonDirective,
dialogDirective: bindDirective(
browserDirective((dialog: HTMLDialogElement, visible: boolean) => {
Expand Down
30 changes: 24 additions & 6 deletions core/src/services/transitions/baseTransitions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe(`createTransition`, () => {
onVisibleChange,
},
});
const directiveInstance = transitionInstance.directives.directive(element, {});
const directiveInstance = transitionInstance.directives.directive(element);
await transitionInstance.api.show();
events.push('here');
await transitionInstance.api.hide();
Expand Down Expand Up @@ -479,23 +479,24 @@ describe(`createTransition`, () => {
events.push(`state = ${JSON.stringify(state)}`);
});
events.push('beforeCallingDirective1');
let directiveInstance = transitionInstance.directives.directive(element, {});
let directiveInstance = transitionInstance.directives.directive(element);
events.push('afterCallingDirective1');
await promiseFromStore(transitionInstance.stores.shown$).promise;
events.push('beforeDestroyingDirective1');
directiveInstance?.destroy?.();
events.push('afterDestroyingDirective1');
element = <HTMLElement>{id: 'domEl2'};
events.push('beforeCallingDirective2');
directiveInstance = transitionInstance.directives.directive(element, {});
directiveInstance = transitionInstance.directives.directive(element);
events.push('afterCallingDirective2');
await promiseFromStore(transitionInstance.stores.shown$).promise;
events.push('beforeDestroyingDirective2');
directiveInstance?.destroy?.();
events.push('afterDestroyingDirective2');
element = <HTMLElement>{id: 'domEl3'};
events.push('beforeCallingDirective3');
directiveInstance = transitionInstance.directives.directive(element, {visible: false});
transitionInstance.patch({visible: false});
directiveInstance = transitionInstance.directives.directive(element);
events.push('afterCallingDirective3');
await promiseFromStore(transitionInstance.stores.hidden$).promise;
events.push('beforeDestroyingDirective3');
Expand Down Expand Up @@ -553,6 +554,14 @@ describe(`createTransition`, () => {
'afterDestroyingDirective2',
'beforeCallingDirective3',
'onVisibleChange:false',
`state = ${JSON.stringify({
visible: false,
element: null,
elementPresent: false,
transitioning: false,
shown: false,
hidden: true,
})}`,
`transitionStart:3:domEl3:hide:anim=false:ctxt=3`,
`state = ${JSON.stringify({
visible: false,
Expand Down Expand Up @@ -594,15 +603,16 @@ describe(`createTransition`, () => {
events.push(`state = ${JSON.stringify(state)}`);
});
events.push('beforeCallingDirective1');
let directiveInstance = transitionInstance.directives.directive(element, {});
let directiveInstance = transitionInstance.directives.directive(element);
events.push('afterCallingDirective1');
await promiseFromStore(transitionInstance.stores.hidden$).promise;
events.push('beforeDestroyingDirective1');
directiveInstance?.destroy?.();
events.push('afterDestroyingDirective1');
element = <HTMLElement>{id: 'domEl2'};
events.push('beforeCallingDirective2');
directiveInstance = transitionInstance.directives.directive(element, {visible: true});
transitionInstance.patch({visible: true});
directiveInstance = transitionInstance.directives.directive(element);
events.push('afterCallingDirective2');
await promiseFromStore(transitionInstance.stores.shown$).promise;
events.push('beforeDestroyingDirective2');
Expand Down Expand Up @@ -637,6 +647,14 @@ describe(`createTransition`, () => {
'afterDestroyingDirective1',
'beforeCallingDirective2',
'onVisibleChange:true',
`state = ${JSON.stringify({
visible: true,
element: null,
elementPresent: false,
transitioning: false,
shown: false,
hidden: false,
})}`,
`transitionStart:2:domEl2:show:anim=${animated}:ctxt=2`,
`state = ${JSON.stringify({
visible: true,
Expand Down
14 changes: 3 additions & 11 deletions core/src/services/transitions/baseTransitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {ConfigValidator, Directive, PropsConfig, SSRHTMLElement, Widget} fr
import {promiseWithResolve} from '../../utils/internal/promise';
import {noop} from '../../utils/internal/func';
import {bindableDerived, stateStores, writablesForProps} from '../../utils/stores';
import {createStoreDirective, directiveSubscribe, directiveUpdate, mergeDirectives} from '../../utils/directive';
import {createStoreDirective, directiveSubscribe, mergeDirectives} from '../../utils/directive';

/**
* Function that implements a transition.
Expand Down Expand Up @@ -158,7 +158,7 @@ export interface TransitionDirectives {
/**
* the transition directive
*/
directive: Directive<void | Partial<TransitionProps>>;
directive: Directive;
}

export type TransitionWidget = Widget<TransitionProps, TransitionState, TransitionApi, TransitionDirectives>;
Expand Down Expand Up @@ -338,15 +338,7 @@ export const createTransition = (config?: PropsConfig<TransitionProps>): Transit
}
};

const directive = mergeDirectives<void | Partial<TransitionProps>>(
storeDirective,
directiveUpdate((args: void | Partial<TransitionProps>) => {
if (args) {
patch(args);
}
}),
directiveSubscribe(visibleAction$),
);
const directive = mergeDirectives(storeDirective, directiveSubscribe(visibleAction$));

return {
...stateStores({
Expand Down
3 changes: 2 additions & 1 deletion demo/src/routes/menu/CollapsibleSection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
animated: paramAnimated$,
animatedOnInit: paramAnimated$,
visible: paramVisible$,
transition: collapseVerticalTransition,
},
});
Expand All @@ -58,7 +59,7 @@
<rect class="vertical" class:expanded={$visible$} x="45" y="20" width="10" height="60" fill="currentColor" />
</svg>
</button>
<div class="contents" use:directive={{transition: collapseVerticalTransition, animated: $paramAnimated$}}>
<div class="contents" use:directive>
{@render children()}
</div>
</div>
Expand Down
25 changes: 10 additions & 15 deletions react/demo/src/bootstrap/samples/transition/Collapse.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
import {useMemo, type PropsWithChildren} from 'react';
import {type PropsWithChildren} from 'react';
import {createTransition} from '@agnos-ui/react-bootstrap/services/transitions/baseTransitions';
import {collapseVerticalTransition} from '@agnos-ui/react-bootstrap/services/transitions/bootstrap';
import {useDirective} from '@agnos-ui/react-bootstrap/utils/directive';
import type {Directive} from '@agnos-ui/react-bootstrap/types';
import '@agnos-ui/common/samples/transition/collapse.scss';
import CollapseIcon from '@agnos-ui/common/samples/transition/collapseButton.svg?react';
import {useObservable} from '@agnos-ui/react-bootstrap/utils/stores';
import {useWidget} from '@agnos-ui/react-bootstrap/utils/widget';

const CollapseContent = ({directive, children}: PropsWithChildren<{directive: Directive}>) => (
<div id="collapse-content" {...useDirective(directive)}>
<div className="card-body">{children}</div>
</div>
);

const Collapse = ({expanded, headerText, children}: PropsWithChildren<{expanded?: boolean; headerText: string}>) => {
const Collapse = ({
expanded,
onExpandedChange,
headerText,
children,
}: PropsWithChildren<{expanded?: boolean; onExpandedChange?: (expanded: boolean) => void; headerText: string}>) => {
const {
state$,
state,
directives: {directive},
api: {toggle},
} = useMemo(
() =>
createTransition({
props: {
visible: expanded,
transition: collapseVerticalTransition,
},
}),
[],
);
const state = useObservable(state$);
} = useWidget(createTransition, {visible: expanded, transition: collapseVerticalTransition, onVisibleChange: onExpandedChange});

return (
<div className="card">
Expand Down
16 changes: 12 additions & 4 deletions svelte/demo/src/bootstrap/samples/transition/Collapse.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,25 @@
import type {Snippet} from 'svelte';
import {callWidgetFactory} from '@agnos-ui/svelte-bootstrap/config';
let {headerText, expanded = false, children}: {headerText: string; expanded: boolean; children: Snippet} = $props();
let {headerText, expanded = $bindable(), children}: {headerText: string; expanded: boolean; children: Snippet} = $props();
const {
state,
api: {toggle},
directives: {directive},
} = callWidgetFactory({
factory: createTransition,
props: {
visible: expanded,
transition: collapseVerticalTransition,
get props() {
return {
visible: expanded,
transition: collapseVerticalTransition,
};
},
enablePatchChanged: true,
events: {
onVisibleChange: (val: boolean) => {
expanded = val;
},
},
});
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
animatedOnInit: paramAnimatedOnInit$,
animated: paramAnimated$,
visible: paramVisible$,
transition: paramTransition$,
},
});
Expand Down Expand Up @@ -81,7 +82,7 @@
</ul>

{#if !$paramRemoveFromDom$ || !$hidden$}
<div use:directive={{transition: $paramTransition$, animated: $paramAnimated$}} style="max-width: 300px;">
<div use:directive style="max-width: 300px;">
<div class="card" style="width: 300px;">
<div class="card-body">You can collapse this card by clicking Toggle</div>
</div>
Expand Down

0 comments on commit 926df6a

Please sign in to comment.