Skip to content

Commit

Permalink
feat: slots select (#818)
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinderoubaix authored Jun 26, 2024
1 parent e2f39b2 commit 24ace1b
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 31 deletions.
4 changes: 2 additions & 2 deletions angular/bootstrap/src/agnos-ui-angular.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
PaginationPreviousDirective,
} from './components/pagination/pagination.component';
import {RatingComponent, RatingStarDirective} from './components/rating/rating.component';
import {SelectBadgeLabelDirective, SelectComponent, SelectItemDirective} from './components/select/select.component';
import {SelectBadgeLabelDirective, SelectComponent, SelectItemLabelDirective} from './components/select/select.component';
import {AlertBodyDirective, AlertComponent, AlertStructureDirective} from './components/alert/alert.component';
import {
AccordionDirective,
Expand All @@ -37,7 +37,7 @@ const components = [
SlotDirective,
SelectComponent,
SelectBadgeLabelDirective,
SelectItemDirective,
SelectItemLabelDirective,
UseDirective,
UseMultiDirective,
RatingComponent,
Expand Down
20 changes: 10 additions & 10 deletions angular/bootstrap/src/components/select/select.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export class SelectBadgeLabelDirective<Item> {
}
}

@Directive({selector: 'ng-template[auSelectItem]', standalone: true})
export class SelectItemDirective<Item> {
@Directive({selector: 'ng-template[auSelectItemLabel]', standalone: true})
export class SelectItemLabelDirective<Item> {
public templateRef = inject(TemplateRef<SelectItemContext<Item>>);
static ngTemplateContextGuard<Item>(_dir: SelectItemDirective<Item>, context: unknown): context is SelectItemContext<Item> {
static ngTemplateContextGuard<Item>(_dir: SelectItemLabelDirective<Item>, context: unknown): context is SelectItemContext<Item> {
return true;
}
}
Expand All @@ -47,7 +47,7 @@ export class SelectItemDirective<Item> {
@if (state.selectedContexts; as selectedContexts) {
@for (itemContext of selectedContexts; track itemCtxTrackBy($index, itemContext)) {
<div [auUse]="[_widget.directives.badgeAttributesDirective, itemContext]">
<ng-template [auSlot]="state.slotBadgeLabel" [auSlotProps]="{state, widget, itemContext}"></ng-template>
<ng-template [auSlot]="state.badgeLabel" [auSlotProps]="{state, widget, itemContext}"></ng-template>
</div>
}
}
Expand Down Expand Up @@ -76,7 +76,7 @@ export class SelectItemDirective<Item> {
[auUse]="[_widget.directives.itemAttributesDirective, itemContext]"
[class.text-bg-primary]="itemContext === state.highlighted"
>
<ng-template [auSlot]="state.slotItem" [auSlotProps]="{state, widget, itemContext}"></ng-template>
<ng-template [auSlot]="state.itemLabel" [auSlotProps]="{state, widget, itemContext}"></ng-template>
</li>
}
</ul>
Expand Down Expand Up @@ -151,15 +151,15 @@ export class SelectComponent<Item> extends BaseWidgetDirective<SelectWidget<Item
* The template to override the way each badge on the left of the input is displayed.
* This define the content of the badge inside the badge container.
*/
@Input('auSlotBadgeLabel') slotBadgeLabel: SlotContent<SelectItemContext<Item>>;
@Input('auBadgeLabel') badgeLabel: SlotContent<SelectItemContext<Item>>;
@ContentChild(SelectBadgeLabelDirective, {static: false}) slotSelectBadgeLabelFromContent: SelectBadgeLabelDirective<Item> | undefined;

/**
* The template to override the way each item is displayed in the list.
* This define the content of the badge inside the badge container.
*/
@Input('auSlotItem') slotItem: SlotContent<SelectItemContext<Item>>;
@ContentChild(SelectItemDirective, {static: false}) slotSelectItemFromContent: SelectItemDirective<Item> | undefined;
@Input('auItemLabel') itemLabel: SlotContent<SelectItemContext<Item>>;
@ContentChild(SelectItemLabelDirective, {static: false}) slotSelectItemLabelFromContent: SelectItemLabelDirective<Item> | undefined;

/**
* Callback called when the text filter change
Expand Down Expand Up @@ -210,8 +210,8 @@ export class SelectComponent<Item> extends BaseWidgetDirective<SelectWidget<Item

ngAfterContentChecked(): void {
this._widget.patchSlots({
slotBadgeLabel: this.slotSelectBadgeLabelFromContent?.templateRef,
slotItem: this.slotSelectItemFromContent?.templateRef,
badgeLabel: this.slotSelectBadgeLabelFromContent?.templateRef,
itemLabel: this.slotSelectItemLabelFromContent?.templateRef,
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function getHtmlText(html: string) {
(click)="widget.actions.onRemoveBadgeClick($event, itemContext.item)"
></button>
</ng-template>
<ng-template auSelectItem let-widget="widget" let-itemContext="itemContext">
<ng-template auSelectItemLabel let-widget="widget" let-itemContext="itemContext">
<div class="fw-bold">{{ itemContext.item.title }}</div>
<div class="text-wrap wiki-desc">{{ itemContext.item.snippet }}</div>
</ng-template>
Expand Down
8 changes: 4 additions & 4 deletions core-bootstrap/src/components/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ interface SelectExtraProps<Item> {
* The template to override the way each badge on the left of the input is displayed.
* This define the content of the badge inside the badge container.
*/
slotBadgeLabel: SlotContent<SelectItemContext<Item>>;
badgeLabel: SlotContent<SelectItemContext<Item>>;

/**
* The template to override the way each item is displayed in the list.
* This define the content of the badge inside the badge container.
*/
slotItem: SlotContent<SelectItemContext<Item>>;
itemLabel: SlotContent<SelectItemContext<Item>>;
}

export interface SelectState<Item> extends CoreState<Item>, SelectExtraProps<Item> {}
Expand All @@ -44,8 +44,8 @@ export interface SelectProps<Item> extends CoreProps<Item>, SelectExtraProps<Ite
export type SelectWidget<Item> = Widget<SelectProps<Item>, SelectState<Item>, SelectApi<Item>, SelectActions<Item>, SelectDirectives<Item>>;

const defaultConfigExtraProps: SelectExtraProps<any> = {
slotBadgeLabel: ({itemContext}: SelectItemContext<any>) => itemContext.item,
slotItem: ({itemContext}: SelectItemContext<any>) => itemContext.item,
badgeLabel: ({itemContext}: SelectItemContext<any>) => itemContext.item,
itemLabel: ({itemContext}: SelectItemContext<any>) => itemContext.item,
};

/**
Expand Down
8 changes: 4 additions & 4 deletions react/bootstrap/src/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function DefaultItem<Item>(slotContext: SelectItemContext<Item>) {
function BadgeContainer<Item>({itemContext, slotContext}: {itemContext: ItemContext<Item>; slotContext: SelectContext<Item>}) {
return (
<div {...useDirective(slotContext.widget.directives.badgeAttributesDirective, itemContext)}>
<Slot slotContent={slotContext.state.slotBadgeLabel} props={{...slotContext, itemContext}} />
<Slot slotContent={slotContext.state.badgeLabel} props={{...slotContext, itemContext}} />
</div>
);
}
Expand All @@ -40,7 +40,7 @@ function SelectItem<Item>({itemContext, slotContext}: {itemContext: ItemContext<
const classname = classNames('dropdown-item', 'position-relative', {'text-bg-primary': itemContext === slotContext.state.highlighted});
return (
<li className={classname} {...useDirective(slotContext.widget.directives.itemAttributesDirective, itemContext)}>
<Slot slotContent={slotContext.state.slotItem} props={{...slotContext, itemContext}} />
<Slot slotContent={slotContext.state.itemLabel} props={{...slotContext, itemContext}} />
</li>
);
}
Expand All @@ -59,8 +59,8 @@ function Rows<Item>({slotContext}: {slotContext: SelectContext<Item>; menuId: st
}

const defaultConfig: Partial<SelectProps<any>> = {
slotBadgeLabel: DefaultBadge,
slotItem: DefaultItem,
badgeLabel: DefaultBadge,
itemLabel: DefaultItem,
};

export function Select<Item>(props: Partial<SelectProps<Item>>) {
Expand Down
6 changes: 3 additions & 3 deletions react/demo/src/bootstrap/samples/select/Custom.route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const SlotBadgeLabel = ({itemContext, widget}: SelectItemContext<WikiResult>) =>
);
};

const SlotItem = ({itemContext}: SelectItemContext<WikiResult>) => {
const SlotItemLabel = ({itemContext}: SelectItemContext<WikiResult>) => {
const item = itemContext.item;
return (
<>
Expand Down Expand Up @@ -83,8 +83,8 @@ const Custom = () => {
navSelector={navSelector}
onFilterTextChange={onFilterTextChange}
onSelectedChange={onSelectedChange}
slotBadgeLabel={SlotBadgeLabel}
slotItem={SlotItem}
badgeLabel={SlotBadgeLabel}
itemLabel={SlotItemLabel}
badgeClassName="badge text-bg-light d-flex align-items-center"
/>
<span className="fw-bold">Selection: </span>
Expand Down
16 changes: 10 additions & 6 deletions svelte/bootstrap/src/components/select/Select.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
});
export const api: SelectApi<Item> = widget.api;
const {
stores: {id$, ariaLabel$, highlighted$, open$, selectedContexts$, slotBadgeLabel$, slotItem$, visibleItems$, className$, filterText$},
stores: {id$, ariaLabel$, highlighted$, open$, selectedContexts$, badgeLabel$, itemLabel$, visibleItems$, className$, filterText$},
state$,
actions: {onInput, onInputKeydown},
directives: {
Expand All @@ -54,13 +54,15 @@
<div use:hasFocusDirective use:inputContainerDirective class="d-flex align-items-center flex-wrap gap-1">
{#each $selectedContexts$ as itemContext (itemContext.id)}
<div use:badgeAttributesDirective={itemContext}>
<Slot slotContent={$slotBadgeLabel$} props={{state: $state$, widget, itemContext}} let:component let:props>
<Slot slotContent={$badgeLabel$} props={{state: $state$, widget, itemContext}} let:component let:props>
<svelte:fragment slot="slot" let:props><slot name="badgeLabel" {...props} /></svelte:fragment>
<svelte:component this={component} {...props}>
<svelte:fragment slot="badgeLabel" let:itemContext let:state let:widget
><slot name="badgeLabel" {itemContext} {state} {widget} /></svelte:fragment
>
<svelte:fragment slot="item" let:itemContext let:state let:widget><slot name="item" {itemContext} {state} {widget} /></svelte:fragment>
<svelte:fragment slot="itemLabel" let:itemContext let:state let:widget
><slot name="itemLabel" {itemContext} {state} {widget} /></svelte:fragment
>
</svelte:component>
</Slot>
</div>
Expand All @@ -84,13 +86,15 @@
{#each $visibleItems$ as itemContext (itemContext.id)}
{@const isHighlighted = itemContext === $highlighted$}
<li class="dropdown-item position-relative" class:text-bg-primary={isHighlighted} use:itemAttributesDirective={itemContext}>
<Slot slotContent={$slotItem$} props={{state: $state$, widget, itemContext}} let:component let:props>
<svelte:fragment slot="slot" let:props><slot name="item" {...props} /></svelte:fragment>
<Slot slotContent={$itemLabel$} props={{state: $state$, widget, itemContext}} let:component let:props>
<svelte:fragment slot="slot" let:props><slot name="itemLabel" {...props} /></svelte:fragment>
<svelte:component this={component} {...props}>
<svelte:fragment slot="badgeLabel" let:itemContext let:state let:widget
><slot name="badgeLabel" {itemContext} {state} {widget} /></svelte:fragment
>
<svelte:fragment slot="item" let:itemContext let:state let:widget><slot name="item" {itemContext} {state} {widget} /></svelte:fragment>
<svelte:fragment slot="itemLabel" let:itemContext let:state let:widget
><slot name="itemLabel" {itemContext} {state} {widget} /></svelte:fragment
>
</svelte:component>
</Slot>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
on:click={(e) => widget.actions.onRemoveBadgeClick(e, itemContext.item)}
></button>
</svelte:fragment>
<label for={'' + itemContext.id} slot="item" let:itemContext>
<label for={'' + itemContext.id} slot="itemLabel" let:itemContext>
{@const item = itemContext.item}
<div class="fw-bold">{item.title}</div>
<div class="text-wrap wiki-desc">{item.snippet}</div>
Expand Down

0 comments on commit 24ace1b

Please sign in to comment.