mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[CL-659] Replace CL non tw css classes with data attributes (#14421)
The component library currently uses classes to determine fvw target, default content and main content. This replaces them with data attributes which avoids the css class linter from detecting them as invalid classes.
This commit is contained in:
@@ -14,7 +14,8 @@
|
||||
<!-- Primary button -->
|
||||
<button
|
||||
type="button"
|
||||
class="fvw-target tw-inline-flex tw-gap-1.5 tw-items-center tw-justify-between tw-bg-transparent hover:tw-bg-transparent tw-border-none tw-outline-none tw-w-full tw-py-1 tw-pl-3 last:tw-pr-3 [&:not(:last-child)]:tw-pr-0 tw-truncate tw-text-[color:inherit] tw-text-[length:inherit]"
|
||||
class="tw-inline-flex tw-gap-1.5 tw-items-center tw-justify-between tw-bg-transparent hover:tw-bg-transparent tw-border-none tw-outline-none tw-w-full tw-py-1 tw-pl-3 last:tw-pr-3 [&:not(:last-child)]:tw-pr-0 tw-truncate tw-text-[color:inherit] tw-text-[length:inherit]"
|
||||
data-fvw-target
|
||||
[ngClass]="{
|
||||
'tw-cursor-not-allowed': disabled,
|
||||
'group-hover/chip-select:tw-text-secondary-700': !selectedOption && !disabled,
|
||||
|
||||
@@ -80,7 +80,7 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
protected focusVisibleWithin = signal(false);
|
||||
@HostListener("focusin", ["$event.target"])
|
||||
onFocusIn(target: HTMLElement) {
|
||||
this.focusVisibleWithin.set(target.matches(".fvw-target:focus-visible"));
|
||||
this.focusVisibleWithin.set(target.matches("[data-fvw-target]:focus-visible"));
|
||||
}
|
||||
@HostListener("focusout")
|
||||
onFocusOut() {
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
<ng-container *ngTemplateOutlet="prefixContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
class="default-content 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-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"
|
||||
data-default-content
|
||||
[ngClass]="[
|
||||
prefixHasChildren() ? '' : 'tw-rounded-l-lg tw-pl-3',
|
||||
suffixHasChildren() ? '' : 'tw-rounded-r-lg tw-pr-3',
|
||||
@@ -96,7 +97,8 @@
|
||||
<ng-container *ngTemplateOutlet="prefixContent"></ng-container>
|
||||
</div>
|
||||
<div
|
||||
class="default-content tw-w-full tw-pb-0 tw-relative [&>*]:tw-p-0 [&>*::selection]:tw-bg-primary-700 [&>*::selection]:tw-text-contrast"
|
||||
class="tw-w-full tw-pb-0 tw-relative [&>*]:tw-p-0 [&>*::selection]:tw-bg-primary-700 [&>*::selection]:tw-text-contrast"
|
||||
data-default-content
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="defaultContent"></ng-container>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +91,7 @@ export class BitFormFieldComponent implements AfterContentChecked {
|
||||
protected defaultContentIsFocused = signal(false);
|
||||
@HostListener("focusin", ["$event.target"])
|
||||
onFocusIn(target: HTMLElement) {
|
||||
this.defaultContentIsFocused.set(target.matches(".default-content *:focus-visible"));
|
||||
this.defaultContentIsFocused.set(target.matches("[data-default-content] *:focus-visible"));
|
||||
}
|
||||
@HostListener("focusout")
|
||||
onFocusOut() {
|
||||
|
||||
@@ -25,7 +25,8 @@ import { TypographyModule } from "../typography";
|
||||
* y-axis padding should be kept in sync with `item-action.component.ts`'s `top` and `bottom` units.
|
||||
* we want this to be the same height as the `item-action`'s `:after` element
|
||||
*/
|
||||
"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",
|
||||
"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",
|
||||
"data-fvw-target": "",
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<bit-item-action class="item-main-content tw-flex tw-flex-1 tw-overflow-hidden">
|
||||
<bit-item-action class="tw-flex tw-flex-1 tw-overflow-hidden" data-item-main-content>
|
||||
<ng-content></ng-content>
|
||||
</bit-item-action>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { ItemActionComponent } from "./item-action.component";
|
||||
providers: [{ provide: A11yRowDirective, useExisting: ItemComponent }],
|
||||
host: {
|
||||
class:
|
||||
"tw-block tw-box-border tw-overflow-hidden 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",
|
||||
"tw-block tw-box-border tw-overflow-hidden tw-flex tw-bg-background [&:has([data-item-main-content]_button:hover,[data-item-main-content]_a:hover)]:tw-cursor-pointer [&:has([data-item-main-content]_button:hover,[data-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 {
|
||||
@@ -29,7 +29,7 @@ export class ItemComponent extends A11yRowDirective {
|
||||
protected focusVisibleWithin = signal(false);
|
||||
@HostListener("focusin", ["$event.target"])
|
||||
onFocusIn(target: HTMLElement) {
|
||||
this.focusVisibleWithin.set(target.matches(".fvw-target:focus-visible"));
|
||||
this.focusVisibleWithin.set(target.matches("[data-fvw-target]:focus-visible"));
|
||||
}
|
||||
@HostListener("focusout")
|
||||
onFocusOut() {
|
||||
|
||||
@@ -70,10 +70,11 @@
|
||||
|
||||
<!-- Show if a value was passed to `this.to` -->
|
||||
<ng-template #isAnchor>
|
||||
<!-- The `fvw` class passes focus to `this.focusVisibleWithin$` -->
|
||||
<!-- The `data-fvw` attribute passes focus to `this.focusVisibleWithin$` -->
|
||||
<!-- The following `class` field should match the `#isButton` class field below -->
|
||||
<a
|
||||
class="fvw tw-w-full tw-truncate tw-border-none tw-bg-transparent tw-p-0 tw-text-start !tw-text-alt2 hover:tw-text-alt2 hover:tw-no-underline focus:tw-outline-none"
|
||||
class="tw-w-full tw-truncate tw-border-none tw-bg-transparent tw-p-0 tw-text-start !tw-text-alt2 hover:tw-text-alt2 hover:tw-no-underline focus:tw-outline-none"
|
||||
data-fvw
|
||||
[routerLink]="route"
|
||||
[relativeTo]="relativeTo"
|
||||
[attr.aria-label]="ariaLabel || text"
|
||||
@@ -92,7 +93,8 @@
|
||||
<!-- Class field should match `#isAnchor` class field above -->
|
||||
<button
|
||||
type="button"
|
||||
class="fvw tw-w-full tw-truncate tw-border-none tw-bg-transparent tw-p-0 tw-text-start !tw-text-alt2 hover:tw-text-alt2 hover:tw-no-underline focus:tw-outline-none"
|
||||
class="tw-w-full tw-truncate tw-border-none tw-bg-transparent tw-p-0 tw-text-start !tw-text-alt2 hover:tw-text-alt2 hover:tw-no-underline focus:tw-outline-none"
|
||||
data-fvw
|
||||
(click)="mainContentClicked.emit()"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="anchorAndButtonContent"></ng-container>
|
||||
|
||||
@@ -39,11 +39,15 @@ export class NavItemComponent extends NavBaseComponent {
|
||||
}
|
||||
|
||||
/**
|
||||
* The design spec calls for the an outline to wrap the entire element when the template's anchor/button has :focus-visible.
|
||||
* Usually, we would use :focus-within for this. However, that matches when a child element has :focus instead of :focus-visible.
|
||||
* The design spec calls for the an outline to wrap the entire element when the template's
|
||||
* anchor/button has :focus-visible. Usually, we would use :focus-within for this. However, that
|
||||
* matches when a child element has :focus instead of :focus-visible.
|
||||
*
|
||||
* Currently, the browser does not have a pseudo selector that combines these two, e.g. :focus-visible-within (WICG/focus-visible#151)
|
||||
* To make our own :focus-visible-within functionality, we use event delegation on the host and manually check if the focus target (denoted with the .fvw class) matches :focus-visible. We then map that state to some styles, so the entire component can have an outline.
|
||||
* Currently, the browser does not have a pseudo selector that combines these two, e.g.
|
||||
* :focus-visible-within (WICG/focus-visible#151). To make our own :focus-visible-within
|
||||
* functionality, we use event delegation on the host and manually check if the focus target
|
||||
* (denoted with the data-fvw attribute) matches :focus-visible. We then map that state to some
|
||||
* styles, so the entire component can have an outline.
|
||||
*/
|
||||
protected focusVisibleWithin$ = new BehaviorSubject(false);
|
||||
protected fvwStyles$ = this.focusVisibleWithin$.pipe(
|
||||
@@ -53,7 +57,7 @@ export class NavItemComponent extends NavBaseComponent {
|
||||
);
|
||||
@HostListener("focusin", ["$event.target"])
|
||||
onFocusIn(target: HTMLElement) {
|
||||
this.focusVisibleWithin$.next(target.matches(".fvw:focus-visible"));
|
||||
this.focusVisibleWithin$.next(target.matches("[data-fvw]:focus-visible"));
|
||||
}
|
||||
@HostListener("focusout")
|
||||
onFocusOut() {
|
||||
|
||||
Reference in New Issue
Block a user