Skip to content

Commit 746579f

Browse files
authored
chore: remove ElementStyles.withBehaviors (#7483)
# Pull Request ## 📖 Description Removes `ElementStyles.withBehaviors()` and the remaining stylesheet behavior-composition path from `@microsoft/fast-element`. This change also: - removes CSS bindings in `css` - removes stylesheet-attached behavior composition from `css` and `css.partial()` - keeps `CSSDirective` as a static CSS extension point via `createCSS(): ComposableStyles` - keeps runtime stylesheet toggling on `ElementController.addStyles()` / `removeStyles()` This also updates the related Playwright coverage, migration guidance, package docs, and regenerated 3.x API and export-size documentation. ### 🎫 Issues - Closes #7244 ## 📑 Test Plan - `npm run build` - `npm run prebuild -w sites/website` - `npm run biome:check` - `npm run checkchange` - `npm run test` - `npm run test:playwright -w @microsoft/fast-element -- -x --reporter=line` ## ✅ Checklist ### General - [x] I have included a change request file using `$ npm run change` - [x] I have added tests for my changes. - [x] I have tested my changes. - [x] I have updated the project documentation to reflect my changes. - [x] I have read the [CONTRIBUTING](https://github.com/microsoft/fast/blob/main/CONTRIBUTING.md) documentation and followed the [standards](https://github.com/microsoft/fast/blob/main/CODE_OF_CONDUCT.md#our-standards) for this project.
1 parent bd4550a commit 746579f

37 files changed

Lines changed: 184 additions & 1974 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "major",
3+
"comment": "Remove ElementStyles.withBehaviors, CSS style behaviors, and CSS bindings in fast-element.",
4+
"packageName": "@microsoft/fast-element",
5+
"email": "7559015+janechu@users.noreply.github.com",
6+
"dependentChangeType": "none"
7+
}

packages/fast-element/DESIGN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ See [ARCHITECTURE_UPDATES.md](./ARCHITECTURE_UPDATES.md) for more detail.
276276

277277
**Files**: `src/styles/css.ts`, `src/styles/element-styles.ts`, `src/styles/css-directive.ts`
278278

279-
The `css` tag (analogous to `html`) builds `ElementStyles` objects. During `ElementController.connect()`, styles are applied to the element's shadow root either via `adoptedStylesheets` (preferred) or an appended `<style>` node, depending on platform support. Styles can also contain dynamic `CSSDirective`s (e.g., CSS custom property bindings) that register as `HostBehavior`s and connect/disconnect alongside the element.
279+
The `css` tag (analogous to `html`) builds `ElementStyles` objects. During `ElementController.connect()`, styles are applied to the element's shadow root either via `adoptedStylesheets` (preferred) or an appended `<style>` node, depending on platform support. `CSSDirective`s can contribute additional static CSS during template composition, but runtime CSS bindings and style-attached `HostBehavior`s are not supported. Arbitrary runtime style toggling is handled through `ElementController.addStyles()` / `removeStyles()`; `ElementStyles` itself is a static container.
280280

281281
---
282282

packages/fast-element/MIGRATION.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,33 @@ This is a **breaking change** for SSR output format. Any system that produces or
172172
4. Add `await` to `compose()` calls that chain `.define()`:
173173

174174
```typescript
175-
// Before
176-
FASTElementDefinition.compose(MyElement, options).define();
175+
// Before
176+
FASTElementDefinition.compose(MyElement, options).define();
177177

178-
// After
179-
(await FASTElementDefinition.compose(MyElement, options)).define();
178+
// After
179+
(await FASTElementDefinition.compose(MyElement, options)).define();
180180
```
181+
182+
## Dynamic stylesheet behaviors (v3)
183+
184+
### Removed API
185+
186+
| Removed | Replacement |
187+
|---|---|
188+
| `ElementStyles.withBehaviors()` | Move the runtime condition into the element and call `this.$fastController.addStyles()` / `this.$fastController.removeStyles()` directly. |
189+
| `ElementStyles.behaviors` | Move any runtime behavior out of the stylesheet and into the element or controller lifecycle. |
190+
| CSS bindings in `css` (for example ``css`color: ${x => x.color}```) | Move the dynamic value into the element and update classes, attributes, or inline styles from element code. |
191+
| `CSSDirective.createCSS(add)` | Update directives to implement `createCSS()` and return only static CSS content. |
192+
193+
### Changed behavior
194+
195+
- `css` and `css.partial()` no longer compose `HostBehavior`s.
196+
- `css` no longer accepts function or `Binding` interpolations.
197+
- `ElementStyles` is now a fully static style container.
198+
199+
### Migration steps
200+
201+
1. Keep the conditional `ElementStyles` in a separate `css` value.
202+
2. Move the external listener or condition (for example `matchMedia()` or an app event subscription) into the element lifecycle.
203+
3. Call `this.$fastController.addStyles(styles)` when the condition is active and `this.$fastController.removeStyles(styles)` when it is inactive or during cleanup.
204+
4. If you previously interpolated bindings or behavior-producing directives into `css`, replace them with element state and standard DOM or controller updates.

packages/fast-element/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ importing `@microsoft/fast-element`.
6565

6666
Bundle sizes for each tree-shakeable export are tracked in [`SIZES.md`](./SIZES.md) and regenerated on every build. See the [Export Sizes](https://www.fast.design/docs/3.x/resources/export-sizes/) documentation page for the latest numbers.
6767

68+
## Dynamic Style Application
69+
70+
When runtime state or external signals need to add or remove styles, create the
71+
`ElementStyles` with `css` and toggle it through
72+
`this.$fastController.addStyles()` / `this.$fastController.removeStyles()` from
73+
the element lifecycle or change handlers.
74+
75+
`css` templates remain static style definitions. Runtime CSS bindings and
76+
behavior-producing CSS directives are no longer supported; keep the condition on
77+
the element and toggle a separate `ElementStyles` instance through the
78+
controller when styles need to change.
79+
6880
## Prerendered Content Optimization
6981

7082
When a FAST element connects and already has an existing shadow root (from server-side rendering or declarative shadow DOM), `ElementController` automatically detects this. The `isPrerendered` property on the controller is a `Promise<boolean>` that resolves to `true` after prerendered content has been hydrated, or `false` when the component is client-side rendered. This enables several optimizations:

packages/fast-element/SIZES.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ Bundle sizes for `@microsoft/fast-element` exports.
44

55
| Export | Minified | Gzip | Brotli |
66
|--------|----------|------|--------|
7-
| CDN Rollup Bundle | 64.76 KB | 19.24 KB | 17.23 KB |
8-
| FASTElement | 23.69 KB | 7.41 KB | 6.68 KB |
7+
| CDN Rollup Bundle | 63.05 KB | 18.81 KB | 16.84 KB |
8+
| FASTElement | 23.29 KB | 7.32 KB | 6.60 KB |
99
| Updates | 3.45 KB | 1.43 KB | 1.21 KB |
10-
| Observable | 7.96 KB | 2.94 KB | 2.61 KB |
11-
| observable | 8.00 KB | 2.95 KB | 2.63 KB |
10+
| Observable | 7.96 KB | 2.94 KB | 2.62 KB |
11+
| observable | 8.00 KB | 2.95 KB | 2.62 KB |
1212
| attr | 3.39 KB | 1.37 KB | 1.13 KB |
13-
| children | 5.99 KB | 2.29 KB | 2.01 KB |
14-
| css | 11.16 KB | 4.03 KB | 3.61 KB |
13+
| children | 5.99 KB | 2.29 KB | 2.02 KB |
14+
| css | 4.47 KB | 1.78 KB | 1.54 KB |
1515
| ref | 4.96 KB | 1.96 KB | 1.71 KB |
1616
| slotted | 5.78 KB | 2.23 KB | 1.95 KB |
17-
| volatile | 8.05 KB | 2.97 KB | 2.64 KB |
17+
| volatile | 8.05 KB | 2.97 KB | 2.63 KB |
1818
| when | 2.40 KB | 978 B | 786 B |
1919
| html | 27.13 KB | 8.88 KB | 7.96 KB |
2020
| repeat | 30.79 KB | 9.81 KB | 8.82 KB |

packages/fast-element/docs/api-report.api.md

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ export interface Accessor {
1111
setValue(source: any, value: any): void;
1212
}
1313

14-
// @public
15-
export type AddBehavior = (behavior: HostBehavior<HTMLElement>) => void;
16-
1714
// @public
1815
export type AddViewBehaviorFactory = (factory: ViewBehaviorFactory) => string;
1916

@@ -185,30 +182,9 @@ export interface ContentView {
185182
// @public
186183
export const css: CSSTemplateTag;
187184

188-
// @public
189-
export class CSSBindingDirective implements HostBehavior, Subscriber, CSSDirective, BindingDirective {
190-
constructor(dataBinding: Binding, targetAspect: string);
191-
addedCallback(controller: HostController<HTMLElement & {
192-
$cssBindings: Map<CSSBindingDirective, CSSBindingEntry>;
193-
}>): void;
194-
connectedCallback(controller: HostController<HTMLElement & {
195-
$cssBindings: Map<CSSBindingDirective, CSSBindingEntry>;
196-
}>): void;
197-
createCSS(add: AddBehavior): ComposableStyles;
198-
// (undocumented)
199-
readonly dataBinding: Binding;
200-
// @internal
201-
handleChange(_: any, observer: ExpressionObserver): void;
202-
removedCallback(controller: HostController<HTMLElement & {
203-
$cssBindings: Map<CSSBindingDirective, CSSBindingEntry>;
204-
}>): void;
205-
// (undocumented)
206-
readonly targetAspect: string;
207-
}
208-
209185
// @public
210186
export interface CSSDirective {
211-
createCSS(add: AddBehavior): ComposableStyles;
187+
createCSS(): ComposableStyles;
212188
}
213189

214190
// @public
@@ -227,12 +203,12 @@ export interface CSSDirectiveDefinition<TType extends Constructable<CSSDirective
227203
}
228204

229205
// @public
230-
export type CSSTemplateTag = (<TSource = any, TParent = any>(strings: TemplateStringsArray, ...values: CSSValue<TSource, TParent>[]) => ElementStyles) & {
231-
partial<TSource = any, TParent = any>(strings: TemplateStringsArray, ...values: CSSValue<TSource, TParent>[]): CSSDirective;
206+
export type CSSTemplateTag = ((strings: TemplateStringsArray, ...values: CSSValue[]) => ElementStyles) & {
207+
partial(strings: TemplateStringsArray, ...values: CSSValue[]): CSSDirective;
232208
};
233209

234210
// @public
235-
export type CSSValue<TSource, TParent = any> = Expression<TSource, any, TParent> | Binding<TSource, any, TParent> | ComposableStyles | CSSDirective;
211+
export type CSSValue = ComposableStyles | CSSDirective;
236212

237213
// @public
238214
export function customElement(nameOrDef: string | PartialFASTElementDefinition): (type: Constructable<HTMLElement>) => void;
@@ -346,7 +322,6 @@ export class ElementStyles {
346322
constructor(styles: ReadonlyArray<ComposableStyles>);
347323
// @internal (undocumented)
348324
addStylesTo(target: StyleTarget): void;
349-
readonly behaviors: ReadonlyArray<HostBehavior<HTMLElement>> | null;
350325
// @internal (undocumented)
351326
isAttachedTo(target: StyleTarget): boolean;
352327
static normalize(styles: ComposableStyles | ComposableStyles[] | undefined): ElementStyles | undefined;
@@ -357,7 +332,6 @@ export class ElementStyles {
357332
// (undocumented)
358333
readonly styles: ReadonlyArray<ComposableStyles>;
359334
static readonly supportsAdoptedStyleSheets: boolean;
360-
withBehaviors(...behaviors: HostBehavior<HTMLElement>[]): this;
361335
withStrategy(Strategy: ConstructibleStyleStrategy): this;
362336
}
363337

@@ -1114,7 +1088,6 @@ export function when<TSource = any, TReturn = any, TParent = any>(condition: Exp
11141088
// dist/dts/components/fast-element.d.ts:60:5 - (ae-forgotten-export) The symbol "define" needs to be exported by the entry point index.d.ts
11151089
// dist/dts/components/fast-element.d.ts:61:5 - (ae-forgotten-export) The symbol "compose" needs to be exported by the entry point index.d.ts
11161090
// dist/dts/components/fast-element.d.ts:62:5 - (ae-forgotten-export) The symbol "from" needs to be exported by the entry point index.d.ts
1117-
// dist/dts/styles/css-binding-directive.d.ts:35:9 - (ae-forgotten-export) The symbol "CSSBindingEntry" needs to be exported by the entry point index.d.ts
11181091

11191092
// (No @packageDocumentation comment for this package)
11201093

0 commit comments

Comments
 (0)