mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[CL-712] Update icon button, components using it, and affected virtual scroll heights (#15683)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<div class="tw-mr-[5px] tw-mt-1">
|
||||
<div class="tw-me-2 tw-mt-1">
|
||||
<button
|
||||
*ngIf="currentAccount$ | async as currentAccount; else defaultButton"
|
||||
type="button"
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
<!--
|
||||
end padding is less than start padding to prioritize visual alignment when icon buttons are used at the end of the end slot.
|
||||
other elements used at the end of the end slot may need to add their own margin/padding to achieve visual alignment.
|
||||
-->
|
||||
<header
|
||||
class="tw-p-3 bit-compact:tw-p-2 tw-pl-4 bit-compact:tw-pl-3 tw-transition-colors tw-duration-200 tw-border-0 tw-border-b tw-border-solid"
|
||||
class="tw-py-3 bit-compact:tw-py-2 tw-pe-1 bit-compact:tw-pe-0.5 tw-transition-colors tw-duration-200 tw-border-0 tw-border-b tw-border-solid"
|
||||
[ngClass]="{
|
||||
'tw-bg-background-alt tw-border-transparent':
|
||||
this.background === 'alt' && !pageContentScrolled(),
|
||||
'tw-bg-background tw-border-secondary-300':
|
||||
(this.background === 'alt' && pageContentScrolled()) || this.background === 'default',
|
||||
'tw-ps-4 bit-compact:tw-ps-3': !showBackButton,
|
||||
'tw-ps-1 bit-compact:tw-ps-0': showBackButton,
|
||||
}"
|
||||
>
|
||||
<div class="tw-max-w-screen-sm tw-mx-auto tw-flex tw-justify-between tw-w-full">
|
||||
<div class="tw-inline-flex tw-items-center tw-gap-2 tw-h-9">
|
||||
<button
|
||||
class="-tw-ml-1"
|
||||
bitIconButton="bwi-angle-left"
|
||||
type="button"
|
||||
*ngIf="showBackButton"
|
||||
|
||||
@@ -117,7 +117,7 @@ class MockPopoutButtonComponent {}
|
||||
@Component({
|
||||
selector: "mock-current-account",
|
||||
template: `
|
||||
<button class="tw-bg-transparent tw-border-none" type="button">
|
||||
<button class="tw-bg-transparent tw-border-none tw-p-0 tw-me-1" type="button">
|
||||
<bit-avatar text="Ash Ketchum" size="small"></bit-avatar>
|
||||
</button>
|
||||
`,
|
||||
@@ -654,7 +654,7 @@ export const WithVirtualScrollChild: Story = {
|
||||
<bit-section>
|
||||
@defer (on immediate) {
|
||||
<bit-item-group aria-label="Mock Vault Items">
|
||||
<cdk-virtual-scroll-viewport itemSize="61" bitScrollLayout>
|
||||
<cdk-virtual-scroll-viewport itemSize="59" bitScrollLayout>
|
||||
<bit-item *cdkVirtualFor="let item of data; index as i">
|
||||
<button type="button" bit-item-content>
|
||||
<i
|
||||
|
||||
@@ -89,8 +89,8 @@ export class GroupsComponent {
|
||||
protected searchControl = new FormControl("");
|
||||
|
||||
// Fixed sizes used for cdkVirtualScroll
|
||||
protected rowHeight = 52;
|
||||
protected rowHeightClass = `tw-h-[52px]`;
|
||||
protected rowHeight = 50;
|
||||
protected rowHeightClass = `tw-h-[50px]`;
|
||||
|
||||
protected ModalTabType = GroupAddEditTabType;
|
||||
private refreshGroups$ = new BehaviorSubject<void>(null);
|
||||
|
||||
@@ -111,8 +111,8 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
protected showUserManagementControls$: Observable<boolean>;
|
||||
|
||||
// Fixed sizes used for cdkVirtualScroll
|
||||
protected rowHeight = 69;
|
||||
protected rowHeightClass = `tw-h-[69px]`;
|
||||
protected rowHeight = 66;
|
||||
protected rowHeightClass = `tw-h-[66px]`;
|
||||
|
||||
private organizationUsersCount = 0;
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-ellipsis-v"
|
||||
buttonType="secondary"
|
||||
[bitMenuTriggerFor]="appListDropdown"
|
||||
class="tw-border-0 tw-bg-transparent tw-p-0"
|
||||
></button>
|
||||
|
||||
@@ -28,8 +28,8 @@ import { VaultItem } from "./vault-item";
|
||||
import { VaultItemEvent } from "./vault-item-event";
|
||||
|
||||
// Fixed manual row height required due to how cdk-virtual-scroll works
|
||||
export const RowHeight = 75.5;
|
||||
export const RowHeightClass = `tw-h-[75.5px]`;
|
||||
export const RowHeight = 75;
|
||||
export const RowHeightClass = `tw-h-[75px]`;
|
||||
|
||||
const MaxSelectionCount = 500;
|
||||
|
||||
|
||||
@@ -52,8 +52,8 @@ export class MembersComponent extends BaseMembersComponent<ProviderUser> {
|
||||
dataSource = new MembersTableDataSource();
|
||||
loading = true;
|
||||
providerId: string;
|
||||
rowHeight = 69;
|
||||
rowHeightClass = `tw-h-[69px]`;
|
||||
rowHeight = 70;
|
||||
rowHeightClass = `tw-h-[70px]`;
|
||||
status: ProviderUserStatusType = null;
|
||||
|
||||
userStatusType = ProviderUserStatusType;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div
|
||||
class="tw-rounded-2xl tw-bg-primary-100 tw-border-primary-600 tw-border-solid tw-border tw-p-4 tw-pt-3 tw-flex tw-flex-col tw-gap-2 tw-mb-4"
|
||||
class="tw-rounded-2xl tw-bg-primary-100 tw-border-primary-600 tw-border-solid tw-border tw-p-4 tw-pt-2 tw-flex tw-flex-col tw-gap-2 tw-mb-4"
|
||||
>
|
||||
<div class="tw-flex tw-justify-between tw-items-start tw-flex-grow">
|
||||
<div>
|
||||
@@ -20,6 +20,7 @@
|
||||
(click)="handleDismiss()"
|
||||
[attr.title]="'close' | i18n"
|
||||
[attr.aria-label]="'close' | i18n"
|
||||
class="-tw-me-2"
|
||||
></button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ const template = `
|
||||
<button class="tw-me-2" type="button" buttonType="secondary" bitButton bitFormButton>Cancel</button>
|
||||
<button class="tw-me-2" type="button" buttonType="danger" bitButton bitFormButton [bitAction]="delete">Delete</button>
|
||||
<button class="tw-me-2" type="button" buttonType="secondary" bitButton bitFormButton [disabled]="true">Disabled</button>
|
||||
<button class="tw-me-2" type="button" buttonType="secondary" bitIconButton="bwi-star" bitFormButton [bitAction]="delete">Delete</button>
|
||||
<button class="tw-me-2" type="button" buttonType="muted" bitIconButton="bwi-star" bitFormButton [bitAction]="delete">Delete</button>
|
||||
</form>`;
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div
|
||||
class="tw-flex tw-items-center tw-gap-2 tw-p-2 tw-ps-4 tw-text-main tw-border-transparent tw-bg-clip-padding tw-border-solid tw-border-b tw-border-0"
|
||||
class="tw-flex tw-items-center tw-gap-4 tw-p-2 tw-ps-4 tw-text-main tw-border-transparent tw-bg-clip-padding tw-border-solid tw-border-b tw-border-0"
|
||||
[ngClass]="bannerClass"
|
||||
[attr.role]="useAlertRole() ? 'status' : null"
|
||||
[attr.aria-live]="useAlertRole() ? 'polite' : null"
|
||||
@@ -14,11 +14,10 @@
|
||||
<!-- Overriding hover and focus-visible colors for a11y against colored background -->
|
||||
@if (showClose()) {
|
||||
<button
|
||||
class="hover:tw-border-text-main focus-visible:before:tw-ring-text-main"
|
||||
type="button"
|
||||
bitIconButton="bwi-close"
|
||||
buttonType="main"
|
||||
size="default"
|
||||
size="small"
|
||||
(click)="onClose.emit()"
|
||||
[attr.title]="'close' | i18n"
|
||||
[attr.aria-label]="'close' | i18n"
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
type="button"
|
||||
[attr.aria-label]="'removeItem' | i18n: label"
|
||||
[disabled]="disabled"
|
||||
class="tw-bg-transparent hover:tw-bg-transparent tw-outline-none tw-rounded-full tw-py-0.5 tw-px-1 tw-me-1 tw-text-[color:inherit] tw-text-[length:inherit] tw-border-solid tw-border tw-border-transparent hover:tw-border-text-contrast hover:disabled:tw-border-transparent tw-flex tw-items-center tw-justify-center focus-visible:tw-ring-2 tw-ring-text-contrast focus-visible:hover:tw-border-transparent"
|
||||
class="tw-bg-transparent hover:tw-bg-hover-contrast tw-outline-none tw-rounded-full tw-py-0.5 tw-px-1 tw-me-1 tw-text-[color:inherit] tw-text-[length:inherit] tw-border-solid tw-border tw-border-transparent tw-flex tw-items-center tw-justify-center focus-visible:tw-ring-2 tw-ring-text-contrast hover:disabled:tw-bg-transparent"
|
||||
[ngClass]="{
|
||||
'tw-cursor-not-allowed': disabled,
|
||||
}"
|
||||
|
||||
@@ -93,7 +93,10 @@ class StoryDialogContentComponent {
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<bit-dialog title="Dialog Title" dialogSize="large">
|
||||
<bit-dialog
|
||||
title="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore"
|
||||
dialogSize="large"
|
||||
>
|
||||
<span bitDialogContent>
|
||||
Dialog body text goes here.
|
||||
<br />
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
<header
|
||||
class="tw-flex tw-justify-between tw-items-center tw-gap-4 tw-border-0 tw-border-b tw-border-solid"
|
||||
[ngClass]="{
|
||||
'tw-p-4': !isDrawer,
|
||||
'tw-p-6 tw-pb-4': isDrawer,
|
||||
'tw-p-4 has-[[biticonbutton]]:tw-pe-2': !isDrawer,
|
||||
'tw-px-6 tw-py-4 has-[[biticonbutton]]:tw-pe-4': isDrawer,
|
||||
'tw-border-secondary-300': showHeaderBorder,
|
||||
'tw-border-transparent': !showHeaderBorder,
|
||||
}"
|
||||
@@ -75,7 +75,7 @@
|
||||
[ngClass]="[isDrawer ? 'tw-px-6 tw-py-4' : 'tw-p-4']"
|
||||
[ngClass]="{
|
||||
'tw-px-6 tw-py-4': isDrawer,
|
||||
'tw-p-4': !isDrawer,
|
||||
'tw-p-4 has-[[biticonbutton]]:tw-pe-2': !isDrawer,
|
||||
'tw-border-secondary-300': showFooterBorder,
|
||||
'tw-border-transparent': !showFooterBorder,
|
||||
}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<header class="tw-flex tw-justify-between tw-items-center">
|
||||
<div class="tw-flex tw-items-center tw-gap-1 tw-overflow-auto">
|
||||
<header class="tw-flex tw-justify-between tw-items-center tw-gap-4">
|
||||
<div class="tw-flex tw-items-center tw-gap-4 tw-overflow-auto">
|
||||
<ng-content select="[slot=start]"></ng-content>
|
||||
<h2 bitTypography="h3" noMargin class="tw-text-main tw-mb-0 tw-truncate" [attr.title]="title()">
|
||||
{{ title() }}
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
>
|
||||
<div
|
||||
#prefixContainer
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-ps-3 tw-py-2"
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-ps-3 has-[[biticonbutton]]:tw-ps-1 tw-py-1"
|
||||
[hidden]="!prefixHasChildren()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="prefixContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
class="tw-w-full tw-relative tw-py-2 has-[bit-select]:tw-p-0 has-[bit-multi-select]:tw-p-0 has-[input:read-only:not([hidden])]:tw-bg-secondary-100 has-[textarea:read-only:not([hidden])]:tw-bg-secondary-100"
|
||||
class="tw-w-full tw-relative tw-py-1 has-[bit-select]:tw-p-0 has-[bit-multi-select]:tw-p-0 has-[input:read-only:not([hidden])]:tw-bg-secondary-100 has-[textarea:read-only:not([hidden])]:tw-bg-secondary-100"
|
||||
data-default-content
|
||||
[ngClass]="[
|
||||
prefixHasChildren() ? '' : 'tw-rounded-s-lg tw-ps-3',
|
||||
@@ -67,7 +67,7 @@
|
||||
</div>
|
||||
<div
|
||||
#suffixContainer
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-pe-3 tw-py-2"
|
||||
class="tw-flex tw-items-center tw-pe-3 has-[[biticonbutton]]:tw-pe-1 tw-py-1"
|
||||
[hidden]="!suffixHasChildren()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="suffixContent"></ng-container>
|
||||
@@ -102,11 +102,7 @@
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="defaultContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
#suffixContainer
|
||||
[hidden]="!suffixHasChildren()"
|
||||
class="tw-flex tw-items-center tw-gap-1 tw-pe-1"
|
||||
>
|
||||
<div #suffixContainer [hidden]="!suffixHasChildren()" class="tw-flex tw-items-center tw-pe-1">
|
||||
<ng-container *ngTemplateOutlet="suffixContent"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -350,9 +350,7 @@ export const ButtonInputGroup: Story = {
|
||||
<input bitInput placeholder="Placeholder" />
|
||||
<button bitSuffix bitIconButton="bwi-eye" [appA11yTitle]="'Hide Label'"></button>
|
||||
<button bitSuffix bitIconButton="bwi-clone" [appA11yTitle]="'Clone Label'"></button>
|
||||
<button bitSuffix bitLink>
|
||||
Apply
|
||||
</button>
|
||||
<button bitSuffix bitIconButton="bwi-ellipsis-v" [appA11yTitle]="'Menu Label'"></button>
|
||||
</bit-form-field>
|
||||
`,
|
||||
}),
|
||||
@@ -369,9 +367,8 @@ export const DisabledButtonInputGroup: Story = {
|
||||
<input bitInput placeholder="Placeholder" disabled />
|
||||
<button bitSuffix bitIconButton="bwi-eye" disabled [appA11yTitle]="'Hide Label'"></button>
|
||||
<button bitSuffix bitIconButton="bwi-clone" disabled [appA11yTitle]="'Clone Label'"></button>
|
||||
<button bitSuffix bitLink disabled>
|
||||
Apply
|
||||
</button>
|
||||
<button bitSuffix bitIconButton="bwi-ellipsis-v" disabled [appA11yTitle]="'Menu Label'"></button>
|
||||
|
||||
</bit-form-field>
|
||||
`,
|
||||
}),
|
||||
@@ -387,9 +384,7 @@ export const PartiallyDisabledButtonInputGroup: Story = {
|
||||
<input bitInput placeholder="Placeholder" disabled />
|
||||
<button bitSuffix bitIconButton="bwi-eye" [appA11yTitle]="'Hide Label'"></button>
|
||||
<button bitSuffix bitIconButton="bwi-clone" [appA11yTitle]="'Clone Label'"></button>
|
||||
<button bitSuffix bitLink disabled>
|
||||
Apply
|
||||
</button>
|
||||
<button bitSuffix bitIconButton="bwi-ellipsis-v" disabled [appA11yTitle]="'Menu Label'"></button>
|
||||
</bit-form-field>
|
||||
`,
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<span class="tw-relative">
|
||||
<span [ngClass]="{ 'tw-invisible': showLoadingStyle() }">
|
||||
<span class="tw-relative tw-inline-block tw-leading-[0px]">
|
||||
<span class="tw-inline-block tw-leading-[0px]" [ngClass]="{ 'tw-invisible': showLoadingStyle() }">
|
||||
<i class="bwi" [ngClass]="iconClass" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span
|
||||
|
||||
@@ -5,10 +5,10 @@ import { Component, computed, ElementRef, HostBinding, input, model } from "@ang
|
||||
import { toObservable, toSignal } from "@angular/core/rxjs-interop";
|
||||
import { debounce, interval } from "rxjs";
|
||||
|
||||
import { ButtonLikeAbstraction, ButtonType } from "../shared/button-like.abstraction";
|
||||
import { ButtonLikeAbstraction } from "../shared/button-like.abstraction";
|
||||
import { FocusableElement } from "../shared/focusable-element";
|
||||
|
||||
export type IconButtonType = ButtonType | "contrast" | "main" | "muted" | "light";
|
||||
export type IconButtonType = "primary" | "danger" | "contrast" | "main" | "muted" | "nav-contrast";
|
||||
|
||||
const focusRing = [
|
||||
// Workaround for box-shadow with transparent offset issue:
|
||||
@@ -20,7 +20,7 @@ const focusRing = [
|
||||
"before:tw-content-['']",
|
||||
"before:tw-block",
|
||||
"before:tw-absolute",
|
||||
"before:-tw-inset-[2px]",
|
||||
"before:-tw-inset-[1px]",
|
||||
"before:tw-rounded-lg",
|
||||
"before:tw-transition",
|
||||
"before:tw-ring-2",
|
||||
@@ -30,122 +30,38 @@ const focusRing = [
|
||||
|
||||
const styles: Record<IconButtonType, string[]> = {
|
||||
contrast: [
|
||||
"tw-bg-transparent",
|
||||
"!tw-text-contrast",
|
||||
"tw-border-transparent",
|
||||
"hover:tw-bg-transparent-hover",
|
||||
"hover:tw-border-text-contrast",
|
||||
"hover:!tw-bg-hover-contrast",
|
||||
"focus-visible:before:tw-ring-text-contrast",
|
||||
...focusRing,
|
||||
],
|
||||
main: [
|
||||
"tw-bg-transparent",
|
||||
"!tw-text-main",
|
||||
"tw-border-transparent",
|
||||
"hover:tw-bg-transparent-hover",
|
||||
"hover:tw-border-primary-600",
|
||||
"focus-visible:before:tw-ring-primary-600",
|
||||
...focusRing,
|
||||
],
|
||||
main: ["!tw-text-main", "focus-visible:before:tw-ring-primary-600", ...focusRing],
|
||||
muted: [
|
||||
"tw-bg-transparent",
|
||||
"!tw-text-muted",
|
||||
"tw-border-transparent",
|
||||
"aria-expanded:tw-bg-text-muted",
|
||||
"aria-expanded:!tw-text-contrast",
|
||||
"hover:tw-bg-transparent-hover",
|
||||
"hover:tw-border-primary-600",
|
||||
"focus-visible:before:tw-ring-primary-600",
|
||||
"aria-expanded:hover:tw-bg-secondary-700",
|
||||
"aria-expanded:hover:tw-border-secondary-700",
|
||||
...focusRing,
|
||||
],
|
||||
primary: [
|
||||
"tw-bg-primary-600",
|
||||
"!tw-text-contrast",
|
||||
"tw-border-primary-600",
|
||||
"hover:tw-bg-primary-600",
|
||||
"hover:tw-border-primary-600",
|
||||
"focus-visible:before:tw-ring-primary-600",
|
||||
...focusRing,
|
||||
],
|
||||
secondary: [
|
||||
"tw-bg-transparent",
|
||||
"!tw-text-muted",
|
||||
"tw-border-text-muted",
|
||||
"hover:!tw-text-contrast",
|
||||
"hover:tw-bg-text-muted",
|
||||
"focus-visible:before:tw-ring-primary-600",
|
||||
...focusRing,
|
||||
],
|
||||
danger: [
|
||||
"tw-bg-transparent",
|
||||
"!tw-text-danger-600",
|
||||
"tw-border-transparent",
|
||||
"hover:!tw-text-danger-600",
|
||||
"hover:tw-bg-transparent",
|
||||
"hover:tw-border-primary-600",
|
||||
"focus-visible:before:tw-ring-primary-600",
|
||||
...focusRing,
|
||||
],
|
||||
light: [
|
||||
"tw-bg-transparent",
|
||||
primary: ["!tw-text-primary-600", "focus-visible:before:tw-ring-primary-600", ...focusRing],
|
||||
danger: ["!tw-text-danger-600", "focus-visible:before:tw-ring-primary-600", ...focusRing],
|
||||
"nav-contrast": [
|
||||
"!tw-text-alt2",
|
||||
"tw-border-transparent",
|
||||
"hover:tw-bg-transparent-hover",
|
||||
"hover:tw-border-text-alt2",
|
||||
"hover:!tw-bg-hover-contrast",
|
||||
"focus-visible:before:tw-ring-text-alt2",
|
||||
...focusRing,
|
||||
],
|
||||
unstyled: [],
|
||||
};
|
||||
|
||||
const disabledStyles: Record<IconButtonType, string[]> = {
|
||||
contrast: [
|
||||
"disabled:tw-opacity-60",
|
||||
"disabled:hover:tw-border-transparent",
|
||||
"disabled:hover:tw-bg-transparent",
|
||||
],
|
||||
main: [
|
||||
"disabled:!tw-text-secondary-300",
|
||||
"disabled:hover:tw-border-transparent",
|
||||
"disabled:hover:tw-bg-transparent",
|
||||
],
|
||||
muted: [
|
||||
"disabled:!tw-text-secondary-300",
|
||||
"disabled:hover:tw-border-transparent",
|
||||
"disabled:hover:tw-bg-transparent",
|
||||
],
|
||||
primary: [
|
||||
"disabled:tw-opacity-60",
|
||||
"disabled:hover:tw-border-primary-600",
|
||||
"disabled:hover:tw-bg-primary-600",
|
||||
],
|
||||
secondary: [
|
||||
"disabled:tw-opacity-60",
|
||||
"disabled:hover:tw-border-text-muted",
|
||||
"disabled:hover:tw-bg-transparent",
|
||||
"disabled:hover:!tw-text-muted",
|
||||
],
|
||||
danger: [
|
||||
"disabled:!tw-text-secondary-300",
|
||||
"disabled:hover:tw-border-transparent",
|
||||
"disabled:hover:tw-bg-transparent",
|
||||
"disabled:hover:!tw-text-secondary-300",
|
||||
],
|
||||
light: [
|
||||
"disabled:tw-opacity-60",
|
||||
"disabled:hover:tw-border-transparent",
|
||||
"disabled:hover:tw-bg-transparent",
|
||||
],
|
||||
unstyled: [],
|
||||
};
|
||||
|
||||
export type IconButtonSize = "default" | "small";
|
||||
|
||||
const sizes: Record<IconButtonSize, string[]> = {
|
||||
default: ["tw-px-2.5", "tw-py-1.5"],
|
||||
small: ["tw-leading-none", "tw-text-base", "tw-p-1"],
|
||||
default: ["tw-text-xl", "tw-p-2.5", "tw-rounded-md"],
|
||||
small: ["tw-text-base", "tw-p-2", "tw-rounded"],
|
||||
};
|
||||
/**
|
||||
* Icon buttons are used when no text accompanies the button. It consists of an icon that may be updated to any icon in the `bwi-font`, a `title` attribute, and an `aria-label`.
|
||||
@@ -164,6 +80,13 @@ const sizes: Record<IconButtonSize, string[]> = {
|
||||
imports: [NgClass],
|
||||
host: {
|
||||
"[attr.disabled]": "disabledAttr()",
|
||||
/**
|
||||
* When the `bitIconButton` input is dynamic from a consumer, Angular doesn't put the
|
||||
* `bitIconButton` attribute into the DOM. We use the attribute as a css selector in
|
||||
* a number of components, so this manual attr binding makes sure that the css selector
|
||||
* works when the input is dynamic.
|
||||
*/
|
||||
"[attr.bitIconButton]": "icon()",
|
||||
},
|
||||
})
|
||||
export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableElement {
|
||||
@@ -176,17 +99,20 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
|
||||
@HostBinding("class") get classList() {
|
||||
return [
|
||||
"tw-font-semibold",
|
||||
"tw-border",
|
||||
"tw-border-solid",
|
||||
"tw-rounded-lg",
|
||||
"tw-leading-[0px]",
|
||||
"tw-border-none",
|
||||
"tw-transition",
|
||||
"tw-bg-transparent",
|
||||
"hover:tw-no-underline",
|
||||
"hover:tw-bg-hover-default",
|
||||
"focus:tw-outline-none",
|
||||
]
|
||||
.concat(styles[this.buttonType()])
|
||||
.concat(sizes[this.size()])
|
||||
.concat(
|
||||
this.showDisabledStyles() || this.disabled() ? disabledStyles[this.buttonType()] : [],
|
||||
this.showDisabledStyles() || this.disabled()
|
||||
? ["disabled:tw-opacity-60", "disabled:hover:!tw-bg-transparent"]
|
||||
: [],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ Icon buttons can be found in other components such as: the
|
||||
|
||||
## Styles
|
||||
|
||||
There are 4 common styles for button main, muted, contrast, and danger. The other styles follow the
|
||||
button component styles.
|
||||
|
||||
### Main
|
||||
|
||||
Used for general icon buttons appearing on the theme’s main `background`
|
||||
@@ -59,22 +56,11 @@ square.
|
||||
|
||||
<Canvas of={stories.Primary} />
|
||||
|
||||
### Secondary
|
||||
### Nav Contrast
|
||||
|
||||
Used in place of the main button component if no text is used. This allows the button to display
|
||||
square.
|
||||
Used on the side nav background that is dark in both light theme and dark theme.
|
||||
|
||||
<Canvas of={stories.Secondary} />
|
||||
|
||||
### Light
|
||||
|
||||
Used on a background that is dark in both light theme and dark theme. Example: end user navigation
|
||||
styles.
|
||||
|
||||
<Canvas of={stories.Light} />
|
||||
|
||||
**Note:** Main and contrast styles appear on backgrounds where using `primary-700` as a focus
|
||||
indicator does not meet WCAG graphic contrast guidelines.
|
||||
<Canvas of={stories.NavContrast} />
|
||||
|
||||
## Sizes
|
||||
|
||||
|
||||
@@ -49,13 +49,6 @@ export const Primary: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Secondary: Story = {
|
||||
...Default,
|
||||
args: {
|
||||
buttonType: "secondary",
|
||||
},
|
||||
};
|
||||
|
||||
export const Danger: Story = {
|
||||
...Default,
|
||||
args: {
|
||||
@@ -77,18 +70,18 @@ export const Muted: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Light: Story = {
|
||||
export const NavContrast: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: /*html*/ `
|
||||
<div class="tw-bg-background-alt2 tw-p-6 tw-w-full tw-inline-block">
|
||||
<div class="tw-bg-background-alt3 tw-p-6 tw-w-full tw-inline-block">
|
||||
<!-- <div> used only to provide dark background color -->
|
||||
<button ${formatArgsForCodeSnippet<BitIconButtonComponent>(args)}>Button</button>
|
||||
</div>
|
||||
`,
|
||||
}),
|
||||
args: {
|
||||
buttonType: "light",
|
||||
buttonType: "nav-contrast",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Component } from "@angular/core";
|
||||
* `top` and `bottom` units should be kept in sync with `item-content.component.ts`'s y-axis padding.
|
||||
* we want this `:after` element to be the same height as the `item-content`
|
||||
*/
|
||||
"[&>button]:tw-relative [&>button:not([bit-item-content])]:after:tw-content-[''] [&>button]:after:tw-absolute [&>button]:after:tw-block bit-compact:[&>button]:after:tw-top-[-0.7rem] bit-compact:[&>button]:after:tw-bottom-[-0.7rem] [&>button]:after:tw-top-[-0.8rem] [&>button]:after:tw-bottom-[-0.80rem] [&>button]:after:tw-right-[-0.25rem] [&>button]:after:tw-left-[-0.25rem]",
|
||||
"[&>button]:tw-relative [&>button:not([bit-item-content])]:after:tw-content-[''] [&>button]:after:tw-absolute [&>button]:after:tw-block bit-compact:[&>button]:after:tw-top-[-0.7rem] bit-compact:[&>button]:after:tw-bottom-[-0.7rem] [&>button]:after:tw-top-[-0.8rem] [&>button]:after:tw-bottom-[-0.80rem] [&>button]:after:tw-right-0 [&>button]:after:tw-left-0",
|
||||
},
|
||||
})
|
||||
export class ItemActionComponent {}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<div
|
||||
#endSlot
|
||||
class="tw-p-2 tw-flex tw-gap-1 tw-items-center"
|
||||
class="tw-px-2 tw-flex tw-items-center tw-gap-2 [&_button[biticonbutton]]:-tw-mx-1"
|
||||
[hidden]="endSlot.childElementCount === 0"
|
||||
>
|
||||
<ng-content select="[slot=end]"></ng-content>
|
||||
|
||||
@@ -397,7 +397,7 @@ export const VirtualScrolling: Story = {
|
||||
data: Array.from(Array(100000).keys()),
|
||||
},
|
||||
template: /*html*/ `
|
||||
<cdk-virtual-scroll-viewport [itemSize]="59" class="tw-h-[500px]">
|
||||
<cdk-virtual-scroll-viewport [itemSize]="54" class="tw-h-[500px]">
|
||||
<bit-item-group aria-label="Virtual Scrolling">
|
||||
<bit-item *cdkVirtualFor="let item of data">
|
||||
<button bit-item-content>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
type="button"
|
||||
class="tw-ms-auto"
|
||||
[bitIconButton]="open() ? 'bwi-angle-up' : 'bwi-angle-down'"
|
||||
[buttonType]="'light'"
|
||||
[buttonType]="'nav-contrast'"
|
||||
(click)="toggle($event)"
|
||||
size="small"
|
||||
[title]="'toggleCollapse' | i18n"
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
@if (open) {
|
||||
<div
|
||||
class="tw-flex tw-items-center tw-pe-1.5 tw-gap-1 [&>*:focus-visible::before]:!tw-ring-text-alt2 [&>*:hover]:!tw-border-text-alt2 [&>*]:tw-text-alt2 empty:tw-hidden"
|
||||
class="tw-flex tw-items-center tw-pe-1 tw-gap-1 [&>*:focus-visible::before]:!tw-ring-text-alt2 [&>*:hover]:!tw-border-text-alt2 [&>*]:tw-text-alt2 empty:tw-hidden"
|
||||
>
|
||||
<ng-content select="[slot=end]"></ng-content>
|
||||
</div>
|
||||
|
||||
@@ -92,7 +92,7 @@ export const WithChildButtons: Story = {
|
||||
slot="end"
|
||||
class="tw-ms-auto"
|
||||
[bitIconButton]="'bwi-pencil-square'"
|
||||
[buttonType]="'light'"
|
||||
[buttonType]="'nav-contrast'"
|
||||
size="small"
|
||||
aria-label="option 2"
|
||||
></button>
|
||||
@@ -100,7 +100,7 @@ export const WithChildButtons: Story = {
|
||||
slot="end"
|
||||
class="tw-ms-auto"
|
||||
[bitIconButton]="'bwi-check'"
|
||||
[buttonType]="'light'"
|
||||
[buttonType]="'nav-contrast'"
|
||||
size="small"
|
||||
aria-label="option 3"
|
||||
></button>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
type="button"
|
||||
class="tw-mx-auto tw-block tw-max-w-fit"
|
||||
[bitIconButton]="data.open ? 'bwi-angle-left' : 'bwi-angle-right'"
|
||||
buttonType="light"
|
||||
buttonType="nav-contrast"
|
||||
size="small"
|
||||
(click)="sideNavService.toggle()"
|
||||
[attr.aria-label]="'toggleSideNavigation' | i18n"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<div
|
||||
class="tw-relative tw-z-20 tw-w-72 tw-break-words tw-bg-background tw-pb-4 tw-pt-2 tw-text-main"
|
||||
>
|
||||
<div class="tw-mb-1 tw-me-2 tw-flex tw-items-start tw-justify-between tw-gap-4 tw-ps-4">
|
||||
<h2 bitTypography="h5" class="tw-mt-1 tw-font-semibold">
|
||||
<div class="tw-me-2 tw-flex tw-items-start tw-justify-between tw-gap-4 tw-ps-4">
|
||||
<h2 bitTypography="h5" class="tw-font-semibold tw-mt-1">
|
||||
{{ title() }}
|
||||
</h2>
|
||||
<button
|
||||
@@ -15,7 +15,6 @@
|
||||
[attr.aria-label]="'close' | i18n"
|
||||
(click)="closed.emit()"
|
||||
size="small"
|
||||
class="tw-mt-0.5"
|
||||
></button>
|
||||
</div>
|
||||
<div bitTypography="body2" class="tw-px-4">
|
||||
|
||||
@@ -68,7 +68,7 @@ const popoverContent = /*html*/ `
|
||||
<li>Esse labore veniam tempora</li>
|
||||
<li>Adipisicing elit ipsum <a href="#" bitLink>iustolaborum</a></li>
|
||||
</ul>
|
||||
<button bitButton class="tw-mt-3" (click)="triggerRef.closePopover()">Close</button>
|
||||
<button bitButton class="tw-mt-4" (click)="triggerRef.closePopover()">Close</button>
|
||||
</bit-popover>
|
||||
`;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
role="search"
|
||||
(mouseenter)="isFormHovered.set(true)"
|
||||
(mouseleave)="isFormHovered.set(false)"
|
||||
class="tw-relative tw-flex tw-items-center tw-w-full"
|
||||
class="tw-relative tw-flex tw-items-center tw-w-full tw-h-10"
|
||||
>
|
||||
<label class="tw-sr-only" [for]="id">{{ "search" | i18n }}</label>
|
||||
<label
|
||||
@@ -18,7 +18,7 @@
|
||||
[type]="inputType"
|
||||
[id]="id"
|
||||
[placeholder]="placeholder() ?? ('search' | i18n)"
|
||||
class="tw-ps-9"
|
||||
class="tw-ps-9 tw-h-full"
|
||||
name="searchText"
|
||||
[ngModel]="searchText"
|
||||
(ngModelChange)="onChange($event)"
|
||||
|
||||
@@ -19,7 +19,7 @@ import { TableDataSource, TableModule } from "../../../table";
|
||||
ScrollLayoutDirective,
|
||||
],
|
||||
template: /*html*/ `<bit-section>
|
||||
<cdk-virtual-scroll-viewport bitScrollLayout itemSize="63.5">
|
||||
<cdk-virtual-scroll-viewport bitScrollLayout itemSize="49.5">
|
||||
<bit-table [dataSource]="dataSource">
|
||||
<ng-container header>
|
||||
<tr>
|
||||
|
||||
@@ -5,6 +5,6 @@ import { Directive, HostBinding } from "@angular/core";
|
||||
})
|
||||
export class CellDirective {
|
||||
@HostBinding("class") get classList() {
|
||||
return ["tw-p-3"];
|
||||
return ["tw-p-3", "has-[[biticonbutton]]:tw-py-1"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
bitIconButton="bwi-close"
|
||||
buttonType="main"
|
||||
type="button"
|
||||
size="small"
|
||||
(click)="this.onClose.emit()"
|
||||
></button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user