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

Anchored region #530

Merged
merged 15 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Create nimble-anchored-region",
"packageName": "@ni/nimble-components",
"email": "[email protected]",
"dependentChangeType": "patch"
}
1 change: 1 addition & 0 deletions packages/nimble-components/src/all-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* that are required instead of leveraging this file.
*/

import './anchored-region';
import './breadcrumb';
import './breadcrumb-item';
import './button';
Expand Down
28 changes: 28 additions & 0 deletions packages/nimble-components/src/anchored-region/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
DesignSystem,
AnchoredRegion as FoundationAnchoredRegion,
anchoredRegionTemplate as template
} from '@microsoft/fast-foundation';
import { styles } from './styles';

declare global {
interface HTMLElementTagNameMap {
'nimble-anchored-region': AnchoredRegion;
}
}

/**
* A nimble-styled anchored region control.
*/
export class AnchoredRegion extends FoundationAnchoredRegion {}

const nimbleAnchoredRegion = AnchoredRegion.compose({
baseName: 'anchored-region',
baseClass: FoundationAnchoredRegion,
template,
styles
});

DesignSystem.getOrCreate()
.withPrefix('nimble')
.register(nimbleAnchoredRegion());
9 changes: 9 additions & 0 deletions packages/nimble-components/src/anchored-region/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { css } from '@microsoft/fast-element';

export const styles = css`
:host {
contain: layout;
display: block;
z-index: 1000;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type { Meta, Story } from '@storybook/html';
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
import { html, ViewTemplate } from '@microsoft/fast-element';
import {
createMatrix,
sharedMatrixParameters
} from '../../utilities/tests/matrix';
import { createStory } from '../../utilities/tests/storybook';
import { hiddenWrapper } from '../../utilities/tests/hidden';
import '../../all-components';
import {
bodyFont,
bodyFontColor,
borderHoverColor,
applicationBackgroundColor
} from '../../theme-provider/design-tokens';

const metadata: Meta = {
title: 'Tests/AnchoredRegion',
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
parameters: {
...sharedMatrixParameters()
}
};

export default metadata;

const horizontalPositionStates = [
['Start', 'start'],
['End', 'end'],
['Left', 'left'],
['Right', 'right'],
['Center', 'center']
] as const;
type HorizontalPositionState = typeof horizontalPositionStates[number];

const verticalPositionStates = [
['Top', 'top'],
['Bottom', 'bottom'],
['Center', 'center']
] as const;
type VerticalPositionState = typeof verticalPositionStates[number];

const component = (
[horizontalPositionName, horizontalPosition]: HorizontalPositionState,
[verticalPositionName, verticalPosition]: VerticalPositionState
): ViewTemplate => html`<style>
.container {
display: inline-flex;
margin: 55px;
height: 75px;
width: 75px;
}

.anchor {
top: 25px;
left: 25px;
width: 75px;
height: 75px;
font: var(${bodyFont.cssCustomProperty});
color: var(${bodyFontColor.cssCustomProperty});
border: 1px solid var(${borderHoverColor.cssCustomProperty});
background: var(${applicationBackgroundColor.cssCustomProperty});
}

.anchoredRegion {
width: 50px;
height: 50px;
font: var(${bodyFont.cssCustomProperty});
color: var(${bodyFontColor.cssCustomProperty});
border: 1px solid var(${borderHoverColor.cssCustomProperty});
background: var(${applicationBackgroundColor.cssCustomProperty});
}
</style>
<div class="container">
<div
id="${() => `${verticalPosition}_${horizontalPosition}`}"
class="anchor"
>
Anchor element
</div>
<nimble-anchored-region
anchor="${() => `${verticalPosition}_${horizontalPosition}`}"
fixed-placement="true"
auto-update-mode="auto"
vertical-default-position="${() => verticalPosition}"
vertical-positioning-mode="locktodefault"
horizontal-default-position="${() => horizontalPosition}"
horizontal-positioning-mode="locktodefault"
>
<div class="anchoredRegion">
${horizontalPositionName} ${verticalPositionName}
</div>
</nimble-anchored-region>
<div></div>
</div>`;

export const anchoredRegionThemeMatrix: Story = createStory(
createMatrix(component, [horizontalPositionStates, verticalPositionStates])
);

export const hiddenAnchoredRegion: Story = createStory(
hiddenWrapper(
html`<nimble-anchored-region hidden>Hidden Anchored Region</nimble-anchored-regionx>`
)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
DesignSystem,
AnchoredRegion as FoundationAnchoredRegion
} from '@microsoft/fast-foundation';
import { AnchoredRegion } from '..';

describe('Anchored Region', () => {
it('should have its tag returned by tagFor(FoundationAnchoredRegion)', () => {
expect(DesignSystem.tagFor(FoundationAnchoredRegion)).toBe(
'nimble-anchored-region'
);
});

it('can construct an element instance', () => {
expect(document.createElement('nimble-anchored-region')).toBeInstanceOf(
AnchoredRegion
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import type { Meta, StoryObj } from '@storybook/html';
import { html } from '@microsoft/fast-element';
import { createUserSelectedThemeStory } from '../../utilities/tests/storybook';
import '../../all-components';
import {
applicationBackgroundColor,
bodyFont,
bodyFontColor,
borderHoverColor
} from '../../theme-provider/design-tokens';

interface AnchoredRegionArgs {
horizontalPosition: string;
verticalPosition: string;
}

const overviewText = `An anchored region is a container component which enables authors to create layouts where the contents of the anchored region can be
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
positioned relative to another "anchor" element. Additionally, the anchored region can react to the available space between the anchor and a parent
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
["viewport"](https://developer.mozilla.org/en-US/docs/Glossary/viewport) element such that the region is placed on the side of the anchor with the most
available space, or even resize itself based on that space.

When the anchor element changes position on the page, it is the client's responsibility to update the position of the anchored region by calling \`update()\`
on the anchored region.

When the anchor element is recreated on the page, it is the client's responsibility to reset the reference the anchored region has to the anchor element. This
can be done by either recreating the anchor element with a new ID that is also set as the \`anchor\` attribute on the anchored region or by explicitly setting the value of
\`anchorElement\` on the anchored region to the new anchor element.`;

const metadata: Meta<AnchoredRegionArgs> = {
title: 'Anchored Region',
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
parameters: {
docs: {
description: {
component: overviewText
}
}
},
// prettier-ignore
render: createUserSelectedThemeStory(html<AnchoredRegionArgs>`
<style>
.container {
height: 300px;
}

.anchor {
position: absolute;
top: 100px;
left: 300px;
width: 150px;
height: 150px;
font: var(${bodyFont.cssCustomProperty});
color: var(${bodyFontColor.cssCustomProperty});
border: 2px solid var(${borderHoverColor.cssCustomProperty});
background: var(${applicationBackgroundColor.cssCustomProperty});
}

.anchoredRegion {
width: 75px;
height: 75px;
font: var(${bodyFont.cssCustomProperty});
color: var(${bodyFontColor.cssCustomProperty});
border: 2px solid var(${borderHoverColor.cssCustomProperty});
background: var(${applicationBackgroundColor.cssCustomProperty});
}
</style>
<div class="container">
<div id="${x => `${x.verticalPosition}_${x.horizontalPosition}`}" class="anchor">
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
Anchor element
</div>
<nimble-anchored-region
anchor="${x => `${x.verticalPosition}_${x.horizontalPosition}`}"
fixed-placement="true"
auto-update-mode="auto"
vertical-default-position="${x => x.verticalPosition}"
vertical-positioning-mode="${x => (x.verticalPosition === 'unset' ? 'dynamic' : 'locktodefault')}"
horizontal-default-position="${x => x.horizontalPosition}"
horizontal-positioning-mode="${x => (x.horizontalPosition === 'unset' ? 'dynamic' : 'locktodefault')}"
>
<div class="anchoredRegion">
Anchored region
</div>
</nimble-anchored-region>
</div>
`),
argTypes: {
horizontalPosition: {
options: ['start', 'end', 'left', 'right', 'center', 'unset'],
control: { type: 'select' }
},
verticalPosition: {
options: ['top', 'bottom', 'center', 'unset'],
control: { type: 'select' }
}
},
args: {}
};

export default metadata;

export const anchoredRegion: StoryObj<AnchoredRegionArgs> = {
args: {
horizontalPosition: 'start',
mollykreis marked this conversation as resolved.
Show resolved Hide resolved
verticalPosition: 'top'
}
};