From ed2b24bd56a0601521de04c91a8c770b0bbe5980 Mon Sep 17 00:00:00 2001 From: Davide Mininni Date: Thu, 21 Mar 2024 09:57:10 +0100 Subject: [PATCH] fix: add styles, minor fix in ts and stories --- .../autocomplete-grid-actions.scss | 2 +- .../autocomplete-grid-button.ts | 23 ++++- .../autocomplete-grid-button/readme.md | 6 ++ .../autocomplete-grid-option.scss | 58 +++++++++++ .../autocomplete-grid-option.ts | 23 ++++- .../autocomplete-grid-row.scss | 97 ++++++++++++++++++- .../autocomplete-grid.stories.ts | 42 ++++++-- .../autocomplete-grid/autocomplete-grid.ts | 47 +++++---- .../common-behaviors/option-base-element.ts | 11 +-- .../option/option.scss} | 2 +- src/components/option/option/option.ts | 8 +- 11 files changed, 267 insertions(+), 52 deletions(-) create mode 100644 src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.scss rename src/components/{core/common-behaviors/option-base-element.scss => option/option/option.scss} (99%) diff --git a/src/components/autocomplete-grid/autocomplete-grid-actions/autocomplete-grid-actions.scss b/src/components/autocomplete-grid/autocomplete-grid-actions/autocomplete-grid-actions.scss index 7bfd87bc1c6..69f558f4495 100644 --- a/src/components/autocomplete-grid/autocomplete-grid-actions/autocomplete-grid-actions.scss +++ b/src/components/autocomplete-grid/autocomplete-grid-actions/autocomplete-grid-actions.scss @@ -6,5 +6,5 @@ .sbb-autocomplete-grid-action { display: flex; - column-gap: var(--sbb-spacing-responsive-xxxs); // FIXME + column-gap: var(--sbb-spacing-fixed-1x); } diff --git a/src/components/autocomplete-grid/autocomplete-grid-button/autocomplete-grid-button.ts b/src/components/autocomplete-grid/autocomplete-grid-button/autocomplete-grid-button.ts index 8b796765bc4..39abec63cf3 100644 --- a/src/components/autocomplete-grid/autocomplete-grid-button/autocomplete-grid-button.ts +++ b/src/components/autocomplete-grid/autocomplete-grid-button/autocomplete-grid-button.ts @@ -8,7 +8,7 @@ import { } from '../../core/common-behaviors'; import { isValidAttribute, setAttribute } from '../../core/dom'; import { AgnosticMutationObserver } from '../../core/observers'; -import type { SbbAutocompleteGridOptionElement } from '../autocomplete-grid-option'; +import { type SbbAutocompleteGridOptionElement } from '../autocomplete-grid-option'; import '../../icon'; import style from './autocomplete-grid-button.scss?lit&inline'; @@ -62,7 +62,26 @@ export class SbbAutocompleteGridButtonElement extends SbbDisabledMixin(SbbMiniBu } public dispatchClick(event: KeyboardEvent): void { - return super.dispatchClickEvent(event); + return this.dispatchClickEvent(event); + } + + // Event needs to be dispatched from the action element; in autocomplete-grid, + // the input has always the focus, so the `event.target` on parent class is the input and not the button. + protected override dispatchClickEvent(event: KeyboardEvent): void { + const { altKey, ctrlKey, metaKey, shiftKey } = event; + this.dispatchEvent( + new PointerEvent('click', { + bubbles: true, + cancelable: true, + composed: true, + pointerId: -1, + pointerType: '', + altKey, + ctrlKey, + metaKey, + shiftKey, + }), + ); } /** Gets the SbbAutocompleteGridOptionElement on the same row of the button. */ diff --git a/src/components/autocomplete-grid/autocomplete-grid-button/readme.md b/src/components/autocomplete-grid/autocomplete-grid-button/readme.md index 86771577c6e..759c7a0a007 100644 --- a/src/components/autocomplete-grid/autocomplete-grid-button/readme.md +++ b/src/components/autocomplete-grid/autocomplete-grid-button/readme.md @@ -106,6 +106,12 @@ Use the accessibility properties to describe the purpose of the `sbb-autocomplet | --------------- | ------- | ----------- | ---------------------- | ------ | -------------- | | `dispatchClick` | public | | `event: KeyboardEvent` | `void` | | +## Events + +| Name | Type | Description | Inherited From | +| ------- | -------------- | ----------- | -------------- | +| `click` | `PointerEvent` | | | + ## Slots | Name | Description | diff --git a/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.scss b/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.scss new file mode 100644 index 00000000000..9107589b322 --- /dev/null +++ b/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.scss @@ -0,0 +1,58 @@ +@use '../../core/styles/index' as sbb; + +// Default component properties, defined for :host. Properties which can not +// travel the shadow boundary are defined through this mixin +@include sbb.host-component-properties; + +:host { + --sbb-option-color: var(--sbb-color-charcoal); + --sbb-option-column-gap: var(--sbb-spacing-responsive-xxxs); + --sbb-option-icon-color: var(--sbb-color-metal); +} + +:host([data-negative]) { + --sbb-option-color: var(--sbb-color-milk); + --sbb-option-icon-color: var(--sbb-color-smoke); +} + +// if the highlight is enabled, hide the slot content +:host(:not([data-disable-highlight])) { + .sbb-option__label slot { + display: none; + } +} + +.sbb-option { + @include sbb.text-s--regular; + + display: flex; + align-items: center; + column-gap: var(--sbb-option-column-gap); + justify-content: start; + color: var(--sbb-option-color); +} + +.sbb-option__label--highlight { + :host(:not(:is([disabled], [data-group-disabled]))) & { + @include sbb.text--bold; + @include sbb.if-forced-colors { + color: Highlight; + } + } +} + +.sbb-option__icon { + display: flex; + min-width: var(--sbb-size-icon-ui-small); + min-height: var(--sbb-size-icon-ui-small); + color: var(--sbb-option-icon-color); + + :host(:not([data-slot-names~='icon'], [icon-name])) & { + // Can be overridden by the 'preserve-icon-space' on the autocomplete + display: var(--sbb-option-icon-container-display, none); + } +} + +.sbb-option__label { + white-space: initial; +} diff --git a/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.ts b/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.ts index 632c54c8600..710775694b5 100644 --- a/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.ts +++ b/src/components/autocomplete-grid/autocomplete-grid-option/autocomplete-grid-option.ts @@ -1,4 +1,4 @@ -import type { TemplateResult } from 'lit'; +import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; import { customElement } from 'lit/decorators.js'; import { assignId } from '../../core/a11y'; @@ -6,6 +6,8 @@ import { hostAttributes, SbbOptionBaseElement } from '../../core/common-behavior import { EventEmitter } from '../../core/eventing'; import '../../icon'; +import '../../screenreader-only'; +import style from './autocomplete-grid-option.scss?lit&inline'; let nextId = 0; @@ -24,6 +26,7 @@ let nextId = 0; role: 'gridcell', }) export class SbbAutocompleteGridOptionElement extends SbbOptionBaseElement { + public static override styles: CSSResultGroup = style; public static readonly events = { selectionChange: 'autocompleteOptionSelectionChange', optionSelected: 'autocompleteOptionSelected', @@ -43,17 +46,33 @@ export class SbbAutocompleteGridOptionElement extends SbbOptionBaseElement { SbbAutocompleteGridOptionElement.events.optionSelected, ); + public override willUpdate(changedProperties: PropertyValues): void { + if (changedProperties.has('active')) { + this.closest?.('sbb-autocomplete-grid-row')?.toggleAttribute('data-active'); + } + if (changedProperties.has('disabled')) { + this.closest?.('sbb-autocomplete-grid-row')?.toggleAttribute( + 'data-disabled', + this.disabled || this.disabledFromGroup, + ); + } + } + protected setAttributeFromParent(): void { const parentGroup = this.closest?.('sbb-autocomplete-grid-optgroup'); if (parentGroup) { this.disabledFromGroup = parentGroup.disabled; } + this.closest?.('sbb-autocomplete-grid-row')?.toggleAttribute( + 'data-disabled', + this.disabled || this.disabledFromGroup, + ); this.negative = !!this.closest?.( // :is() selector not possible due to test environment `sbb-autocomplete-grid[negative],sbb-form-field[negative]`, ); - this.toggleAttribute('data-group-negative', this.negative); + this.toggleAttribute('data-negative', this.negative); } protected selectByClick(event: MouseEvent): void { diff --git a/src/components/autocomplete-grid/autocomplete-grid-row/autocomplete-grid-row.scss b/src/components/autocomplete-grid/autocomplete-grid-row/autocomplete-grid-row.scss index 73a75f8540d..194f796becc 100644 --- a/src/components/autocomplete-grid/autocomplete-grid-row/autocomplete-grid-row.scss +++ b/src/components/autocomplete-grid/autocomplete-grid-row/autocomplete-grid-row.scss @@ -4,10 +4,101 @@ // travel the shadow boundary are defined through this mixin @include sbb.host-component-properties; +:host { + --sbb-autocomplete-grid-row-color: var(--sbb-color-charcoal); + --sbb-autocomplete-grid-row-background-color: inherit; + --sbb-autocomplete-grid-row-background-color-hover: var(--sbb-color-milk); + --sbb-autocomplete-grid-row-background-color-active: var(--sbb-color-cloud); + --sbb-autocomplete-grid-row-disabled-border-color: var(--sbb-color-graphite); + --sbb-autocomplete-grid-row-disabled-background-color: var(--sbb-color-milk); + --sbb-autocomplete-grid-row-padding-inline: var(--sbb-spacing-responsive-xxxs); + --sbb-autocomplete-grid-row-padding-block: calc( + var(--sbb-spacing-fixed-2x) + var(--sbb-border-width-2x) + ); + --sbb-autocomplete-grid-row-justify-content: space-between; + --sbb-autocomplete-grid-row-min-height: var(--sbb-size-button-m-min-height); + --sbb-autocomplete-grid-row-cursor: pointer; + --sbb-autocomplete-grid-row-border-radius: var(--sbb-border-radius-4x); + --sbb-autocomplete-grid-row-icon-color: var(--sbb-color-metal); +} + +:host([data-negative]) { + --sbb-autocomplete-grid-row-color: var(--sbb-color-milk); + --sbb-autocomplete-grid-row-icon-color: var(--sbb-color-smoke); + --sbb-autocomplete-grid-row-background-color-hover: var(--sbb-color-charcoal); + --sbb-autocomplete-grid-row-background-color-active: var(--sbb-color-iron); + --sbb-autocomplete-grid-row-disabled-border-color: var(--sbb-color-smoke); + --sbb-autocomplete-grid-row-disabled-background-color: var(--sbb-color-charcoal); + --sbb-focus-outline-color: var(--sbb-focus-outline-color-dark); +} + +:host([data-active]) { + --sbb-focus-outline-offset: calc(-1 * var(--sbb-spacing-fixed-1x)); +} + +:host(:hover:not([data-disabled])) { + @include sbb.hover-mq($hover: true) { + --sbb-autocomplete-grid-row-background-color: var( + --sbb-autocomplete-grid-row-background-color-hover + ); + } +} + +:host([data-active]):not([data-disabled]) { + --sbb-autocomplete-grid-row-background-color: var( + --sbb-autocomplete-grid-row-background-color-active + ); +} + +:host(:is([data-disabled])) { + --sbb-autocomplete-grid-row-cursor: default; + + @include sbb.if-forced-colors { + --sbb-autocomplete-grid-row-color: GrayText; + } +} + +::slotted(sbb-autocomplete-grid-option) { + flex: 1 1 auto; +} + .sbb-autocomplete-grid-row { display: flex; - justify-content: space-between; align-items: center; - padding-inline: var(--sbb-spacing-responsive-xxxs); - padding-block: calc(var(--sbb-spacing-fixed-2x) + var(--sbb-border-width-2x)); + padding-inline: var(--sbb-autocomplete-grid-row-padding-inline); + padding-block: var(--sbb-autocomplete-grid-row-padding-block); + justify-content: var(--sbb-autocomplete-grid-row-justify-content); + color: var(--sbb-autocomplete-grid-row-color); + background-color: var(--sbb-autocomplete-grid-row-background-color); + cursor: var(--sbb-autocomplete-grid-row-cursor); + -webkit-tap-highlight-color: transparent; + -webkit-text-fill-color: var(--sbb-autocomplete-grid-row-color); + + :host([data-active]) & { + @include sbb.focus-outline; + + border-radius: var(--sbb-autocomplete-grid-row-border-radius); + } + + // Add inner border and background for disabled option when it's not multiple + :host([data-disabled]) & { + position: relative; + z-index: 0; + + &::before { + content: ''; + display: block; + position: absolute; + inset: #{sbb.px-to-rem-build(6)}; + border: var(--sbb-border-width-1x) dashed + var(--sbb-autocomplete-grid-row-disabled-border-color); + border-radius: var(--sbb-border-radius-2x); + background-color: var(--sbb-autocomplete-grid-row-disabled-background-color); + z-index: -1; + + @include sbb.if-forced-colors { + border-color: GrayText; + } + } + } } diff --git a/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.stories.ts b/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.stories.ts index 89380eda414..ed1fb0a8550 100644 --- a/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.stories.ts +++ b/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.stories.ts @@ -25,7 +25,7 @@ import '../../form-field'; const getOption = (event: Event): void => { const button = event.target as SbbAutocompleteGridButtonElement; const div: HTMLDivElement = document.createElement('div'); - div.innerText = `Button has been clicked on row with label: '${button.optionOnSameRow?.textContent}' and value: '${button.optionOnSameRow?.value}'`; + div.innerText = `Button '${button.iconName}' clicked on row '${button.optionOnSameRow?.textContent}' / value: '${button.optionOnSameRow?.value}'`; (event.currentTarget as HTMLElement).closest('div')!.querySelector('#container')!.prepend(div); }; @@ -105,6 +105,15 @@ const optionIconName: InputType = { }, }; +const disableOption: InputType = { + control: { + type: 'boolean', + }, + table: { + category: 'Option', + }, +}; + const buttonIconName: InputType = { control: { type: 'text', @@ -130,6 +139,7 @@ const defaultArgTypes: ArgTypes = { // Option args optionIconName, + disableOption, // Button args buttonIconName, @@ -151,23 +161,32 @@ const defaultArgs: Args = { // Option args optionIconName: 'clock-small', + disableOption: false, // Button args buttonIconName: 'pen-small', }; -const createRows1 = (optionIconName: string, buttonIconName: string): TemplateResult => html` +const createRows1 = ( + optionIconName: string, + buttonIconName: string, + disableOption: boolean, +): TemplateResult => html` ${repeat( new Array(3), (_, i: number) => html` - ${`Option 1-${i + 1}`} getOption(event)} > @@ -176,23 +195,25 @@ const createRows1 = (optionIconName: string, buttonIconName: string): TemplateRe )} `; -const createRows2 = (buttonIconName: string): TemplateResult => html` +const createRows2 = (buttonIconName: string, disableOption: boolean): TemplateResult => html` ${repeat( new Array(3), (_, i: number) => html` - ${`Option 2-${i + 1}`} getOption(event)} > getOption(event)} > @@ -242,11 +263,18 @@ const Template = (args: Args): TemplateResult => html` ?disable-animation=${args.disableAnimation} ?preserve-icon-space=${args.preserveIconSpace} > - ${createRows1(args.optionIconName, args.buttonIconName)} ${createRows2(args.buttonIconName)} + ${createRows1(args.optionIconName, args.buttonIconName, args.disableOption)} + ${createRows2(args.buttonIconName, args.disableOptio1n)} ${textBlock()} -
+
`; diff --git a/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts b/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts index b006d82cc9a..cd4ad7217ae 100644 --- a/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts +++ b/src/components/autocomplete-grid/autocomplete-grid/autocomplete-grid.ts @@ -7,6 +7,7 @@ import { SbbAutocompleteBaseElement } from '../../core/common-behaviors/autocomp import { getDocumentWritingMode, isValidAttribute, setAttribute } from '../../core/dom'; import { EventEmitter } from '../../core/eventing'; import { setAriaComboBoxAttributes } from '../../core/overlay'; +import type { SbbDividerElement } from '../../divider'; import type { SbbOptGroupElement, SbbOptionElement } from '../../option'; import type { SbbAutocompleteGridButtonElement } from '../autocomplete-grid-button'; import { SbbAutocompleteGridOptionElement } from '../autocomplete-grid-option'; @@ -70,9 +71,12 @@ export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { return Array.from(this.querySelectorAll?.('sbb-autocomplete-grid-option') ?? []); } - // fixme private get _row(): SbbAutocompleteGridRowElement[] { - return Array.from(this.querySelectorAll?.('sbb-autocomplete-grid-row') ?? []); + return ( + Array.from(this.querySelectorAll?.('sbb-autocomplete-grid-row')).filter( + (row) => !row.hasAttribute('data-disabled'), + ) ?? [] + ); } /** When an option is selected, update the input value and close the autocomplete. */ @@ -120,15 +124,13 @@ export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { } protected syncNegative(): void { - this.querySelectorAll?.('sbb-divider').forEach((divider) => (divider.negative = this.negative)); + this.querySelectorAll?.( + 'sbb-divider, sbb-autocomplete-grid-button', + ).forEach((e) => (e.negative = this.negative)); this.querySelectorAll?.( - 'sbb-autocomplete-grid-option, sbb-autocomplete-grid-optgroup', + 'sbb-autocomplete-grid-row, sbb-autocomplete-grid-option, sbb-autocomplete-grid-optgroup', ).forEach((element) => element.toggleAttribute('data-negative', this.negative)); - - this.querySelectorAll?.( - 'sbb-autocomplete-grid-button', - ).forEach((element) => (element.negative = this.negative)); } protected openedPanelKeyboardInteraction(event: KeyboardEvent): void { @@ -146,13 +148,11 @@ export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { this.selectByKeyboard(event); break; - // FIXME case 'ArrowDown': case 'ArrowUp': this.setNextActiveOption(event); break; - // FIXME case 'ArrowRight': case 'ArrowLeft': this._setNextHorizontalActiveElement(event); @@ -160,7 +160,6 @@ export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { } } - // TODO protected selectByKeyboard(event: KeyboardEvent): void { if (this._activeColumnIndex !== 0) { ( @@ -191,22 +190,21 @@ export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { this.triggerElement?.setAttribute('aria-activedescendant', nextActiveOption.id); nextActiveOption.scrollIntoView({ block: 'nearest' }); - // Reset the previous active option - const lastActiveOption = filteredOptions[this._activeItemIndex]; - if (lastActiveOption) { - lastActiveOption.active = false; - } + // Reset the previous active option/button if (this._activeColumnIndex !== 0) { this._row[this._activeItemIndex] .querySelectorAll('sbb-autocomplete-grid-button') .forEach((e) => e.toggleAttribute('data-focus-visible', false)); + } else { + const lastActiveOption = filteredOptions[this._activeItemIndex]; + if (lastActiveOption) { + lastActiveOption.active = false; + } } - this._activeItemIndex = next; this._activeColumnIndex = 0; } - // FIXME private _setNextHorizontalActiveElement(event: KeyboardEvent): void { if (this._activeItemIndex < 0) { return; @@ -242,17 +240,18 @@ export class SbbAutocompleteGridElement extends SbbAutocompleteBaseElement { this._activeColumnIndex = next; } - // FIXME protected resetActiveElement(): void { - const activeElement = this.options[this._activeItemIndex]; - - if (activeElement) { - activeElement.active = false; - } if (this._activeColumnIndex !== 0) { this._row[this._activeItemIndex] .querySelectorAll('sbb-autocomplete-grid-button') .forEach((e) => e.toggleAttribute('data-focus-visible', false)); + } else { + const activeElement = this.options.filter( + (opt) => !opt.disabled && !isValidAttribute(opt, 'data-group-disabled'), + )[this._activeItemIndex]; + if (activeElement) { + activeElement.active = false; + } } this._activeItemIndex = -1; this._activeColumnIndex = 0; diff --git a/src/components/core/common-behaviors/option-base-element.ts b/src/components/core/common-behaviors/option-base-element.ts index 91a96671064..e5b8c375883 100644 --- a/src/components/core/common-behaviors/option-base-element.ts +++ b/src/components/core/common-behaviors/option-base-element.ts @@ -1,4 +1,4 @@ -import { type CSSResultGroup, html, LitElement, nothing, type TemplateResult } from 'lit'; +import { html, LitElement, nothing, type TemplateResult } from 'lit'; import { property, state } from 'lit/decorators.js'; import { isAndroid, isSafari, isValidAttribute, setAttribute } from '../dom'; @@ -9,7 +9,6 @@ import { AgnosticMutationObserver } from '../observers'; import { SbbDisabledMixin } from './disabled-mixins'; import { SbbIconNameMixin } from './icon-name-mixin'; import { NamedSlotStateController } from './named-slot-state-controller'; -import style from './option-base-element.scss?lit&inline'; /** Configuration for the attribute to look at if component is nested in an option group */ const optionObserverConfig: MutationObserverInit = { @@ -17,8 +16,6 @@ const optionObserverConfig: MutationObserverInit = { }; export abstract class SbbOptionBaseElement extends SbbDisabledMixin(SbbIconNameMixin(LitElement)) { - public static override styles: CSSResultGroup = style; - /** Value of the option. */ @property() public value?: string; @@ -177,11 +174,7 @@ export abstract class SbbOptionBaseElement extends SbbDisabledMixin(SbbIconNameM ${this.renderLabel()} ${this._inertAriaGroups && this._groupLabel - ? html` - - (${this._groupLabel}) - - ` + ? html`(${this._groupLabel})` : nothing} ${this.renderTick()} diff --git a/src/components/core/common-behaviors/option-base-element.scss b/src/components/option/option/option.scss similarity index 99% rename from src/components/core/common-behaviors/option-base-element.scss rename to src/components/option/option/option.scss index 69959f1dd4d..972ed984af7 100644 --- a/src/components/core/common-behaviors/option-base-element.scss +++ b/src/components/option/option/option.scss @@ -1,4 +1,4 @@ -@use '../styles' as sbb; +@use '../../core/styles/index' as sbb; // Default component properties, defined for :host. Properties which can not // travel the shadow boundary are defined through this mixin diff --git a/src/components/option/option/option.ts b/src/components/option/option/option.ts index 224d2700ee2..06ed4ee5734 100644 --- a/src/components/option/option/option.ts +++ b/src/components/option/option/option.ts @@ -1,4 +1,4 @@ -import type { TemplateResult } from 'lit'; +import type { CSSResultGroup, TemplateResult } from 'lit'; import { html, nothing } from 'lit'; import { customElement } from 'lit/decorators.js'; @@ -8,8 +8,9 @@ import { setAttribute } from '../../core/dom'; import { EventEmitter } from '../../core/eventing'; import '../../icon'; -import '../../visual-checkbox'; import '../../screenreader-only'; +import '../../visual-checkbox'; +import style from './option.scss?lit&inline'; let nextId = 0; @@ -30,6 +31,7 @@ export type SbbOptionVariant = 'autocomplete' | 'select'; role: 'option', }) export class SbbOptionElement extends SbbOptionBaseElement { + public static override styles: CSSResultGroup = style; public static readonly events = { selectionChange: 'optionSelectionChange', optionSelected: 'optionSelected', @@ -70,7 +72,7 @@ export class SbbOptionElement extends SbbOptionBaseElement { // :is() selector not possible due to test environment `sbb-autocomplete[negative],sbb-form-field[negative]`, ); - this.toggleAttribute('data-group-negative', this.negative); + this.toggleAttribute('data-negative', this.negative); } protected selectByClick(event: MouseEvent): void {