Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[@next] refactor setDefaultAria to use ElementInternals as fallback #445

Merged
merged 9 commits into from
Dec 14, 2023
3 changes: 0 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
"@material/card": "^14.0.0",
"@material/checkbox": "^14.0.0",
"@material/chips": "^14.0.0",
"@material/density": "^14.0.0",
"@material/dom": "^14.0.0",
"@material/drawer": "^14.0.0",
"@material/elevation": "^14.0.0",
"@material/feature-targeting": "^14.0.0",
Expand All @@ -54,7 +52,6 @@
"@material/select": "^14.0.0",
"@material/shape": "^14.0.0",
"@material/theme": "^14.0.0",
"@material/touch-target": "^14.0.0",
"@material/typography": "^14.0.0",
"@tylertech/forge-core": "^2.3.0",
"@tylertech/tyler-icons": "^1.12.0",
Expand Down
19 changes: 19 additions & 0 deletions src/dev/pages/button-toggle/button-toggle.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,25 @@
</div>
</forge-card>
</section>

<!-- Legacy -->
<section>
<h3 class="forge-typography--heading2">Legacy (custom)</h3>
<forge-button-toggle-group class="legacy-button-toggle-group" value="email" aria-label="Custom button toggle group">
<forge-button-toggle value="email">
<forge-icon name="email" slot="start"></forge-icon>
By email
</forge-button-toggle>
<forge-button-toggle value="mail">
<forge-icon name="mail" slot="start"></forge-icon>
By mail
</forge-button-toggle>
<forge-button-toggle value="phone">
<forge-icon name="phone" slot="start"></forge-icon>
By phone
</forge-button-toggle>
</forge-button-toggle-group>
</section>
</div>

<script type="module" src="button-toggle.ts"></script>
2 changes: 1 addition & 1 deletion src/dev/pages/button-toggle/button-toggle.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
type: 'select',
label: 'Theme',
id: 'opt-theme',
defaultValue: 'primary',
defaultValue: 'tertiary',
options: [
{ label: 'Primary', value: 'primary' },
{ label: 'Secondary', value: 'secondary' },
Expand Down
37 changes: 37 additions & 0 deletions src/dev/pages/button-toggle/button-toggle.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@use '../../../lib/button-toggle/button-toggle-group';
@use '../../../lib/button-toggle/button-toggle';
@use '../../../lib/core/styles/theme';

#toolbar-card {
display: inline-block;
Expand All @@ -16,4 +18,39 @@
height: auto;
margin-block: 4px;
}
}

.legacy-button-toggle-group {
@include button-toggle-group.provide-theme((
gap: 1px,
padding: 0
));

forge-button-toggle {
@include button-toggle.provide-theme((
selected-color: theme.variable(on-primary),
selected-background: theme.variable(primary),
focus-indicator-offset: 2px
));

&:first-of-type {
@include button-toggle.provide-theme((
shape-start-end: 0,
shape-end-end: 0
));
}

&:not(:first-of-type):not(:last-of-type) {
@include button-toggle.provide-theme((
shape: 0
));
}

&:last-of-type {
@include button-toggle.provide-theme((
shape-start-start: 0,
shape-end-start: 0
));
}
}
}
29 changes: 21 additions & 8 deletions src/dev/pages/theme/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ interface ISwatchGroup {

interface ISwatch {
text?: string;
background: string;
background?: string;
border?: string;
noBorder?: boolean;
foreground?: string;
}

Expand Down Expand Up @@ -105,17 +107,19 @@ const SWATCH_GROUPS: ISwatchGroup[] = [
{
header: 'Text',
swatches: [
{ text: 'High', background: 'text-high', foreground: 'text-high-inverse' },
{ text: 'Medium', background: 'text-medium', foreground: 'text-high-inverse' },
{ text: 'Low', background: 'text-low', foreground: 'text-high' },
{ text: 'Lowest', background: 'text-lowest', foreground: 'text-high' }
{ text: 'High (87%)', foreground: 'text-high', noBorder: true },
{ text: 'Medium (60%)', foreground: 'text-medium', noBorder: true },
{ text: 'Low (38%)', foreground: 'text-low', noBorder: true },
{ text: 'Lowest (12%)', foreground: 'text-lowest', noBorder: true }
]
},
{
header: 'Utilities',
swatches: [
{ text: 'Outline', background: 'outline', foreground: 'text-high' },
{ text: 'Outline (high)', background: 'outline-high', foreground: 'text-high-inverse' }
{ text: 'Outline (high)', border: 'outline-high' },
{ text: 'Outline (medium)', border: 'outline-medium' },
{ text: 'Outline (low)', border: 'outline-low' },
{ text: 'Outline', border: 'outline' }
]
}
];
Expand Down Expand Up @@ -148,7 +152,16 @@ function createSwatch(config: ISwatch): HTMLElement {
if (config.text) {
swatch.textContent = config.text;
}
swatch.style.setProperty('background-color', `var(--forge-theme-${config.background})`);

if (config.border && !config.noBorder) {
swatch.style.setProperty('border-color', `var(--forge-theme-${config.border})`);
} else if (config.noBorder) {
swatch.style.setProperty('border', 'none');
}

if (config.background) {
swatch.style.setProperty('background-color', `var(--forge-theme-${config.background})`);
}

if (config.foreground) {
swatch.style.setProperty('color', `var(--forge-theme-${config.foreground})`);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { COMPONENT_NAME_PREFIX, Theme } from '../../constants';
import { supportsElementInternalsAria } from '../../core';
import { ARIAAttribute } from '../../core/utils/a11y-utils';

const elementName: keyof HTMLElementTagNameMap = `${COMPONENT_NAME_PREFIX}button-toggle-group`;

Expand All @@ -18,8 +16,6 @@ const observedAttributes = {
THEME: 'theme'
};

const observedAriaAttributes: ARIAAttribute[] = supportsElementInternalsAria() ? [] : ['role', 'aria-label'];

const attributes = {
...observedAttributes
};
Expand All @@ -40,7 +36,6 @@ const events = {
export const BUTTON_TOGGLE_GROUP_CONSTANTS = {
elementName,
observedAttributes,
observedAriaAttributes,
attributes,
classes,
selectors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class ButtonToggleGroupFoundation implements IButtonToggleGroupFoundation
private _disabled = false;
private _readonly = false;
private _required = false;
private _theme: ButtonToggleGroupTheme = 'primary';
private _theme: ButtonToggleGroupTheme = 'tertiary';

private _selectListener: (evt: CustomEvent<IButtonToggleSelectEventData>) => void;
private _slotListener: () => void;
Expand Down Expand Up @@ -233,7 +233,7 @@ export class ButtonToggleGroupFoundation implements IButtonToggleGroupFoundation
public set theme(value: ButtonToggleGroupTheme) {
if (this._theme !== value) {
this._theme = value;
this._adapter.toggleHostAttribute(BUTTON_TOGGLE_GROUP_CONSTANTS.attributes.THEME, this._theme !== 'primary', this._theme);
this._adapter.toggleHostAttribute(BUTTON_TOGGLE_GROUP_CONSTANTS.attributes.THEME, this._theme !== 'tertiary', this._theme);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,15 @@ $_host-tokens: [display];
::slotted(forge-button-toggle) {
@include button-toggle.provide-theme((
selected-background: #{theme.variable(#{$theme}-container-low)},
selected-color: #{theme.variable($theme)},
selected-color: #{theme.variable(on-#{$theme}-container-low)},
focus-indicator-color: #{theme.variable($theme)}
));
}
}
}

@include theme(primary);
@include theme(secondary);
@include theme(tertiary);
@include theme(success);
@include theme(error);
@include theme(warning);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ButtonToggleComponent } from '../button-toggle/button-toggle';
import { ButtonToggleGroupAdapter } from './button-toggle-group-adapter';
import { ButtonToggleGroupTheme, BUTTON_TOGGLE_GROUP_CONSTANTS, IButtonToggleGroupChangeEventData } from './button-toggle-group-constants';
import { ButtonToggleGroupFoundation } from './button-toggle-group-foundation';
import { getFormState, getFormValue, inputType, observedDefaultAriaAttributes, setDefaultAria } from '../../constants';
import { getFormState, getFormValue, inputType, setDefaultAria } from '../../constants';
import { FormValue, FormRestoreState, FormRestoreReason } from '../../core/utils/form-utils';
import { IWithDefaultAria, WithDefaultAria } from '../../core/mixins/internals/with-default-aria';

Expand Down Expand Up @@ -100,14 +100,9 @@ const BaseButtonToggleGroupClass = WithLabelAwareness(WithFormAssociation(WithFo
})
export class ButtonToggleGroupComponent extends BaseButtonToggleGroupClass implements IButtonToggleGroupComponent {
public static get observedAttributes(): string[] {
return [
...Object.values(BUTTON_TOGGLE_GROUP_CONSTANTS.observedAttributes),
...Object.values(BUTTON_TOGGLE_GROUP_CONSTANTS.observedAriaAttributes)
];
return Object.values(BUTTON_TOGGLE_GROUP_CONSTANTS.observedAttributes);
}

public readonly [observedDefaultAriaAttributes] = BUTTON_TOGGLE_GROUP_CONSTANTS.observedAriaAttributes;

private _foundation: ButtonToggleGroupFoundation;

constructor() {
Expand All @@ -118,7 +113,7 @@ export class ButtonToggleGroupComponent extends BaseButtonToggleGroupClass imple
}

public connectedCallback(): void {
this[setDefaultAria]({ role: 'group' });
this[setDefaultAria]({ role: 'group' }, { setAttribute: !this.hasAttribute('role') });
this._foundation.initialize();
}

Expand Down
6 changes: 3 additions & 3 deletions src/lib/button-toggle/button-toggle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ describe('Button Toggle', () => {
expect(harness.buttonToggles.every(toggle => toggle.getAttribute('aria-pressed') === 'false')).to.be.true;
});

['primary', 'secondary', 'danger', 'success', 'warning', 'info'].forEach((theme: ButtonToggleGroupTheme) => {
['primary', 'secondary', 'tertiary', 'danger', 'success', 'warning', 'info'].forEach((theme: ButtonToggleGroupTheme) => {
it(`should be accessible with selected values for theme ${theme}`, async () => {
const harness = await createFixture({ theme, value: 'two' });

// Primary is the default
if (theme !== 'primary') {
// tertiary is the default
if (theme !== 'tertiary') {
expect(harness.element.getAttribute(BUTTON_TOGGLE_GROUP_CONSTANTS.attributes.THEME)).to.equal(theme);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ export class ButtonToggleAdapter extends BaseAdapter<IButtonToggleComponent> imp
}

public initialize(): void {
this._component[setDefaultAria]({ role: 'button' }, { setAttribute: !this._component.hasAttribute('role') });
this._component[setDefaultAria]({
role: 'button',
ariaPressed: `${!!this._component.selected}`,
ariaDisabled: `${!!this._component.disabled}`
});
this._component[isFocusable] = !this._component.disabled;
}

public setSelected(value: boolean): void {
this._component[setDefaultAria]({ ariaPressed: `${!!value}` }, { overwrite: true });
this._component[setDefaultAria]({ ariaPressed: `${!!value}` });
}

public setDisabled(value: boolean): void {
this._component[setDefaultAria]({ ariaDisabled: `${!!value}` }, { overwrite: true });
this._component[setDefaultAria]({ ariaDisabled: `${!!value}` });
this._component[isFocusable] = !value;
this._stateLayerElement.disabled = value;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { COMPONENT_NAME_PREFIX } from '../../constants';
import { supportsElementInternalsAria } from '../../core';
import { ARIAAttribute } from '../../core/utils/a11y-utils';

const elementName: keyof HTMLElementTagNameMap = `${COMPONENT_NAME_PREFIX}button-toggle`;

Expand All @@ -12,8 +10,6 @@ const observedAttributes = {
TABINDEX: 'tabindex' // Need this to support the focusable mixin
};

const observedAriaAttributes: ARIAAttribute[] = supportsElementInternalsAria() ? [] : ['role', 'aria-pressed', 'aria-disabled'];

const attributes = {
...observedAttributes
};
Expand All @@ -25,7 +21,6 @@ const events = {
export const BUTTON_TOGGLE_CONSTANTS = {
elementName,
observedAttributes,
observedAriaAttributes,
attributes,
events
};
Expand Down
9 changes: 7 additions & 2 deletions src/lib/button-toggle/button-toggle/button-toggle.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@ $_host-tokens: [display];

forge-focus-indicator {
@include focus-indicator.provide-theme((
outward-offset: 0px, // Requires unit
color: #{token(focus-indicator-color)}
outward-offset: #{token(focus-indicator-offset)},
color: #{token(focus-indicator-color)},
shape: #{token(shape)},
shape-start-start: #{token(shape-start-start)},
shape-start-end: #{token(shape-start-end)},
shape-end-start: #{token(shape-end-start)},
shape-end-end: #{token(shape-end-end)},
));
}
}
Expand Down
9 changes: 2 additions & 7 deletions src/lib/button-toggle/button-toggle/button-toggle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { attachShadowTemplate, coerceBoolean, CustomElement, FoundationProperty } from '@tylertech/forge-core';
import { ExperimentalFocusOptions, observedDefaultAriaAttributes } from '../../constants';
import { ExperimentalFocusOptions } from '../../constants';
import { IWithFocusable, WithFocusable } from '../../core/mixins/focus/with-focusable';
import { IWithElementInternals, WithElementInternals } from '../../core/mixins/internals/with-element-internals';
import { FocusIndicatorComponent } from '../../focus-indicator';
Expand Down Expand Up @@ -95,14 +95,9 @@ const BaseButtonToggleClass = WithDefaultAria(WithElementInternals(WithFocusable
})
export class ButtonToggleComponent<T = unknown> extends BaseButtonToggleClass implements IButtonToggleComponent {
public static get observedAttributes(): string[] {
return [
...Object.values(BUTTON_TOGGLE_CONSTANTS.observedAttributes),
...Object.values(BUTTON_TOGGLE_CONSTANTS.observedAriaAttributes)
];
return Object.values(BUTTON_TOGGLE_CONSTANTS.observedAttributes);
}

public readonly [observedDefaultAriaAttributes] = BUTTON_TOGGLE_CONSTANTS.observedAriaAttributes;

private _foundation: ButtonToggleFoundation;

constructor() {
Expand Down
Loading