diff --git a/packages/accordion/_mixins.scss b/packages/accordion/_mixins.scss index 79709dec8..0fe4cb11f 100644 --- a/packages/accordion/_mixins.scss +++ b/packages/accordion/_mixins.scss @@ -1,3 +1,5 @@ +@use 'sass:math'; +@use '@material/animation/index' as animation; @use '@material/elevation/index' as elevation; @use '@material/theme/index' as theme; @use '@material/feature-targeting/index' as feature-targeting; @@ -7,7 +9,9 @@ $ripple-target: '.smui-accordion__header__ripple'; $panel-padding: 16px 24px !default; $open-margin: 1rem; +$extend-width: 10px; $transition-duration: 0.2s; +$content-transition-duration: 0.3s; $divider-color-on-light-bg: rgba(0, 0, 0, 0.12) !default; $divider-color-on-dark-bg: rgba(255, 255, 255, 0.2) !default; @@ -34,8 +38,25 @@ $divider-color-on-dark-bg: rgba(255, 255, 255, 0.2) !default; padding: 0; margin-top: 0; margin-bottom: 0; - transition: margin-top $transition-duration ease, - margin-bottom $transition-duration ease; + transition: animation.standard(margin-top, $transition-duration), + animation.standard(margin-bottom, $transition-duration); + + &.smui-accordion__panel--extend { + // Adding width, left, and box-shadow to animate the scaling and + // elevation change as well. + transition: animation.standard(width, $transition-duration), + animation.standard(left, $transition-duration), + animation.standard(box-shadow, $transition-duration), + animation.standard(margin-top, $transition-duration), + animation.standard(margin-bottom, $transition-duration); + width: 100%; + left: 0; + + &.smui-accordion__panel--open { + width: calc(100% + $extend-width); + left: math.div($extend-width, 2) * -1; + } + } &.smui-accordion__panel--raised, &.smui-paper--unelevated { @@ -127,17 +148,26 @@ $divider-color-on-dark-bg: rgba(255, 255, 255, 0.2) !default; .smui-accordion__header__title { padding: $panel-padding; flex-grow: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; &.smui-accordion__header__title--with-description { - width: 30%; + flex-basis: 30%; max-width: 280px; + box-sizing: border-box; + padding-inline-end: 0; } } .smui-accordion__header__description { opacity: 0.48; padding: $panel-padding; + flex-basis: 0; flex-grow: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .smui-accordion__header__icon { @@ -146,6 +176,7 @@ $divider-color-on-dark-bg: rgba(255, 255, 255, 0.2) !default; margin: $panel-padding; margin-top: 0; margin-bottom: 0; + margin-inline-start: 0; } #{$ripple-target} { @@ -174,17 +205,23 @@ $divider-color-on-dark-bg: rgba(255, 255, 255, 0.2) !default; } & > .smui-paper__content { - padding: $panel-padding; overflow: hidden; - transition: height $transition-duration ease, - padding $transition-duration ease; - box-sizing: content-box; + transition: animation.standard(height, $content-transition-duration), + animation.standard(padding, $content-transition-duration); + box-sizing: border-box; height: 0; - } - - &:not(.smui-accordion__panel--open) > .smui-paper__content { + padding: $panel-padding; padding-top: 0; padding-bottom: 0; + + &.smui-accordion__content--no-transition { + transition: none; + } + + &.smui-accordion__content--force-open { + height: auto; + padding: $panel-padding; + } } &.smui-accordion__panel--open { @@ -193,6 +230,7 @@ $divider-color-on-dark-bg: rgba(255, 255, 255, 0.2) !default; & > .smui-paper__content { height: auto; + padding: $panel-padding; } } } diff --git a/packages/accordion/package.json b/packages/accordion/package.json index f9587bbde..496646d3f 100644 --- a/packages/accordion/package.json +++ b/packages/accordion/package.json @@ -36,6 +36,7 @@ }, "license": "Apache-2.0", "dependencies": { + "@material/animation": "^13.0.0", "@material/elevation": "^13.0.0", "@material/feature-targeting": "^13.0.0", "@material/ripple": "^13.0.0", diff --git a/packages/accordion/src/Panel.svelte b/packages/accordion/src/Panel.svelte index a30133eb8..6fd9d1b8b 100644 --- a/packages/accordion/src/Panel.svelte +++ b/packages/accordion/src/Panel.svelte @@ -7,8 +7,11 @@ 'smui-accordion__panel--open': open, 'smui-accordion__panel--disabled': disabled, 'smui-accordion__panel--raised': variant === 'raised', - ['smui-accordion__panel--elevation-z' + elevation]: - elevation !== 0 && variant === 'raised', + 'smui-accordion__panel--extend': extend, + ['smui-accordion__panel--elevation-z' + + (extend && open ? extendedElevation : elevation)]: + (elevation !== 0 && variant === 'raised') || + (extendedElevation !== 0 && variant === 'raised' && extend && open), })} {color} variant={variant === 'raised' ? 'unelevated' : variant} @@ -42,6 +45,8 @@ export let elevation = 1; export let open = false; export let disabled = false; + export let extend = false; + export let extendedElevation = 3; let element: PaperComponentDev; let accessor: SMUIAccordionPanelAccessor; @@ -64,12 +69,14 @@ // Calculate the height of the content and apply it. This lets the CSS // animation run properly. if (open) { - content.style.height = 'auto'; + content.classList.add('smui-accordion__content--no-transition'); + content.classList.add('smui-accordion__content--force-open'); // Force a reflow to get the height. const { height } = content.getBoundingClientRect(); - content.style.height = ''; + content.classList.remove('smui-accordion__content--force-open'); // Force another reflow to reset the height. content.getBoundingClientRect(); + content.classList.remove('smui-accordion__content--no-transition'); content.style.height = height + 'px'; content.addEventListener( 'transitionend', @@ -81,7 +88,9 @@ { once: true } ); } else { - content.style.height = content.clientHeight + 'px'; + content.style.height = content.getBoundingClientRect().height + 'px'; + // Force a reflow. + content.getBoundingClientRect(); requestAnimationFrame(() => { if (content) { content.style.height = ''; diff --git a/packages/site/src/routes/demo/accordion/_Extend.svelte b/packages/site/src/routes/demo/accordion/_Extend.svelte new file mode 100644 index 000000000..4dac3d92c --- /dev/null +++ b/packages/site/src/routes/demo/accordion/_Extend.svelte @@ -0,0 +1,57 @@ +
+ + +
+ Panel 1 + Description of panel 1. +
+ + The content for panel 1. + +
    +
  • Some
  • +
  • List
  • +
  • Items
  • +
+
+
+ +
+ Panel 2 + Description of panel 2. +
+ The content for panel 2. +
+ +
+ Panel 3 + Description of panel 3. +
+ + The content for panel 3. + +
    +
  • Some
  • +
  • More
  • +
  • List
  • +
  • Items
  • +
  • To
  • +
  • Show
  • +
  • Big
  • +
  • Height
  • +
+
+
+ +
+ Panel 4 + Description of panel 4. +
+ The content for panel 4. +
+
+
+ + diff --git a/packages/site/src/routes/demo/accordion/_PaperProps.svelte b/packages/site/src/routes/demo/accordion/_PaperProps.svelte index 8e42dcb87..5379fa96f 100644 --- a/packages/site/src/routes/demo/accordion/_PaperProps.svelte +++ b/packages/site/src/routes/demo/accordion/_PaperProps.svelte @@ -1,45 +1,69 @@
- - + +
Panel 1 Description of panel 1. - expand_less - expand_more + unfold_less + unfold_more
The content for panel 1.
- +
Panel 2 Description of panel 2. - expand_less - expand_more + unfold_less + unfold_more
The content for panel 2.
- +
Panel 3 Description of panel 3. - expand_less - expand_more + unfold_less + unfold_more
The content for panel 3.
- +
Panel 4 Description of panel 4. - expand_less - expand_more + unfold_less + unfold_more
The content for panel 4. @@ -56,3 +80,12 @@ let panel3Open = false; let panel4Open = false; + + diff --git a/packages/site/src/routes/demo/accordion/index.svelte b/packages/site/src/routes/demo/accordion/index.svelte index dcea15ba1..26e98b86e 100644 --- a/packages/site/src/routes/demo/accordion/index.svelte +++ b/packages/site/src/routes/demo/accordion/index.svelte @@ -21,11 +21,15 @@ - Adding descriptions + Descriptions Toggle icons + + Extending panels + + Primary color @@ -48,6 +52,7 @@ import Simple from './_Simple.svelte'; import Multiple from './_Multiple.svelte'; + import Extend from './_Extend.svelte'; import Description from './_Description.svelte'; import Icon from './_Icon.svelte'; import PrimaryColor from './_PrimaryColor.svelte'; @@ -62,8 +67,7 @@ } * :global(.smui-accordion) { - margin: 0 auto 24px; - max-width: 800px; + margin: 0 12px 24px; } * :global(.smui-accordion:last-child) {