Skip to content

Commit c531d81

Browse files
authored
fix: use Stencil watchers instead of global attributes util (#8407)
**Related Issue:** #8193 ## Summary Stencil v4 allows [watching global attributes](https://stenciljs.com/docs/reactive-data#watching-native-html-attributes) on components, so we no longer need our custom util for this.
1 parent ff0720f commit c531d81

File tree

5 files changed

+46
-271
lines changed

5 files changed

+46
-271
lines changed

packages/calcite-components/conventions/README.md

+1-39
Original file line numberDiff line numberDiff line change
@@ -366,45 +366,7 @@ There are utilities for common workflows in [`src/utils`](../src/utils).
366366

367367
### Global attributes
368368

369-
The [`globalAttributes`](../src/utils/globalAttributes.ts) util was specifically made to access the `lang` global attribute when set on a Calcite component. However, it can be extended to allow additional [global attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#list_of_global_attributes) by adding to the [`allowedGlobalAttributes`](https://github.com/Esri/calcite-design-system/blob/a33aa0df0c5bf103f91187826e6b12b8ff266d90/src/utils/globalAttributes.ts#L4-L5) array. The util is used in [`calcite-pagination`](../src/components/pagination/pagination.tsx), which you can use as a reference.
370-
371-
#### Usage steps
372-
373-
1. Import the interface and watch/unwatch methods
374-
375-
```js
376-
import { GlobalAttrComponent, watchGlobalAttributes, unwatchGlobalAttributes } from "../../utils/globalAttributes";
377-
```
378-
379-
2. Implement the interface
380-
381-
```js
382-
export class ComponentName implements GlobalAttrComponent {
383-
```
384-
385-
3. Add `globalAttributes` state
386-
387-
```js
388-
@State() globalAttributes = {};
389-
```
390-
391-
4. Add connect/disconnect callbacks
392-
393-
```js
394-
connectedCallback(): void {
395-
watchGlobalAttributes(this, ["lang"]);
396-
}
397-
398-
disconnectedCallback(): void {
399-
unwatchGlobalAttributes(this);
400-
}
401-
```
402-
403-
5. Use the state to access `lang` (or another global attribute that may be allowed in the future).
404-
405-
```js
406-
const lang = this.globalAttributes["lang"] || document.documentElement.lang || "en";
407-
```
369+
Watching global attributes on components is now possible with Stencil v4. Please refer to the [documentation page](https://stenciljs.com/docs/reactive-data#watching-native-html-attributes) for more information.
408370

409371
### BigDecimal
410372

packages/calcite-components/src/components/button/button.tsx

+24-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
import { Build, Component, Element, h, Method, Prop, State, VNode, Watch } from "@stencil/core";
1+
import {
2+
Build,
3+
Component,
4+
Element,
5+
forceUpdate,
6+
h,
7+
Method,
8+
Prop,
9+
State,
10+
VNode,
11+
Watch,
12+
} from "@stencil/core";
213
import { findAssociatedForm, FormOwner, resetForm, submitForm } from "../../utils/form";
314
import {
415
connectInteractive,
@@ -27,11 +38,6 @@ import { Appearance, FlipContext, Kind, Scale, Width } from "../interfaces";
2738
import { ButtonMessages } from "./assets/button/t9n";
2839
import { ButtonAlignment } from "./interfaces";
2940
import { CSS } from "./resources";
30-
import {
31-
GlobalAttrComponent,
32-
unwatchGlobalAttributes,
33-
watchGlobalAttributes,
34-
} from "../../utils/globalAttributes";
3541
import { toAriaBoolean } from "../../utils/dom";
3642

3743
/** Passing a 'href' will render an anchor link, instead of a button. Role will be set to link, or button, depending on this. */
@@ -46,7 +52,6 @@ import { toAriaBoolean } from "../../utils/dom";
4652
})
4753
export class Button
4854
implements
49-
GlobalAttrComponent,
5055
LabelableComponent,
5156
InteractiveComponent,
5257
FormOwner,
@@ -56,6 +61,17 @@ export class Button
5661
{
5762
//--------------------------------------------------------------------------
5863
//
64+
// Global attributes
65+
//
66+
//--------------------------------------------------------------------------
67+
68+
@Watch("aria-expanded")
69+
handleGlobalAttributesChanged(): void {
70+
forceUpdate(this);
71+
}
72+
73+
// --------------------------------------------------------------------------
74+
//
5975
// Properties
6076
//
6177
//--------------------------------------------------------------------------
@@ -183,7 +199,6 @@ export class Button
183199
connectInteractive(this);
184200
connectLocalized(this);
185201
connectMessages(this);
186-
watchGlobalAttributes(this, ["aria-expanded"]);
187202
this.hasLoader = this.loading;
188203
this.setupTextContentObserver();
189204
connectLabel(this);
@@ -198,7 +213,6 @@ export class Button
198213
disconnectMessages(this);
199214
this.resizeObserver?.disconnect();
200215
this.formEl = null;
201-
unwatchGlobalAttributes(this);
202216
}
203217

204218
async componentWillLoad(): Promise<void> {
@@ -260,6 +274,7 @@ export class Button
260274
return (
261275
<Tag
262276
aria-disabled={childElType === "a" ? toAriaBoolean(this.disabled || this.loading) : null}
277+
aria-expanded={this.el.getAttribute("aria-expanded")}
263278
aria-label={!this.loading ? getLabelText(this) : this.messages.loading}
264279
aria-live="polite"
265280
class={{
@@ -278,7 +293,6 @@ export class Button
278293
target={childElType === "a" && this.target}
279294
title={this.tooltipText}
280295
type={childElType === "button" && this.type}
281-
{...this.globalAttributes}
282296
// eslint-disable-next-line react/jsx-sort-props -- ref should be last so node attrs/props are in sync (see https://github.com/Esri/calcite-design-system/pull/6530)
283297
ref={this.setChildEl}
284298
>
@@ -357,10 +371,6 @@ export class Button
357371

358372
resizeObserver = createObserver("resize", () => this.setTooltipText());
359373

360-
@State() globalAttributes = {
361-
ariaExpanded: undefined,
362-
};
363-
364374
//--------------------------------------------------------------------------
365375
//
366376
// Private Methods

packages/calcite-components/src/components/menu/menu.tsx

+21-17
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Watch,
1010
Method,
1111
VNode,
12+
forceUpdate,
1213
} from "@stencil/core";
1314
import { focusElement, focusElementInGroup, slotChangeGetAssignedElements } from "../../utils/dom";
1415
import {
@@ -26,11 +27,6 @@ import {
2627
updateMessages,
2728
} from "../../utils/t9n";
2829
import { MenuMessages } from "./assets/menu/t9n";
29-
import {
30-
GlobalAttrComponent,
31-
unwatchGlobalAttributes,
32-
watchGlobalAttributes,
33-
} from "../../utils/globalAttributes";
3430

3531
type Layout = "horizontal" | "vertical";
3632

@@ -42,12 +38,22 @@ type Layout = "horizontal" | "vertical";
4238
},
4339
assetsDirs: ["assets"],
4440
})
45-
export class CalciteMenu
46-
implements GlobalAttrComponent, LocalizedComponent, T9nComponent, LoadableComponent
47-
{
41+
export class CalciteMenu implements LocalizedComponent, T9nComponent, LoadableComponent {
4842
//--------------------------------------------------------------------------
4943
//
50-
// Public Properties
44+
// Global attributes
45+
//
46+
//--------------------------------------------------------------------------
47+
48+
@Watch("role")
49+
handleGlobalAttributesChanged(): void {
50+
forceUpdate(this);
51+
this.setMenuItemLayout(this.menuItems, this.layout);
52+
}
53+
54+
//--------------------------------------------------------------------------
55+
//
56+
// Properties
5157
//
5258
//--------------------------------------------------------------------------
5359

@@ -102,10 +108,6 @@ export class CalciteMenu
102108
updateMessages(this, this.effectiveLocale);
103109
}
104110

105-
@State() globalAttributes = {
106-
role: "menubar",
107-
};
108-
109111
menuItems: HTMLCalciteMenuItemElement[] = [];
110112

111113
//--------------------------------------------------------------------------
@@ -117,7 +119,6 @@ export class CalciteMenu
117119
connectedCallback(): void {
118120
connectLocalized(this);
119121
connectMessages(this);
120-
watchGlobalAttributes(this, ["role"]);
121122
}
122123

123124
async componentWillLoad(): Promise<void> {
@@ -132,7 +133,6 @@ export class CalciteMenu
132133
disconnectedCallback(): void {
133134
disconnectLocalized(this);
134135
disconnectMessages(this);
135-
unwatchGlobalAttributes(this);
136136
}
137137

138138
//--------------------------------------------------------------------------
@@ -220,13 +220,17 @@ export class CalciteMenu
220220
setMenuItemLayout(items: HTMLCalciteMenuItemElement[], layout: Layout): void {
221221
items.forEach((item) => {
222222
item.layout = layout;
223-
if (this.globalAttributes.role === "menubar") {
223+
if (this.getEffectiveRole() === "menubar") {
224224
item.isTopLevelItem = true;
225225
item.topLevelMenuLayout = this.layout;
226226
}
227227
});
228228
}
229229

230+
private getEffectiveRole(): string {
231+
return this.el.getAttribute("role") || "menubar";
232+
}
233+
230234
// --------------------------------------------------------------------------
231235
//
232236
// Render Methods
@@ -236,7 +240,7 @@ export class CalciteMenu
236240
render(): VNode {
237241
return (
238242
<Host>
239-
<ul aria-label={this.label} {...this.globalAttributes}>
243+
<ul aria-label={this.label} role={this.getEffectiveRole()}>
240244
<slot onSlotchange={this.handleMenuSlotChange} />
241245
</ul>
242246
</Host>

packages/calcite-components/src/utils/globalAttributes.spec.ts

-97
This file was deleted.

0 commit comments

Comments
 (0)