Skip to content

Commit

Permalink
feat: adding directional stylesheet behavior (microsoft#3559)
Browse files Browse the repository at this point in the history
* adding directional stylesheet behavior

* fixing documentation

* Update packages/web-components/fast-components/docs/design/localization.md

Co-authored-by: Jane Chu <7559015+janechu@users.noreply.github.com>

* align imports and doc links

Co-authored-by: nicholasrice <nicholasrice@users.noreply.github.com>
Co-authored-by: Jane Chu <7559015+janechu@users.noreply.github.com>
  • Loading branch information
3 people authored Jul 28, 2020
1 parent 6c6ec43 commit 74c19af
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
id: localization
title: Localization
custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-components/docs/design/localization.md
---

## Document Direction
Many CSS layout properties like [flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) and [CSS grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout) automatically handle reflow depending on the [document's primary direction](https://www.w3.org/International/questions/qa-html-dir). There are also CSS [logical properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Logical_Properties/Basic_concepts) that can be used as well to apply localized margins, paddings, borders and positioning. Unfortunately, browser support for these properties is limited and there are still styling cases not covered by these properties (directional glyphs, transforms, etc). That is why FAST provides several mechanisms to apply direction-based styles.

### DesignSystemProvider
The [`FASTDesignSystemProvider`](/docs/api/fast-components.fastdesignsystemprovider/) exposes a `direction` property. This should be set to the primary document direction and defaults to `ltr`. This value will be used to inform the stylesheet behaviors described below.

### `inlineStartBehavior` and `inlineEndBehavior`
[inlineStartBehavior](/docs/api/fast-components.inlinestartbehavior/) and [inlineEndBehavior](/docs/api/fast-components.inlineendbehavior/) can be used to apply localized [float](https://developer.mozilla.org/en-US/docs/Web/CSS/float) properties. These are drop-in replacements for the browsers `inline-start` and `inline-end` float values and should be used when the native values are not supported. If your browser-matrix supports `inline-start` and `inline-end` float values, please use the native values.

**Example: Using `inlineStartBehavior` and `inlineEndBehavior`**
```ts
import { css } from "@microsoft/fast-element";
import { inlineStartBehavior } from "@microsoft/fast-components";

const styles = css`
:host {
float: ${inlineStartBehavior.var}
}
`.withBehaviors(inlineStartBehavior)
```

### DirectionalStyleSheetBehavior
[`DirectionalStyleSheetBehavior`](/docs/api/fast-foundation.directionalstylesheetbehavior/) can be used to apply arbitrary LTR and RTL stylesheets, depending on the nearest [`FASTDesignSystemProvider`s direction](/docs/api/fast-components.fastdesignsystemprovider.direction/) property.

**Example: Using `DirectionalStyleSheetBehavior`**
```ts
import { css } from "@microsoft/fast-element";
import { DirectionalStyleSheetBehavior } from "@microsoft/fast-components";

const ltr = css`
:host {
left: 20px;
}
`;

const rtl = css`
:host {
right: 20px;
}
`;

const styles = css`
.host {
position: relative
}
`.withBehaviors(new DirectionalStyleSheetBehavior(ltr, rtl))
```
11 changes: 11 additions & 0 deletions packages/web-components/fast-foundation/docs/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,9 @@ export class DesignSystemProvider extends FASTElement implements CSSCustomProper
designSystemProperties: {
[propertyName: string]: Required<Pick<DecoratorDesignSystemPropertyConfiguration, "cssCustomProperty" | "default">>;
};
// @deprecated
disconnectedCSSCustomPropertyRegistry: CSSCustomPropertyDefinition[];
disconnectedRegistry: Array<(provider: DesignSystemProvider) => void> | void;
evaluate(definition: CSSCustomPropertyDefinition): string;
static findProvider(el: HTMLElement & Partial<DesignSystemConsumer>): DesignSystemProvider | null;
static isDesignSystemProvider(el: HTMLElement | DesignSystemProvider): el is DesignSystemProvider;
Expand Down Expand Up @@ -299,6 +301,15 @@ export class Dialog extends FASTElement {
// @public
export const DialogTemplate: import("@microsoft/fast-element").ViewTemplate<Dialog, any>;

// @public
export class DirectionalStyleSheetBehavior implements Behavior {
constructor(ltr: ElementStyles | null, rtl: ElementStyles | null);
// @internal (undocumented)
bind(source: typeof FASTElement & HTMLElement): void;
// @internal (undocumented)
unbind(source: typeof FASTElement & HTMLElement): void;
}

// @public
export const disabledCursor = "not-allowed";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
CSSCustomPropertyDefinition,
CSSCustomPropertyTarget,
} from "../custom-properties/index";
import { composedParent } from "../utilities/index";
import { composedParent } from "../utilities/composed-parent";
import { DecoratorDesignSystemPropertyConfiguration } from "./design-system-property";

const supportsAdoptedStylesheets = "adoptedStyleSheets" in window.ShadowRoot.prototype;
Expand Down Expand Up @@ -245,9 +245,19 @@ export class DesignSystemProvider extends FASTElement
* are defined before this DesignSystemProvider.
*
* @public
* @deprecated - use disconnectedRegistry
*/
public disconnectedCSSCustomPropertyRegistry: CSSCustomPropertyDefinition[];

/**
* Allows arbitrary registration to the provider before the constructor runs.
* When the constructor runs, all registration functions in the disconnectedRegistry
* will be invoked with the provider instance.
*
* @public
*/
public disconnectedRegistry: Array<(provider: DesignSystemProvider) => void> | void;

/**
* The target of CSSCustomPropertyDefinitions registered
* with the provider. This will be #1 when adoptedStyleSheets are supported
Expand Down Expand Up @@ -367,6 +377,14 @@ export class DesignSystemProvider extends FASTElement

delete this.disconnectedCSSCustomPropertyRegistry;
}

if (Array.isArray(this.disconnectedRegistry)) {
for (let i = 0; i < this.disconnectedRegistry.length; i++) {
this.disconnectedRegistry[i](this);
}

delete this.disconnectedRegistry;
}
}

/**
Expand Down Expand Up @@ -450,6 +468,7 @@ export class DesignSystemProvider extends FASTElement
definition.value({ ...this.designSystem })
: definition.value;
}

/**
* Synchronize the provider's design system with the local
* overrides. Any value defined on the instance will take priority
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
ElementStyles,
Behavior,
FASTElement,
Subscriber,
Observable,
} from "@microsoft/fast-element";
import { DesignSystemProvider } from "../../design-system-provider";
import { Direction } from "@microsoft/fast-web-utilities";

/**
* Behavior to conditionally apply LTR and RTL stylesheets. To determine which to apply,
* the behavior will use the nearest DesignSystemProvider's 'direction' design system value.
*
* @public
* @example
* ```ts
* import { css } from "@microsoft/fast-element";
* import { DirectionalStyleSheetBehavior } from "@microsoft/fast-foundation";
*
* css`
* // ...
* `.withBehaviors(new DirectionalStyleSheetBehavior(
* css`:host { content: "ltr"}`),
* css`:host { content: "rtl"}`),
* )
* ```
*/
export class DirectionalStyleSheetBehavior implements Behavior {
private ltr: ElementStyles | null;
private rtl: ElementStyles | null;
private cache: WeakMap<
HTMLElement,
[DesignSystemProvider, DirectionalStyleSheetBehaviorSubscription]
> = new WeakMap();

constructor(ltr: ElementStyles | null, rtl: ElementStyles | null) {
this.ltr = ltr;
this.rtl = rtl;
}

/**
* @internal
*/
public bind(source: typeof FASTElement & HTMLElement) {
const provider = DesignSystemProvider.findProvider(source);

if (provider !== null) {
if (provider.$fastController && provider.$fastController.isConnected) {
this.attach(source, provider);
} else {
if (!Array.isArray(provider.disconnectedRegistry)) {
provider.disconnectedRegistry = [];
}

provider.disconnectedRegistry.push(this.attach.bind(this, source));
}
}
}

/**
* @internal
*/
public unbind(source: typeof FASTElement & HTMLElement) {
const cache = this.cache.get(source);

if (cache) {
Observable.getNotifier(cache[0].designSystem).unsubscribe(cache[1]);
}
}

private attach(
source: typeof FASTElement & HTMLElement,
provider: DesignSystemProvider
) {
const subscriber = new DirectionalStyleSheetBehaviorSubscription(
this.ltr,
this.rtl,
source
);
Observable.getNotifier(provider.designSystem).subscribe(subscriber, "direction");
subscriber.attach(provider.designSystem["direction"]);

this.cache.set(source, [provider, subscriber]);
}
}

/**
* Subscription for {@link DirectionalStyleSheetBehavior}
*/
class DirectionalStyleSheetBehaviorSubscription implements Subscriber {
private attached: ElementStyles | null = null;

constructor(
private ltr: ElementStyles | null,
private rtl: ElementStyles | null,
private source: HTMLElement
) {}

public handleChange(source: any) {
this.attach(source.direction);
}

public attach(direction: Direction) {
if (this.attached !== this[direction] && this.source?.shadowRoot) {
this.attached?.removeStylesFrom(this.source.shadowRoot);
this[direction]?.addStylesTo(this.source.shadowRoot);
this.attached = this[direction];
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./disabled";
export * from "./display";
export * from "./focus";
export * from "./direction";
1 change: 1 addition & 0 deletions sites/website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ module.exports = {
"design/design-system",
"design/type-ramp",
"design/color",
"design/localization",
"design/match-media-stylesheets",
],
},
Expand Down

0 comments on commit 74c19af

Please sign in to comment.