Skip to content

Commit

Permalink
web component accordion (#26547)
Browse files Browse the repository at this point in the history
* accordion and accordion item init

* yarn change

* updates docs

* updates accordion item styles

* code formatting

* updates imports

* adds v9 appearance sizes

* updates attribute name to align with fluent v9

* adds alternative stories for accordion with custom icons

* adds docs

* updates storybook

* updates changelog

* removes dead code

* removes dynamic icons from sb

* removes dead code

* adds accordion README

* moves accordion readme to accordion directory

* updates docs

* updates accordion docs

* updates docs

* updates docs

* fixes docs

* fixes exports

* adds display helper to styles

* optimizes styles

* updates html helper to use html.partial

* optimizes styles

* exports directly on class

* removes html helper

* removes arg tables from stories

* sorts exports alphabetically

* api report

* flattens accordion componnent folders

* removes comment

* updates styles

* optimizes styles

* updates attributes

* removes renaming of definition import

* removes attribute syntax

* adds attr

* reverts api-report

* removes dead code

* updates styles

* consolidates stories into one

* updates docs

* adds display helper to accordion styles
  • Loading branch information
brianchristopherbrady authored and radium-v committed Apr 30, 2024
1 parent 7b4099f commit 4ea54ce
Show file tree
Hide file tree
Showing 18 changed files with 818 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat(accordion): Add accordion web component",
"packageName": "@fluentui/web-components",
"email": "brianbrady@microsoft.com",
"dependentChangeType": "patch"
}
8 changes: 8 additions & 0 deletions packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@
"types": "./dist/dts/index.d.ts",
"default": "./dist/esm/index.js"
},
"./accordion": {
"types": "./dist/esm/accordion/define.d.ts",
"default": "./dist/esm/accordion/define.js"
},
"./accordion-item": {
"types": "./dist/esm/accordion-item/define.d.ts",
"default": "./dist/esm/accordion-item/define.js"
},
"./badge": {
"types": "./dist/esm/badge/define.d.ts",
"default": "./dist/esm/badge/define.js"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FluentDesignSystem } from '../fluent-design-system.js';
import { AccordionItem } from './accordion-item.js';
import { styles } from './accordion-item.styles.js';
import { template } from './accordion-item.template.js';

/**
* The Fluent AccordionItem Element. Implements {@link @microsoft/fast-foundation#AccordionItem },
* {@link @microsoft/fast-foundation#accordionItemTemplate}
*
*
* @public
* @remarks
* HTML Element: \<fluent-accordion-item\>
*/
export const definition = AccordionItem.compose({
name: `${FluentDesignSystem.prefix}-accordion-item`,
template,
styles,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ValuesOf } from '@microsoft/fast-foundation';

/**
* An Accordion Item header font size can be small, medium, large, and extra-large
*/
export const AccordionItemSize = {
small: 'small',
medium: 'medium',
large: 'large',
extraLarge: 'extra-large',
} as const;

/**
* Applies font size to accordion header
* @public
*/
export type AccordionItemSize = ValuesOf<typeof AccordionItemSize>;

/**
* An Accordion Item expand/collapse icon can appear at the start or end of the accordion
*/
export const AccordionItemExpandIconPosition = {
start: 'start',
end: 'end',
} as const;

/**
* Applies expand/collapse icon position
* @public
*/
export type AccordionItemExpandIconPosition = ValuesOf<typeof AccordionItemExpandIconPosition>;
218 changes: 218 additions & 0 deletions packages/web-components/src/accordion-item/accordion-item.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import { css } from '@microsoft/fast-element';
import { display } from '@microsoft/fast-foundation';
import {
borderRadiusMedium,
borderRadiusSmall,
colorNeutralForeground1,
colorNeutralForegroundDisabled,
colorStrokeFocus1,
colorStrokeFocus2,
colorTransparentBackground,
fontFamilyBase,
fontSizeBase200,
fontSizeBase300,
fontSizeBase400,
fontSizeBase500,
fontWeightRegular,
lineHeightBase200,
lineHeightBase300,
lineHeightBase400,
lineHeightBase500,
spacingHorizontalM,
spacingHorizontalMNudge,
spacingHorizontalS,
} from '../theme/design-tokens.js';

export const styles = css`
${display('block')}
:host {
max-width: fit-content;
}
.heading {
height: 44px;
display: grid;
position: relative;
vertical-align: middle;
padding-inline: ${spacingHorizontalM} ${spacingHorizontalMNudge};
border-radius: ${borderRadiusMedium};
font-family: ${fontFamilyBase};
font-size: ${fontSizeBase300};
font-weight: ${fontWeightRegular};
line-height: ${lineHeightBase300};
grid-template-columns: auto auto 1fr auto;
}
.heading-content {
height: 100%;
display: flex;
align-items: center;
}
.button {
box-sizing: border-box;
appearance: none;
border: none;
outline: none;
text-align: start;
cursor: pointer;
font-family: inherit;
height: 44px;
color: ${colorNeutralForeground1};
background: ${colorTransparentBackground};
line-height: ${lineHeightBase300};
height: auto;
padding: 0;
font-size: inherit;
grid-column: auto / span 2;
grid-row: 1;
}
.button::before {
content: '';
position: absolute;
inset: 0px;
cursor: pointer;
border-radius: ${borderRadiusSmall};
}
.icon {
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
position: relative;
height: 100%;
padding-right: ${spacingHorizontalS};
grid-column: 1 / span 1;
grid-row: 1;
}
.region {
margin: 0 ${spacingHorizontalM};
}
::slotted([slot='start']),
::slotted([slot='end']) {
justify-content: center;
align-items: center;
padding-right: ${spacingHorizontalS};
grid-column: 2 / span 1;
grid-row: 1 / span 1;
}
button:focus-visible::after {
content: '';
position: absolute;
inset: 0px;
cursor: pointer;
border-radius: ${borderRadiusSmall};
outline: none;
border: 2px solid ${colorStrokeFocus1};
box-shadow: inset 0 0 0 1px ${colorStrokeFocus2};
}
/* --- Disabled attr styles --- */
:host([disabled]) .button {
color: ${colorNeutralForegroundDisabled};
}
:host([disabled]) svg {
filter: invert(89%) sepia(0%) saturate(569%) hue-rotate(155deg) brightness(88%) contrast(87%);
}
/* --- Expanded attr styles --- */
:host([expanded]) .region {
display: block;
}
:host([expanded]) .default-collapsed-icon,
:host([expanded]) ::slotted([slot='collapsed-icon']),
:host(:not([expanded])) .default-expanded-icon,
:host(:not([expanded])) ::slotted([slot='expanded-icon']),
:host([expanded]) ::slotted([slot='end']),
::slotted([slot='start']),
.region {
display: none;
}
:host([expanded]) ::slotted([slot='start']),
:host([expanded]) ::slotted([slot='expanded-icon']),
:host(:not([expanded])) ::slotted([slot='collapsed-icon']),
::slotted([slot='end']) {
display: flex;
}
/* --- Appearance attr styles --- */
.heading {
font-size: ${fontSizeBase300};
line-height: ${lineHeightBase300};
}
:host([size='small']) .heading {
font-size: ${fontSizeBase200};
line-height: ${lineHeightBase200};
}
:host([size='large']) .heading {
font-size: ${fontSizeBase400};
line-height: ${lineHeightBase400};
}
:host([size='extra-large']) .heading {
font-size: ${fontSizeBase500};
line-height: ${lineHeightBase500};
}
/* --- expand-icon-position attr styles --- */
:host([expand-icon-position='end']) :slotted(span[slot='start']),
:host([expand-icon-position='end']) ::slotted(span[slot='end']) {
grid-column: 1 / span 1;
grid-row: 1;
}
:host([expand-icon-position='end']) ::slotted(span[slot='start']),
:host([expand-icon-position='end']) ::slotted(span[slot='end']) {
grid-column: 1 / span 1;
grid-row: 1;
}
:host([expand-icon-position='end']) .icon {
grid-column: 4 / span 1;
grid-row: 1;
display: flex;
padding-left: 10px;
padding-right: 0;
}
:host([expand-icon-position='end']) .button {
grid-column: 2 / span 3;
grid-row: 1;
}
/* --- Block attr styles --- */
:host([block]) {
max-width: 100%;
}
:host([expand-icon-position='end']) .heading {
grid-template-columns: auto auto 28px;
}
:host([expand-icon-position='end']) .icon {
grid-column: 5 / span 1;
}
:host([block][expand-icon-position='end']) .heading {
grid-template-columns: auto 1fr;
}
:host([block][expand-icon-position='end']) .icon {
grid-column: 5 / span 1;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ElementViewTemplate, html } from '@microsoft/fast-element';
import { accordionItemTemplate } from '@microsoft/fast-foundation';
import { AccordionItem } from './accordion-item.js';

const chevronRight20Filled = html.partial(`<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="default-collapsed-icon"
>
<path
d="M7.73271 4.20694C8.03263 3.92125 8.50737 3.93279 8.79306 4.23271L13.7944 9.48318C14.0703 9.77285 14.0703 10.2281 13.7944 10.5178L8.79306 15.7682C8.50737 16.0681 8.03263 16.0797 7.73271 15.794C7.43279 15.5083 7.42125 15.0336 7.70694 14.7336L12.2155 10.0005L7.70694 5.26729C7.42125 4.96737 7.43279 4.49264 7.73271 4.20694Z"
fill="#212121"
/>
</svg>`);

const chevronDown20Filled = html.partial(`<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="default-expanded-icon"
>
<path
d="M15.794 7.73271C16.0797 8.03263 16.0681 8.50737 15.7682 8.79306L10.5178 13.7944C10.2281 14.0703 9.77285 14.0703 9.48318 13.7944L4.23271 8.79306C3.93279 8.50737 3.92125 8.03263 4.20694 7.73271C4.49264 7.43279 4.96737 7.42125 5.26729 7.70694L10.0005 12.2155L14.7336 7.70694C15.0336 7.42125 15.5083 7.43279 15.794 7.73271Z"
fill="#212121"
/>
</svg>`);

/**
* The template for the fluent-accordion component.
* @public
*/
export const template: ElementViewTemplate<AccordionItem> = accordionItemTemplate({
collapsedIcon: chevronRight20Filled,
expandedIcon: chevronDown20Filled,
});
40 changes: 40 additions & 0 deletions packages/web-components/src/accordion-item/accordion-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { attr } from '@microsoft/fast-element';
import { FASTAccordionItem } from '@microsoft/fast-foundation';
import { AccordionItemExpandIconPosition, AccordionItemSize } from './accordion-item.options.js';

/**
* @internal
*/
export class AccordionItem extends FASTAccordionItem {
/**
* Defines accordion header font size.
*
* @public
* @default 'medium'
* @remarks
* HTML Attribute: size
*/
@attr
public size: AccordionItemSize;

/**
* Sets the width of the focus state.
*
* @public
* @remarks
* HTML Attribute: block
*/
@attr({ mode: 'boolean' })
public block: boolean = false;

/**
* Sets expand and collapsed icon position.
*
* @public
* @default 'start'
* @remarks
* HTML Attribute: expandIconPosition
*/
@attr({ attribute: 'expand-icon-position' })
public expandIconPosition: AccordionItemExpandIconPosition;
}
4 changes: 4 additions & 0 deletions packages/web-components/src/accordion-item/define.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { FluentDesignSystem } from '../fluent-design-system.js';
import { definition } from './accordion-item.definition.js';

definition.define(FluentDesignSystem.registry);
5 changes: 5 additions & 0 deletions packages/web-components/src/accordion-item/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './accordion-item.js';
export * from './accordion-item.options.js';
export { styles as accordionItemStyles } from './accordion-item.styles.js';
export { definition as accordionItemDefinition } from './accordion-item.definition.js';
export { template as accordionItemTemplate } from './accordion-item.template.js';
Loading

0 comments on commit 4ea54ce

Please sign in to comment.