1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 00:33:44 +00:00

[CL-499][PM-14020] compact mode (#11796)

This commit is contained in:
Will Martin
2024-11-18 16:35:49 -05:00
committed by GitHub
parent 3521c54672
commit a07b072196
28 changed files with 392 additions and 190 deletions

View File

@@ -1,3 +1 @@
export * from "./item.module";
export { BitItemHeight, BitItemHeightClass } from "./item.component";

View File

@@ -17,7 +17,7 @@ import { TypographyModule } from "../typography";
templateUrl: `item-content.component.html`,
host: {
class:
"fvw-target tw-outline-none tw-text-main hover:tw-text-main tw-no-underline hover:tw-no-underline tw-text-base tw-py-2 tw-px-4 tw-bg-transparent tw-w-full tw-border-none tw-flex tw-gap-4 tw-items-center tw-justify-between",
"fvw-target tw-outline-none tw-text-main hover:tw-text-main tw-no-underline hover:tw-no-underline tw-text-base tw-py-2 tw-px-4 bit-compact:tw-py-1.5 bit-compact:tw-px-2 tw-bg-transparent tw-w-full tw-border-none tw-flex tw-gap-4 tw-items-center tw-justify-between",
},
changeDetection: ChangeDetectionStrategy.OnPush,
})

View File

@@ -1,20 +1,11 @@
<div
class="tw-box-border tw-overflow-auto tw-flex tw-bg-background [&:has(.item-main-content_button:hover,.item-main-content_a:hover)]:tw-cursor-pointer [&:has(.item-main-content_button:hover,.item-main-content_a:hover)]:tw-bg-primary-100 tw-text-main tw-border-solid tw-border-b tw-border-0 [&:not(bit-layout_*)]:tw-rounded-lg tw-mb-1.5"
[ngClass]="
focusVisibleWithin()
? 'tw-z-10 tw-rounded tw-outline-none tw-ring-2 tw-ring-primary-600 tw-border-transparent'
: 'tw-border-b-shadow'
"
>
<bit-item-action class="item-main-content tw-block tw-flex-1 tw-overflow-hidden">
<ng-content></ng-content>
</bit-item-action>
<bit-item-action class="item-main-content tw-flex tw-flex-1 tw-overflow-hidden">
<ng-content></ng-content>
</bit-item-action>
<div
#endSlot
class="tw-p-2 tw-flex tw-gap-1 tw-items-center"
[hidden]="endSlot.childElementCount === 0"
>
<ng-content select="[slot=end]"></ng-content>
</div>
<div
#endSlot
class="tw-p-2 tw-flex tw-gap-1 tw-items-center"
[hidden]="endSlot.childElementCount === 0"
>
<ng-content select="[slot=end]"></ng-content>
</div>

View File

@@ -1,24 +1,16 @@
import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, Component, HostListener, signal } from "@angular/core";
import {
ChangeDetectionStrategy,
Component,
HostBinding,
HostListener,
signal,
} from "@angular/core";
import { A11yRowDirective } from "../a11y/a11y-row.directive";
import { ItemActionComponent } from "./item-action.component";
/**
* The class used to set the height of a bit item's inner content.
*/
export const BitItemHeightClass = `tw-h-[52px]`;
/**
* The height of a bit item in pixels. Includes any margin, padding, or border. Used by the virtual scroll
* to estimate how many items can be displayed at once and how large the virtual container should be.
* Needs to be updated if the item height or spacing changes.
*
* 52px + 6px bottom margin + 1px border = 59px
*/
export const BitItemHeight = 59;
@Component({
selector: "bit-item",
standalone: true,
@@ -26,6 +18,10 @@ export const BitItemHeight = 59;
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: "item.component.html",
providers: [{ provide: A11yRowDirective, useExisting: ItemComponent }],
host: {
class:
"tw-block tw-box-border tw-overflow-auto tw-flex tw-bg-background [&:has(.item-main-content_button:hover,.item-main-content_a:hover)]:tw-cursor-pointer [&:has(.item-main-content_button:hover,.item-main-content_a:hover)]:tw-bg-primary-100 tw-text-main tw-border-solid tw-border-b tw-border-0 [&:not(bit-layout_*)]:tw-rounded-lg bit-compact:[&:not(bit-layout_*)]:tw-rounded-none bit-compact:[&:not(bit-layout_*)]:last-of-type:tw-rounded-b-lg bit-compact:[&:not(bit-layout_*)]:first-of-type:tw-rounded-t-lg tw-min-h-9 tw-mb-1.5 bit-compact:tw-mb-0",
},
})
export class ItemComponent extends A11yRowDirective {
/**
@@ -40,4 +36,14 @@ export class ItemComponent extends A11yRowDirective {
onFocusOut() {
this.focusVisibleWithin.set(false);
}
@HostBinding("class") get classList(): string[] {
return [
this.focusVisibleWithin()
? "tw-z-10 tw-rounded tw-outline-none tw-ring-2 bit-compact:tw-ring-inset tw-ring-primary-600 tw-border-transparent".split(
" ",
)
: "tw-border-b-shadow",
].flat();
}
}

View File

@@ -16,7 +16,7 @@ import { I18nMockService } from "../utils/i18n-mock.service";
import { ItemActionComponent } from "./item-action.component";
import { ItemContentComponent } from "./item-content.component";
import { ItemGroupComponent } from "./item-group.component";
import { ItemComponent, BitItemHeight, BitItemHeightClass } from "./item.component";
import { ItemComponent } from "./item.component";
export default {
title: "Component Library/Item",
@@ -152,127 +152,129 @@ export const TextOverflow: Story = {
}),
};
const multipleActionListTemplate = /*html*/ `
<bit-item-group aria-label="Multiple Action List">
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
</bit-item-group>
`;
export const MultipleActionList: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<bit-item-group aria-label="Multiple Action List">
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
<bit-item>
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
Foo
<span slot="secondary">Bar</span>
</button>
<ng-container slot="end">
<bit-item-action>
<button type="button" bitBadge variant="primary">Auto-fill</button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-clone" size="small"></button>
</bit-item-action>
<bit-item-action>
<button type="button" bitIconButton="bwi-ellipsis-v" size="small"></button>
</bit-item-action>
</ng-container>
</bit-item>
</bit-item-group>
`,
template: multipleActionListTemplate,
}),
};
@@ -346,18 +348,27 @@ export const SingleActionWithBadge: Story = {
}),
};
export const CompactMode: Story = {
render: (args) => ({
props: args,
template: /*html*/ `
<div class="tw-bit-compact">
${multipleActionListTemplate}
</div>
`,
}),
};
export const VirtualScrolling: Story = {
render: (_args) => ({
props: {
data: Array.from(Array(100000).keys()),
itemSize: BitItemHeight,
itemClass: BitItemHeightClass,
},
template: /*html*/ `
<cdk-virtual-scroll-viewport [itemSize]="itemSize" class="tw-h-[500px]">
<cdk-virtual-scroll-viewport [itemSize]="59" class="tw-h-[500px]">
<bit-item-group aria-label="Virtual Scrolling">
<bit-item *cdkVirtualFor="let item of data">
<button bit-item-content [ngClass]="itemClass">
<button bit-item-content>
<i slot="start" class="bwi bwi-globe tw-text-2xl tw-text-muted" aria-hidden="true"></i>
{{ item }}
</button>