From 5e7eee11c6e463aba8cc377a02874333ae738529 Mon Sep 17 00:00:00 2001 From: Said MARAR Date: Sat, 24 Dec 2022 21:03:09 +0100 Subject: [PATCH 01/10] feat: enable horizontal mode --- README.md | 4 +++ src/index.ts | 71 +++++++++++++++++++++++++++++++--------------------- src/types.ts | 2 ++ src/utils.ts | 21 +++++++++++++--- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 886185c..b58d349 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,11 @@ const { getCollapseProps, getToggleProps, isExpanded, setExpanded } = useCollapse({ isExpanded: boolean, defaultExpanded: boolean, + isHorizontal: boolean, expandStyles: {}, collapseStyles: {}, collapsedHeight: 0, + collapsedWidth: 0, easing: string, duration: number, onCollapseStart: func, @@ -103,9 +105,11 @@ The following are optional properties passed into `useCollapse({ })`: | -------------------- | -------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | isExpanded | boolean | `undefined` | If true, the Collapse is expanded | | defaultExpanded | boolean | `false` | If true, the Collapse will be expanded when mounted | +| isHorizontal | boolean | `false` | If true, the component will collapse/expand will horizontally | | expandStyles | object | `{}` | Style object applied to the collapse panel when it expands | | collapseStyles | object | `{}` | Style object applied to the collapse panel when it collapses | | collapsedHeight | number | `0` | The height of the content when collapsed | +| collapsedWidth | number | `0` | The width of the content when collapsed | | easing | string | `cubic-bezier(0.4, 0, 0.2, 1)` | The transition timing function for the animation | | duration | number | `undefined` | The duration of the animation in milliseconds. By default, the duration is programmatically calculated based on the height of the collapsed element | | onCollapseStart | function | no-op | Handler called when the collapse animation begins | diff --git a/src/index.ts b/src/index.ts index dcb6584..36af8c3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,8 @@ import { noop, callAll, getElementHeight, - getAutoHeightDuration, + getElementWidth, + getAutoDistanceDuration, mergeRefs, usePaddingWarning, useUniqueId, @@ -34,6 +35,7 @@ export default function useCollapse({ isExpanded: configIsExpanded, defaultExpanded = false, hasDisabledAnimation = false, + isHorizontal = false, ...initialConfig }: UseCollapseInput = {}): UseCollapseOutput { const [isExpanded, setExpanded] = useControlledState( @@ -43,10 +45,11 @@ export default function useCollapse({ const uniqueId = useUniqueId() const el = useRef(null) usePaddingWarning(el) - const collapsedHeight = `${initialConfig.collapsedHeight || 0}px` + const dimension = isHorizontal ? 'width' : 'height' + const collapsedDimension = `${(isHorizontal ? initialConfig.collapsedWidth : initialConfig.collapsedHeight) || 0}px` const collapsedStyles = { - display: collapsedHeight === '0px' ? 'none' : 'block', - height: collapsedHeight, + display: collapsedDimension === '0px' ? 'none' : 'block', + [dimension]: collapsedDimension, overflow: 'hidden', } const [styles, setStylesRaw] = useState( @@ -64,87 +67,99 @@ export default function useCollapse({ setStyles((oldStyles) => ({ ...oldStyles, ...newStyles })) } - function getTransitionStyles(height: number | string): CSSProperties { + function getTransitionStyles(distance: number | string): CSSProperties { if (hasDisabledAnimation) { return {} } - const _duration = duration || getAutoHeightDuration(height) + const _duration = duration || getAutoDistanceDuration(distance) return { - transition: `height ${_duration}ms ${easing}`, + transition: `${dimension} ${_duration}ms ${easing}`, } } + const [initHeight, setIniHeight] = useState(0) + const [initWidth, setInitWidth] = useState(0) + useEffectAfterMount(() => { + if (isHorizontal && initHeight === 0) { + setIniHeight(getElementHeight(el)) + setInitWidth(getElementWidth(el)) + return + } if (isExpanded) { requestAnimationFrame(() => { onExpandStart() mergeStyles({ ...expandStyles, - willChange: 'height', + willChange: dimension, display: 'block', overflow: 'hidden', }) requestAnimationFrame(() => { - const height = getElementHeight(el) + const dimensionValue = isHorizontal ? initWidth : getElementHeight(el) + const transitionStyles = getTransitionStyles(dimensionValue) mergeStyles({ - ...getTransitionStyles(height), - height, + ...transitionStyles, + [dimension]: dimensionValue, }) }) }) } else { requestAnimationFrame(() => { onCollapseStart() - const height = getElementHeight(el) + const dimensionValue = isHorizontal ? getElementWidth(el) : getElementHeight(el) + const transitionStyles = getTransitionStyles(dimensionValue) mergeStyles({ ...collapseStyles, - ...getTransitionStyles(height), - willChange: 'height', - height, + ...transitionStyles, + willChange: dimension, + [dimension]: dimensionValue, }) requestAnimationFrame(() => { mergeStyles({ - height: collapsedHeight, + [dimension]: collapsedDimension, overflow: 'hidden', + // when collapsing width we make sure to preserve the initial height + ...(isHorizontal ? {height: initHeight} : {}), }) }) }) } - }, [isExpanded, collapsedHeight]) + }, [isExpanded, collapsedDimension, initHeight]) const handleTransitionEnd = (e: TransitionEvent): void => { // Sometimes onTransitionEnd is triggered by another transition, // such as a nested collapse panel transitioning. But we only // want to handle this if this component's element is transitioning - if (e.target !== el.current || e.propertyName !== 'height') { + if (e.target !== el.current || e.propertyName !== dimension) { return } - // The height comparisons below are a final check before + // The height/width comparisons below are a final check before // completing the transition // Sometimes this callback is run even though we've already begun // transitioning the other direction // The conditions give us the opportunity to bail out, // which will prevent the collapsed content from flashing on the screen if (isExpanded) { - const height = getElementHeight(el) + const dimensionValue = isHorizontal ? getElementWidth(el) : getElementHeight(el) - // If the height at the end of the transition - // matches the height we're animating to, - if (height === styles.height) { + // If the height/width at the end of the transition + // matches the height/width we're animating to, + if (dimensionValue === styles[dimension]) { setStyles({}) } else { - // If the heights don't match, this could be due the height + // If the heights/widths don't match, this could be due the height/width // of the content changing mid-transition - mergeStyles({ height }) + mergeStyles({ [dimension]: dimensionValue }) } onExpandEnd() - // If the height we should be animating to matches the collapsed height, + // If the height/width we should be animating to matches the collapsed height/width, // it's safe to apply the collapsed overrides - } else if (styles.height === collapsedHeight) { - setStyles(collapsedStyles) + } else if (styles[dimension] === collapsedDimension) { + setStyles({...collapsedStyles, ...(isHorizontal ? {height: initHeight} : {})}) onCollapseEnd() } } diff --git a/src/types.ts b/src/types.ts index 69b670e..6901b62 100644 --- a/src/types.ts +++ b/src/types.ts @@ -57,6 +57,7 @@ export interface UseCollapseInput { isExpanded?: boolean defaultExpanded?: boolean collapsedHeight?: number + collapsedWidth?: number expandStyles?: {} collapseStyles?: {} easing?: string @@ -66,6 +67,7 @@ export interface UseCollapseInput { onExpandStart?: () => void onExpandEnd?: () => void hasDisabledAnimation?: boolean + isHorizontal?: boolean } export interface UseCollapseOutput { diff --git a/src/utils.ts b/src/utils.ts index e049888..7478e31 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -29,6 +29,21 @@ export function getElementHeight( return el.current.scrollHeight } +export function getElementWidth( + el: RefObject | { current?: { scrollWidth: number } } +): string | number { + if (!el?.current) { + warning( + true, + `useCollapse was not able to find a ref to the collapse element via \`getCollapseProps\`. Ensure that the element exposes its \`ref\` prop. If it exposes the ref prop under a different name (like \`innerRef\`), use the \`refKey\` property to change it. Example: + +{...getCollapseProps({refKey: 'innerRef'})}` + ) + return 'auto' + } + return el.current.scrollWidth +} + // Helper function for render props. Sets a function to be called, plus any additional functions passed in export const callAll = (...fns: AnyFunction[]) => @@ -36,12 +51,12 @@ export const callAll = fns.forEach((fn) => fn && fn(...args)) // https://github.com/mui-org/material-ui/blob/da362266f7c137bf671d7e8c44c84ad5cfc0e9e2/packages/material-ui/src/styles/transitions.js#L89-L98 -export function getAutoHeightDuration(height: number | string): number { - if (!height || typeof height === 'string') { +export function getAutoDistanceDuration(distance: number | string): number { + if (!distance || typeof distance === 'string') { return 0 } - const constant = height / 36 + const constant = distance / 36 // https://www.wolframalpha.com/input/?i=(4+%2B+15+*+(x+%2F+36+)+**+0.25+%2B+(x+%2F+36)+%2F+5)+*+10 return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10) From c5504e4bb658061e331d335c45f3634d963a7896 Mon Sep 17 00:00:00 2001 From: Said MARAR Date: Sat, 24 Dec 2022 21:11:14 +0100 Subject: [PATCH 02/10] fix doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b58d349..d3e6bec 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ The following are optional properties passed into `useCollapse({ })`: | -------------------- | -------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | isExpanded | boolean | `undefined` | If true, the Collapse is expanded | | defaultExpanded | boolean | `false` | If true, the Collapse will be expanded when mounted | -| isHorizontal | boolean | `false` | If true, the component will collapse/expand will horizontally | +| isHorizontal | boolean | `false` | If true, the component will collapse/expand horizontally | | expandStyles | object | `{}` | Style object applied to the collapse panel when it expands | | collapseStyles | object | `{}` | Style object applied to the collapse panel when it collapses | | collapsedHeight | number | `0` | The height of the content when collapsed | From 55f10ae7c3d50e74249bd68e57535f274c587fa4 Mon Sep 17 00:00:00 2001 From: Said MARAR Date: Mon, 16 Jan 2023 16:38:45 +0100 Subject: [PATCH 03/10] add horizontal mode (width) --- packages/core/src/Collapse.ts | 62 ++++++++++++++++++++++++----------- packages/core/src/utils.ts | 6 ++-- packages/react/README.md | 8 +++-- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/packages/core/src/Collapse.ts b/packages/core/src/Collapse.ts index fc808bf..e703710 100644 --- a/packages/core/src/Collapse.ts +++ b/packages/core/src/Collapse.ts @@ -1,4 +1,4 @@ -import { uid, getAutoHeightDuration, paddingWarning } from './utils' +import { uid, getAutoDimensionDuration, paddingWarning } from './utils' type Style = Partial @@ -6,7 +6,7 @@ export interface CollapseParams { /** If true, the collapse element will initialize expanded */ defaultExpanded?: boolean /** Height in pixels that the collapse element collapses to */ - collapsedHeight?: number + collapsedDimension?: number /** Styles applied to the collapse upon expanding */ expandStyles?: Style /** Styles applied to the collapse upon collapsing */ @@ -22,6 +22,8 @@ export interface CollapseParams { hasDisabledAnimation?: boolean /** Unique ID used for accessibility */ id?: string + /** Horizontal mode expand/collapse width */ + isHorizontal?: boolean /** Handler called when the expanded state changes */ onExpandedChange?: (state: boolean) => void /** Handler called when the collapse transition starts */ @@ -44,10 +46,14 @@ export class Collapse { private id!: string private collapseElement: HTMLElement | null | undefined = null private isMounted = false + private dimension: 'height' | 'width' + private initialWidth = 0 + private initialHeight = 0 constructor(params: CollapseParams) { this.setOptions(params) this.isExpanded = Boolean(this.options.defaultExpanded) + this.dimension = this.options.isHorizontal ? 'width' : 'height' this.init() this.isMounted = true } @@ -56,16 +62,21 @@ export class Collapse { const collapseElement = this.options.getCollapseElement() if (this.collapseElement !== collapseElement) { this.collapseElement = collapseElement + this.setInitialDimensions() if (!this.isExpanded) { - this.setStyles(this.getCollapsedStyles()) + this.setStyles({ + ...this.getCollapsedStyles(), + // When expand = false and collapsing width we preserve initial height + ...(this.options.isHorizontal ? {height: `${this.initialHeight}px`} : {}), + }) } } } private getCollapsedStyles = (): Style => { return { - display: this.options.collapsedHeight === 0 ? 'none' : 'block', - height: `${this.options.collapsedHeight}px`, + display: this.options.collapsedDimension === 0 ? 'none' : 'block', + [this.dimension]: `${this.options.collapsedDimension}px`, overflow: 'hidden', } } @@ -85,8 +96,9 @@ export class Collapse { expandStyles: {}, collapseStyles: {}, hasDisabledAnimation: false, - collapsedHeight: 0, + collapsedDimension: 0, defaultExpanded: false, + isHorizontal: false, onExpandedChange() {}, ...opts, } @@ -109,25 +121,25 @@ export class Collapse { } } - private getTransitionStyles = (height: number | string) => { + private getTransitionStyles = (dimension: number | string) => { if (this.options.hasDisabledAnimation) { return '' } const duration = this.options.duration === 'auto' - ? getAutoHeightDuration(height) + ? getAutoDimensionDuration(dimension) : this.options.duration - return `height ${duration}ms ${this.options.easing}` + return `${this.dimension} ${duration}ms ${this.options.easing}` } private handleTransitionEnd = (e: TransitionEvent) => { - if (e.propertyName !== 'height') { + if (e.propertyName !== this.dimension) { return } if (this.isExpanded) { this.setStyles({ - height: '', + [this.dimension]: '', overflow: '', transition: '', display: '', @@ -142,6 +154,16 @@ export class Collapse { } } + private setInitialDimensions = () => { + const collapseElement = this.options.getCollapseElement() + if (this.initialWidth === 0) { + this.initialWidth = collapseElement?.scrollWidth || 0 + } + if (this.initialHeight === 0) { + this.initialHeight = collapseElement?.scrollHeight || 0 + } + } + open = (): void => { // don't repeat if already open if (this.isExpanded || !this.isMounted) { @@ -162,14 +184,14 @@ export class Collapse { ...this.options.expandStyles, display: 'block', overflow: 'hidden', - height: `${this.options.collapsedHeight}px`, + [this.dimension]: `${this.options.collapsedDimension}px`, }) requestAnimationFrame(() => { - const height = target.scrollHeight + const dimensionValue = this.options.isHorizontal ? this.initialWidth : target.scrollHeight // Order important! So setting properties directly - target.style.transition = this.getTransitionStyles(height) - target.style.height = `${height}px` + target.style.transition = this.getTransitionStyles(dimensionValue) + target.style[this.dimension] = `${dimensionValue}px` }) }) } @@ -194,16 +216,18 @@ export class Collapse { this.options.onExpandedChange?.(false) this.options.onCollapseStart?.() requestAnimationFrame(() => { - const height = target.scrollHeight + const dimensionValue = this.options.isHorizontal ? target.scrollWidth : target.scrollHeight this.setStyles({ ...this.options.collapseStyles, - transition: this.getTransitionStyles(height), - height: `${height}px`, + transition: this.getTransitionStyles(dimensionValue), + [this.dimension]: `${dimensionValue}px`, }) requestAnimationFrame(() => { this.setStyles({ - height: `${this.options.collapsedHeight}px`, + [this.dimension]: `${this.options.collapsedDimension}px`, overflow: 'hidden', + // when collapsing width we make sure to preserve the initial height + ...(this.options.isHorizontal ? {height: `${this.initialHeight}px`} : {}), }) }) }) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index bab99b0..37494f7 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -9,12 +9,12 @@ export const callAll = fns.forEach((fn) => fn && fn(...args)) // https://github.com/mui-org/material-ui/blob/da362266f7c137bf671d7e8c44c84ad5cfc0e9e2/packages/material-ui/src/styles/transitions.js#L89-L98 -export function getAutoHeightDuration(height: number | string): number { - if (!height || typeof height === 'string') { +export function getAutoDimensionDuration(dimension: number | string): number { + if (!dimension || typeof dimension === 'string') { return 0 } - const constant = height / 36 + const constant = dimension / 36 // https://www.wolframalpha.com/input/?i=(4+%2B+15+*+(x+%2F+36+)+**+0.25+%2B+(x+%2F+36)+%2F+5)+*+10 return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10) diff --git a/packages/react/README.md b/packages/react/README.md index f1b3f02..b31d619 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -9,7 +9,7 @@ A React hook for creating accessible expand/collapse components. Animates the he ## Features -- Handles the height of animations of your elements, `auto` included! +- Handles the height/width of animations of your elements, `auto` included! - You control the UI - `useCollapse` provides the necessary props, you control the styles and the elements. - Accessible out of the box - no need to worry if your collapse/expand component is accessible, since this takes care of it for you! - No animation framework required! Simply powered by CSS animations @@ -81,9 +81,10 @@ const { getCollapseProps, getToggleProps, isExpanded, setExpanded } = useCollapse({ isExpanded: boolean, defaultExpanded: boolean, + isHorizontal: boolean, expandStyles: {}, collapseStyles: {}, - collapsedHeight: 0, + collapsedDimension: 0, easing: string, duration: number, onCollapseStart: func, @@ -101,9 +102,10 @@ The following are optional properties passed into `useCollapse({ })`: | -------------------- | -------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | isExpanded | boolean | `undefined` | If true, the Collapse is expanded | | defaultExpanded | boolean | `false` | If true, the Collapse will be expanded when mounted | +| isHorizontal | boolean | `false` | If true, the component will collapse/expand horizontally | | expandStyles | object | `{}` | Style object applied to the collapse panel when it expands | | collapseStyles | object | `{}` | Style object applied to the collapse panel when it collapses | -| collapsedHeight | number | `0` | The height of the content when collapsed | +| collapsedDimension | number | `0` | The height/width of the content when collapsed | | easing | string | `cubic-bezier(0.4, 0, 0.2, 1)` | The transition timing function for the animation | | duration | number | `undefined` | The duration of the animation in milliseconds. By default, the duration is programmatically calculated based on the height of the collapsed element | | onCollapseStart | function | no-op | Handler called when the collapse animation begins | From cdd8229eaf5ac511c8fa1e794b5e753ef75f67e4 Mon Sep 17 00:00:00 2001 From: Said MARAR Date: Mon, 16 Jan 2023 18:24:33 +0100 Subject: [PATCH 04/10] add horizontal mode story --- packages/react/src/stories/basic.stories.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/react/src/stories/basic.stories.tsx b/packages/react/src/stories/basic.stories.tsx index 6d7c5b3..8191d2b 100644 --- a/packages/react/src/stories/basic.stories.tsx +++ b/packages/react/src/stories/basic.stories.tsx @@ -29,6 +29,17 @@ export const Controlled = () => { ) } +export const HorizontalMode = () => { + const { getToggleProps, getCollapseProps, isExpanded } = useCollapse({ isHorizontal: true }) + + return ( +
+ {isExpanded ? 'Close' : 'Open'} + {excerpt} +
+ ) +} + function useReduceMotion() { const [matches, setMatch] = React.useState( window.matchMedia('(prefers-reduced-motion: reduce)').matches From 7c30d276e296fc304c52d1c266b09ebaf69774ab Mon Sep 17 00:00:00 2001 From: Said MARAR Date: Mon, 16 Jan 2023 20:54:22 +0100 Subject: [PATCH 05/10] update code --- packages/core/src/Collapse.ts | 36 ++++++++++++-------- packages/react/README.md | 34 +++++++++--------- packages/react/src/stories/basic.stories.tsx | 2 +- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/packages/core/src/Collapse.ts b/packages/core/src/Collapse.ts index e703710..fed4a9c 100644 --- a/packages/core/src/Collapse.ts +++ b/packages/core/src/Collapse.ts @@ -5,7 +5,9 @@ type Style = Partial export interface CollapseParams { /** If true, the collapse element will initialize expanded */ defaultExpanded?: boolean - /** Height in pixels that the collapse element collapses to */ + /** @deprecate Height in pixels that the collapse element collapses to */ + collapsedHeight?: number + /** Dimension in pixels that the collapse element collapses to */ collapsedDimension?: number /** Styles applied to the collapse upon expanding */ expandStyles?: Style @@ -22,8 +24,8 @@ export interface CollapseParams { hasDisabledAnimation?: boolean /** Unique ID used for accessibility */ id?: string - /** Horizontal mode expand/collapse width */ - isHorizontal?: boolean + /** Vertical/Horizontal mode expand/collapse height/width, default value is vertical */ + axis?: 'vertical' | 'horizontal' /** Handler called when the expanded state changes */ onExpandedChange?: (state: boolean) => void /** Handler called when the collapse transition starts */ @@ -46,14 +48,15 @@ export class Collapse { private id!: string private collapseElement: HTMLElement | null | undefined = null private isMounted = false + private isVertical = true private dimension: 'height' | 'width' - private initialWidth = 0 - private initialHeight = 0 + private initialDimensions = { height: 0, width: 0 } constructor(params: CollapseParams) { this.setOptions(params) this.isExpanded = Boolean(this.options.defaultExpanded) - this.dimension = this.options.isHorizontal ? 'width' : 'height' + this.isVertical = this.options.axis === 'vertical' + this.dimension = this.isVertical ? 'height' : 'width' this.init() this.isMounted = true } @@ -67,7 +70,7 @@ export class Collapse { this.setStyles({ ...this.getCollapsedStyles(), // When expand = false and collapsing width we preserve initial height - ...(this.options.isHorizontal ? {height: `${this.initialHeight}px`} : {}), + ...(this.isVertical ? {} : { height: `${this.initialDimensions.height}px` }), }) } } @@ -96,13 +99,16 @@ export class Collapse { expandStyles: {}, collapseStyles: {}, hasDisabledAnimation: false, + collapsedHeight: 0, collapsedDimension: 0, defaultExpanded: false, - isHorizontal: false, + axis: 'vertical', onExpandedChange() {}, ...opts, } + this.options.collapsedDimension = this.isVertical ? this.options.collapsedHeight : this.options.collapsedDimension + this.id = this.options.id ?? `collapse-${uid(this)}` } @@ -156,11 +162,11 @@ export class Collapse { private setInitialDimensions = () => { const collapseElement = this.options.getCollapseElement() - if (this.initialWidth === 0) { - this.initialWidth = collapseElement?.scrollWidth || 0 + if (this.initialDimensions.width === 0) { + this.initialDimensions.width = collapseElement?.scrollWidth || 0 } - if (this.initialHeight === 0) { - this.initialHeight = collapseElement?.scrollHeight || 0 + if (this.initialDimensions.height === 0) { + this.initialDimensions.height = collapseElement?.scrollHeight || 0 } } @@ -187,7 +193,7 @@ export class Collapse { [this.dimension]: `${this.options.collapsedDimension}px`, }) requestAnimationFrame(() => { - const dimensionValue = this.options.isHorizontal ? this.initialWidth : target.scrollHeight + const dimensionValue = this.isVertical ? target.scrollHeight : this.initialDimensions.width // Order important! So setting properties directly target.style.transition = this.getTransitionStyles(dimensionValue) @@ -216,7 +222,7 @@ export class Collapse { this.options.onExpandedChange?.(false) this.options.onCollapseStart?.() requestAnimationFrame(() => { - const dimensionValue = this.options.isHorizontal ? target.scrollWidth : target.scrollHeight + const dimensionValue = this.isVertical ? target.scrollHeight : target.scrollWidth this.setStyles({ ...this.options.collapseStyles, transition: this.getTransitionStyles(dimensionValue), @@ -227,7 +233,7 @@ export class Collapse { [this.dimension]: `${this.options.collapsedDimension}px`, overflow: 'hidden', // when collapsing width we make sure to preserve the initial height - ...(this.options.isHorizontal ? {height: `${this.initialHeight}px`} : {}), + ...(this.isVertical ? {} : { height: `${this.initialDimensions.height}px` }), }) }) }) diff --git a/packages/react/README.md b/packages/react/README.md index b31d619..093f033 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -81,9 +81,10 @@ const { getCollapseProps, getToggleProps, isExpanded, setExpanded } = useCollapse({ isExpanded: boolean, defaultExpanded: boolean, - isHorizontal: boolean, + axis: 'vertical' | 'horizontal', expandStyles: {}, collapseStyles: {}, + collapsedHeight: 0, collapsedDimension: 0, easing: string, duration: number, @@ -98,21 +99,22 @@ const { getCollapseProps, getToggleProps, isExpanded, setExpanded } = The following are optional properties passed into `useCollapse({ })`: -| Prop | Type | Default | Description | -| -------------------- | -------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| isExpanded | boolean | `undefined` | If true, the Collapse is expanded | -| defaultExpanded | boolean | `false` | If true, the Collapse will be expanded when mounted | -| isHorizontal | boolean | `false` | If true, the component will collapse/expand horizontally | -| expandStyles | object | `{}` | Style object applied to the collapse panel when it expands | -| collapseStyles | object | `{}` | Style object applied to the collapse panel when it collapses | -| collapsedDimension | number | `0` | The height/width of the content when collapsed | -| easing | string | `cubic-bezier(0.4, 0, 0.2, 1)` | The transition timing function for the animation | -| duration | number | `undefined` | The duration of the animation in milliseconds. By default, the duration is programmatically calculated based on the height of the collapsed element | -| onCollapseStart | function | no-op | Handler called when the collapse animation begins | -| onCollapseEnd | function | no-op | Handler called when the collapse animation ends | -| onExpandStart | function | no-op | Handler called when the expand animation begins | -| onExpandEnd | function | no-op | Handler called when the expand animation ends | -| hasDisabledAnimation | boolean | false | If true, will disable the animation | +| Prop | Type | Default | Description | +| -------------------- | -------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| isExpanded | boolean | `undefined` | If true, the Collapse is expanded | +| defaultExpanded | boolean | `false` | If true, the Collapse will be expanded when mounted | +| axis | "vertical" / "horizontal" | `"vertical"` | If "horizontal", the component will collapse/expand horizontally | +| expandStyles | object | `{}` | Style object applied to the collapse panel when it expands | +| collapseStyles | object | `{}` | Style object applied to the collapse panel when it collapses | +| collapsedHeight | number | `0` | The height of the content when collapsed | +| collapsedDimension | number | `0` | The height/width of the content when collapsed | +| easing | string | `cubic-bezier(0.4, 0, 0.2, 1)` | The transition timing function for the animation | +| duration | number | `undefined` | The duration of the animation in milliseconds. By default, the duration is programmatically calculated based on the height of the collapsed element | +| onCollapseStart | function | no-op | Handler called when the collapse animation begins | +| onCollapseEnd | function | no-op | Handler called when the collapse animation ends | +| onExpandStart | function | no-op | Handler called when the expand animation begins | +| onExpandEnd | function | no-op | Handler called when the expand animation ends | +| hasDisabledAnimation | boolean | false | If true, will disable the animation | ### What you get diff --git a/packages/react/src/stories/basic.stories.tsx b/packages/react/src/stories/basic.stories.tsx index 8191d2b..791763c 100644 --- a/packages/react/src/stories/basic.stories.tsx +++ b/packages/react/src/stories/basic.stories.tsx @@ -30,7 +30,7 @@ export const Controlled = () => { } export const HorizontalMode = () => { - const { getToggleProps, getCollapseProps, isExpanded } = useCollapse({ isHorizontal: true }) + const { getToggleProps, getCollapseProps, isExpanded } = useCollapse({ axis: 'horizontal' }) return (
From eeddcff48d2a7da74e55d80ea0cf61e7f434831d Mon Sep 17 00:00:00 2001 From: Said MARAR Date: Mon, 16 Jan 2023 21:02:50 +0100 Subject: [PATCH 06/10] update doc --- packages/core/src/Collapse.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/src/Collapse.ts b/packages/core/src/Collapse.ts index fed4a9c..ce8d8b1 100644 --- a/packages/core/src/Collapse.ts +++ b/packages/core/src/Collapse.ts @@ -5,7 +5,8 @@ type Style = Partial export interface CollapseParams { /** If true, the collapse element will initialize expanded */ defaultExpanded?: boolean - /** @deprecate Height in pixels that the collapse element collapses to */ + /** @deprecate will be replaced by collapsedDimension + * Height in pixels that the collapse element collapses to */ collapsedHeight?: number /** Dimension in pixels that the collapse element collapses to */ collapsedDimension?: number From b88ba1cb6b6e569f2524c90b67d9cec54b491952 Mon Sep 17 00:00:00 2001 From: Rogin Farrer Date: Mon, 16 Jan 2023 17:07:43 -0800 Subject: [PATCH 07/10] add sidebar example, fix core version --- example/index.tsx | 50 +++++++++++++++++++- packages/react/package.json | 2 +- packages/react/src/stories/basic.stories.tsx | 4 +- pnpm-lock.yaml | 2 +- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/example/index.tsx b/example/index.tsx index 37286fe..f77fe59 100644 --- a/example/index.tsx +++ b/example/index.tsx @@ -11,6 +11,7 @@ export const Uncontrolled = () => { return (
+

Uncontrolled

@@ -32,10 +33,57 @@ export const Uncontrolled = () => { ) } -const App = () => { +const Sidebar = () => { + const [showExample, setShowExample] = React.useState(false) + const { getToggleProps, getCollapseProps, isExpanded } = useCollapse({ + axis: 'horizontal', + collapsedDimension: 75, + }) + + let content: JSX.Element + if (!showExample) { + content = + } else { + content = ( +
+
+
+ + +
sit at the bottom
+
+
+
+ ) + } + return (
+

Sidebar

+ {content} +
+ ) +} + +const App = () => { + return ( +
+
) } diff --git a/packages/react/package.json b/packages/react/package.json index bc34eee..6675920 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -71,7 +71,7 @@ "vite": "^3.2.4" }, "dependencies": { - "@collapsed/core": "workspace:*", + "@collapsed/core": "4.0.0", "tiny-warning": "^1.0.3" }, "repository": { diff --git a/packages/react/src/stories/basic.stories.tsx b/packages/react/src/stories/basic.stories.tsx index 791763c..800f1ec 100644 --- a/packages/react/src/stories/basic.stories.tsx +++ b/packages/react/src/stories/basic.stories.tsx @@ -30,7 +30,9 @@ export const Controlled = () => { } export const HorizontalMode = () => { - const { getToggleProps, getCollapseProps, isExpanded } = useCollapse({ axis: 'horizontal' }) + const { getToggleProps, getCollapseProps, isExpanded } = useCollapse({ + axis: 'horizontal', + }) return (
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ecfdeeb..e11dde3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -122,7 +122,7 @@ importers: '@babel/preset-react': ^7.14.5 '@collapsed-internal/build': workspace:* '@collapsed-internal/tsconfig': workspace:* - '@collapsed/core': workspace:* + '@collapsed/core': 4.0.0 '@cypress/vite-dev-server': ^5.0.0 '@storybook/addon-a11y': ^6.5.11 '@storybook/addon-actions': ^6.5.11 From 79a6b40970232f29906664d7b878a5ef3fbe2d43 Mon Sep 17 00:00:00 2001 From: SaidMarar Date: Tue, 17 Jan 2023 10:11:55 +0100 Subject: [PATCH 08/10] Update packages/core/src/Collapse.ts Co-authored-by: Rogin Farrer --- packages/core/src/Collapse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/Collapse.ts b/packages/core/src/Collapse.ts index ce8d8b1..b21d393 100644 --- a/packages/core/src/Collapse.ts +++ b/packages/core/src/Collapse.ts @@ -5,7 +5,7 @@ type Style = Partial export interface CollapseParams { /** If true, the collapse element will initialize expanded */ defaultExpanded?: boolean - /** @deprecate will be replaced by collapsedDimension + /** @deprecated will be replaced by collapsedDimension * Height in pixels that the collapse element collapses to */ collapsedHeight?: number /** Dimension in pixels that the collapse element collapses to */ From 9637fb9bde82d0a263cfb17a57ed330abec84916 Mon Sep 17 00:00:00 2001 From: SaidMarar Date: Tue, 17 Jan 2023 10:28:09 +0100 Subject: [PATCH 09/10] Update packages/react/README.md Co-authored-by: Rogin Farrer --- packages/react/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/README.md b/packages/react/README.md index 093f033..7e2b775 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -84,7 +84,6 @@ const { getCollapseProps, getToggleProps, isExpanded, setExpanded } = axis: 'vertical' | 'horizontal', expandStyles: {}, collapseStyles: {}, - collapsedHeight: 0, collapsedDimension: 0, easing: string, duration: number, From 3ae5a7e573ff934c644f281448ccf02370836e76 Mon Sep 17 00:00:00 2001 From: SaidMarar Date: Tue, 17 Jan 2023 10:32:07 +0100 Subject: [PATCH 10/10] Update packages/react/README.md Co-authored-by: Rogin Farrer --- packages/react/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/README.md b/packages/react/README.md index 7e2b775..0c096fc 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -105,7 +105,6 @@ The following are optional properties passed into `useCollapse({ })`: | axis | "vertical" / "horizontal" | `"vertical"` | If "horizontal", the component will collapse/expand horizontally | | expandStyles | object | `{}` | Style object applied to the collapse panel when it expands | | collapseStyles | object | `{}` | Style object applied to the collapse panel when it collapses | -| collapsedHeight | number | `0` | The height of the content when collapsed | | collapsedDimension | number | `0` | The height/width of the content when collapsed | | easing | string | `cubic-bezier(0.4, 0, 0.2, 1)` | The transition timing function for the animation | | duration | number | `undefined` | The duration of the animation in milliseconds. By default, the duration is programmatically calculated based on the height of the collapsed element |