Skip to content

feature: add motion to accordion component #877

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

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
fedf384
feat(motion): add motion variables and animation
ckrook Nov 28, 2024
734bfa4
feat(motion): refactor motion animations into mixins for improved reu…
ckrook Nov 29, 2024
cd955d3
Update motion/index.scss
ckrook Nov 29, 2024
1a5d48e
Merge branch 'feature/motion-variables' of https://github.com/scania-…
ckrook Nov 29, 2024
b934924
feat(motion): add motion variables and animation
ckrook Nov 28, 2024
7b0d243
feat(motion): refactor motion animations into mixins for improved reu…
ckrook Nov 29, 2024
a7e2d68
Update motion/index.scss
ckrook Nov 29, 2024
e006f64
Merge branch 'feature/motion-variables' of https://github.com/scania-…
ckrook Nov 29, 2024
7c923c2
feat(motion): for motion animation to work we put it outside host, html
ckrook Nov 29, 2024
aa6532e
fix(motion): remove redundant animation import from index.scss
ckrook Nov 29, 2024
bb2ec6f
feat(motion): convert motion animations mixins to CSS variables for d…
ckrook Dec 2, 2024
719bdff
Merge branch 'develop' into feature/motion-variables
ckrook Dec 2, 2024
dd8a4d4
feat(accordion): add animation prop and styles to accordion items
ckrook Dec 9, 2024
ef80c50
Merge branch 'develop' into feature/accordion-motion
ckrook Dec 9, 2024
791dfa6
feat(accordion-item): enhance transitions for background color and ic…
ckrook Dec 9, 2024
d5d6100
Merge branch 'develop' into feature/accordion-motion
ckrook Dec 12, 2024
698589f
feat: add slide expand and close animations for accordion component
ckrook Dec 17, 2024
a0ed1b6
feat: enhance accordion item with slide animations and initial load h…
ckrook Dec 17, 2024
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
26 changes: 26 additions & 0 deletions motion/_animation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,32 @@
}
}

@keyframes tds-slide-expand {
0% {
max-height: 0;
padding: 0 var(--tds-spacing-layout-64) 0 var(--tds-spacing-element-16);
}

100% {
max-height: 500px;
padding: var(--tds-spacing-element-8) var(--tds-spacing-layout-64) 31px
var(--tds-spacing-element-16);
}
}

@keyframes tds-slide-expand-hidden {
0% {
max-height: 500px;
padding: var(--tds-spacing-element-8) var(--tds-spacing-layout-64) 31px
var(--tds-spacing-element-16);
}

100% {
max-height: 0;
padding: 0 var(--tds-spacing-layout-64) 0 var(--tds-spacing-element-16);
}
}

.star1 {
animation: animate-svg-stroke-1 2s cubic-bezier(0.47, 0, 0.745, 0.715) 0s both;
fill: #fff;
Expand Down
6 changes: 6 additions & 0 deletions motion/_motion.scss
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,10 @@ html {
tds-slide-out-bottom-hidden var(--tds-motion-duration-slow-02) var(--tds-motion-easing-exit)
forwards,
tds-zoom-out var(--tds-motion-duration-slow-02) var(--tds-motion-easing-exit) forwards;

/* ### Accordion ### */
--accordian-slide-expand: tds-slide-expand var(--tds-motion-duration-moderate-01)
var(--tds-motion-easing-enter) forwards;
--accordian-slide-close: tds-slide-close var(--tds-motion-duration-fast-01)
var(--tds-motion-easing-exit) forwards;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
color: var(--tds-accordion-color);
position: relative;

&:focus {
border-top: 1px solid var(--tds-accordion-border-focus);
}

&[disabled='true']:focus {
border-color: var(--tds-accordion-border);
}

button.tds-accordion-header-icon-start,
button.tds-accordion-header-icon-end {
all: unset;
Expand All @@ -24,16 +32,15 @@
display: flex;
align-items: center;
width: 100%;

// fixme: wrong line-height compared to production
font: var(--tds-headline-07);
letter-spacing: var(--tds-headline-07-ls);
padding: var(--tds-spacing-element-16);
background-color: var(--tds-accordion-background);
transition: background-color var(--tds-motion-duration-fast-02) var(--tds-motion-easing-scania);

.tds-accordion-icon {
transform-origin: center;
transition: transform 0.15s ease-in-out;
transition: transform var(--tds-motion-duration-fast-02) var(--tds-motion-easing-scania);
color: var(--tds-accordion-icon-color);

& > tds-icon {
Expand All @@ -46,11 +53,48 @@
flex-grow: 2;
}

&.tds-accordion-item-animation-open-slide .tds-accordion-panel {
animation: tds-slide-expand var(--tds-motion-duration-moderate-01)
var(--tds-motion-easing-enter) forwards;
}

&.tds-accordion-item-animation-close-slide .tds-accordion-panel {
animation: tds-slide-close var(--tds-motion-duration-moderate-01) var(--tds-motion-easing-exit)
forwards;
}

// Becase the component has shadow 'true' we need to define the animation here
@keyframes tds-slide-expand {
0% {
max-height: 0;
padding: 0 var(--tds-spacing-layout-64) 0 var(--tds-spacing-element-16);
}

100% {
max-height: 500px;
padding: var(--tds-spacing-element-8) var(--tds-spacing-layout-64) 31px
var(--tds-spacing-element-16);
}
}

@keyframes tds-slide-close {
0% {
max-height: 500px;
padding: var(--tds-spacing-element-8) var(--tds-spacing-layout-64) 31px
var(--tds-spacing-element-16);
}

100% {
max-height: 0;
padding: 0 var(--tds-spacing-layout-64) 0 var(--tds-spacing-element-16);
}
}

.tds-accordion-panel {
cursor: default;
padding: var(--tds-spacing-element-8) var(--tds-spacing-layout-64) var(--tds-spacing-element-32)
var(--tds-spacing-element-16);
display: none;
overflow: hidden;
max-height: 0;
padding: 0 var(--tds-spacing-layout-64) 0 var(--tds-spacing-element-16);
font: var(--tds-detail-03);
letter-spacing: var(--tds-detail-03-ls);

Expand Down Expand Up @@ -104,8 +148,11 @@

&.expanded {
.tds-accordion-panel {
display: block;
padding-bottom: 31px;
max-height: 500px;

/* Set this to a value larger than the content height */
padding: var(--tds-spacing-element-8) var(--tds-spacing-layout-64) 31px
var(--tds-spacing-element-16);
}

.tds-accordion-icon {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Event, EventEmitter, h, Host, Method, Prop } from '@stencil/core';
import { Component, Event, EventEmitter, h, Host, Method, Prop, State } from '@stencil/core';

/**
* @slot <default> - <b>Unnamed slot.</b> For content of an expanded accordion.
Expand Down Expand Up @@ -26,6 +26,18 @@ export class TdsAccordionItem {
/** When true, 16px on right padding instead of 64px */
@Prop() paddingReset: boolean = false;

/**
* Animation variant for the accordion item.
* Inherits from tds-accordion if not set explicitly.
*/
@Prop() animation: 'none' | 'slide' = 'slide';

/**
* Private boolean to track if this is the initial load.
* If true, we skip triggering the animation classes on first render.
*/
@State() private initialLoad = true;

/** Method for toggling the expanded state of the Accordion Item. */
@Method()
async toggleAccordionItem() {
Expand All @@ -50,13 +62,27 @@ export class TdsAccordionItem {
}>;

render() {
// If initialLoad is true, we do NOT attach the animation classes
// so it won't animate on the very first render.
const shouldAnimate = this.animation !== 'none' && !this.initialLoad;

// Build up dynamic classes
const classes = {
'tds-accordion-item': true,
'disabled': this.disabled,
'expanded': this.expanded,
[`tds-accordion-item-animation-open-${this.animation}`]: shouldAnimate && this.expanded,
[`tds-accordion-item-animation-close-${this.animation}`]: shouldAnimate && !this.expanded,
};

this.initialLoad = false;

return (
<Host>
<div
class={`tds-accordion-item
${this.disabled ? 'disabled' : ''}
${this.expanded ? 'expanded' : ''}
`}
class={Object.keys(classes)
.filter((c) => classes[c])
.join(' ')}
>
<button
type="button"
Expand All @@ -74,9 +100,9 @@ export class TdsAccordionItem {
</div>
</button>
<div
class={`tds-accordion-panel
${this.paddingReset ? 'tds-accordion-panel--padding-reset ' : ''}
`}
class={`tds-accordion-panel ${
this.paddingReset ? 'tds-accordion-panel--padding-reset' : ''
}`}
>
<slot></slot>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@

## Properties

| Property | Attribute | Description | Type | Default |
| -------------------- | ---------------------- | ---------------------------------------------------------------------------------------------- | ------------------ | ------- |
| `disabled` | `disabled` | Disabled option in `boolean`. | `boolean` | `false` |
| `expandIconPosition` | `expand-icon-position` | Changes position of the expand icon. | `"end" \| "start"` | `'end'` |
| `expanded` | `expanded` | Set to true to expand panel open | `boolean` | `false` |
| `header` | `header` | The header gives users the context about the additional information available inside the panel | `string` | `''` |
| `paddingReset` | `padding-reset` | When true, 16px on right padding instead of 64px | `boolean` | `false` |
| Property | Attribute | Description | Type | Default |
| -------------------- | ---------------------- | ---------------------------------------------------------------------------------------------- | ------------------- | --------- |
| `animation` | `animation` | Animation variant for the accordion item. Inherits from tds-accordion if not set explicitly. | `"none" \| "slide"` | `'slide'` |
| `disabled` | `disabled` | Disabled option in `boolean`. | `boolean` | `false` |
| `expandIconPosition` | `expand-icon-position` | Changes position of the expand icon. | `"end" \| "start"` | `'end'` |
| `expanded` | `expanded` | Set to true to expand panel open | `boolean` | `false` |
| `header` | `header` | The header gives users the context about the additional information available inside the panel | `string` | `''` |
| `paddingReset` | `padding-reset` | When true, 16px on right padding instead of 64px | `boolean` | `false` |


## Events
Expand Down
23 changes: 21 additions & 2 deletions packages/core/src/components/accordion/accordion.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ export default {
defaultValue: { summary: false },
},
},
animation: {
name: 'Animation',
description: 'Sets the animation type for the Accordion.',
control: {
type: 'radio',
},
options: { None: 'none', Slide: 'slide' },
table: {
defaultValue: { summary: 'slide' },
},
},
},
parameters: {
notes: { 'Accordion': readme, 'Accordion Item': readmeItem },
Expand All @@ -81,10 +92,18 @@ export default {
paddingReset: false,
disabled: false,
hideLastBorder: false,
animation: 'none',
},
};

const Template = ({ disabled, iconPosition, paddingReset, modeVariant, hideLastBorder }) => {
const Template = ({
disabled,
iconPosition,
paddingReset,
modeVariant,
hideLastBorder,
animation,
}) => {
const affixAttr = iconPosition === 'start' ? 'expand-icon-position="start"' : '';
const disabledAttr = disabled ? 'disabled' : '';
const paddingResetAttr = paddingReset ? 'padding-reset' : '';
Expand All @@ -93,7 +112,7 @@ const Template = ({ disabled, iconPosition, paddingReset, modeVariant, hideLastB
return formatHtmlPreview(`
<tds-accordion ${
modeVariant !== 'Inherit from parent' ? `mode-variant="${modeVariant.toLowerCase()}"` : ''
} ${hideLastBorderAttr}>
} ${hideLastBorderAttr} animation="${animation}">
<tds-accordion-item header="First item" ${affixAttr} ${disabledAttr} ${paddingResetAttr}>
This is the panel, which contains associated information with the header. Usually it contains text, set in the same size as the header.
Lorem ipsum doler sit amet.
Expand Down
15 changes: 14 additions & 1 deletion packages/core/src/components/accordion/accordion.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, h, Host, Prop } from '@stencil/core';
import { Component, h, Host, Prop, Element } from '@stencil/core';

/**
* @slot <default> - <b>Unnamed slot.</b> For accordion items.
Expand All @@ -9,12 +9,25 @@ import { Component, h, Host, Prop } from '@stencil/core';
shadow: true,
})
export class TdsAccordion {
@Element() host: HTMLElement;

/** Set the variant of the Accordion. */
@Prop() modeVariant: 'primary' | 'secondary' = null;

/** Removes the bottom border of the last Accordion item. */
@Prop() hideLastBorder: boolean = false;

@Prop() animation: 'none' | 'slide' = 'slide';

componentDidLoad() {
// After the component has rendered, find all child <tds-accordion-item> elements
const items = this.host.querySelectorAll('tds-accordion-item');
items.forEach((item: HTMLElement & { animation?: string }) => {
// Set the animation prop on each Accordion Item
item.animation = this.animation;
});
}

render() {
return (
<Host
Expand Down
9 changes: 5 additions & 4 deletions packages/core/src/components/accordion/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

## Properties

| Property | Attribute | Description | Type | Default |
| ---------------- | ------------------ | ----------------------------------------------------- | -------------------------- | ------- |
| `hideLastBorder` | `hide-last-border` | Removes the bottom border of the last Accordion item. | `boolean` | `false` |
| `modeVariant` | `mode-variant` | Set the variant of the Accordion. | `"primary" \| "secondary"` | `null` |
| Property | Attribute | Description | Type | Default |
| ---------------- | ------------------ | ----------------------------------------------------- | -------------------------- | --------- |
| `animation` | `animation` | | `"none" \| "slide"` | `'slide'` |
| `hideLastBorder` | `hide-last-border` | Removes the bottom border of the last Accordion item. | `boolean` | `false` |
| `modeVariant` | `mode-variant` | Set the variant of the Accordion. | `"primary" \| "secondary"` | `null` |


## Slots
Expand Down
Loading