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

ToggleGroupControl: rewrite backdrop animation with framer motion shared layout animations #50278

Merged
merged 42 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ed5e18d
Reuse previous implementation
ciampo Apr 30, 2023
ea4c62f
Reset motion context in slot-fill
ciampo May 1, 2023
b8bc3c5
Memoize classes
ciampo May 1, 2023
ba4a3c2
Move layout group to root component
ciampo May 1, 2023
5ab8f5a
Use useLayoutEffect to apply internal state changes
ciampo May 2, 2023
03ffe1a
CHANGELOG
ciampo May 3, 2023
0a52c45
Update snapshots
ciampo May 3, 2023
8384195
Expose motion context from the components package
ciampo Jun 8, 2023
d7785ba
Refactor inspector controls slot/fill to accept an array of context p…
ciampo Jun 8, 2023
2ae837a
Add framer motion context to the forwarded contexts in inspector cont…
ciampo Jun 8, 2023
d2edd74
Remove hardcoded motion provider from fill component, update slot fil…
ciampo Jun 8, 2023
759658f
CHANGELOG update
ciampo Jun 8, 2023
6c7166e
Update as button group to also use useLayoutEffect
ciampo Jun 8, 2023
5aa029e
Use controlled version of the component in unit tests
ciampo Jun 8, 2023
9a63905
Improve context provider storybook types
ciampo Jun 9, 2023
95ec7a0
Fix register/deregister logic for toolspanel in inspector controls
ciampo Jun 9, 2023
8d09bd2
extract useUpdateLayoutEffect to separate util hook
ciampo Jun 9, 2023
49594aa
Better fillprops forwarded context type
ciampo Jun 11, 2023
4784edd
Change docs to have controlled usage
ciampo Jun 11, 2023
1b18a0a
Reuse types
ciampo Jun 22, 2023
b1c6a27
Add defaultValue prop
ciampo Jun 22, 2023
31f352b
Refactor component to handle both controlled and uncontrolled updates
ciampo Jun 22, 2023
b0410fd
Remove unused `useUpdateLayoutEffect` hook
ciampo Jun 22, 2023
ec6da00
Update unit tess: check both controlled and uncontrolled, use initial…
ciampo Jun 22, 2023
dc4ceea
Introduce logic to distinguish undefined as controlled or uncontrolle…
ciampo Jun 26, 2023
fc03b14
Bring back README example to be uncontrolled, but use `defaultValue`
ciampo Jun 26, 2023
8c84d61
Update `defaultValue` prop description, add to README
ciampo Jun 26, 2023
4da4e77
Stop using deprecated `ReactText` type, use `string | number` instead
ciampo Jun 26, 2023
14f8897
Add keyboard interaction with reset unit test
ciampo Jun 27, 2023
9d11002
Add reset button to Storybook example
ciampo Jun 27, 2023
0d75bf5
Refactor to ariakit
ciampo Jun 27, 2023
cebd4f5
Pass props to `button` instead of `radio`
ciampo Jun 27, 2023
3948355
add support for uncontrolled without the `defaultValue` prop
ciampo Aug 30, 2023
0253bf5
Update snappshots
ciampo Aug 30, 2023
25435f3
Restore README
ciampo Aug 30, 2023
420681a
Update CHANGELOG
ciampo Aug 30, 2023
81e8277
Format
ciampo Aug 30, 2023
9beee76
Fix format (again)
ciampo Aug 30, 2023
1e2ff30
Remove unnecessary cast to string when using `useInstanceId`
ciampo Sep 5, 2023
ee5e7f4
Remove temporary Storybook changes
ciampo Sep 5, 2023
2364d02
CHANGELOG
ciampo Sep 5, 2023
e69993e
Fix indentation
ciampo Sep 5, 2023
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
Expand Up @@ -2,11 +2,27 @@
* WordPress dependencies
*/
import { __experimentalToolsPanelContext as ToolsPanelContext } from '@wordpress/components';
import { useContext } from '@wordpress/element';
import { useContext, useMemo } from '@wordpress/element';

export default function BlockSupportSlotContainer( { Slot, ...props } ) {
export default function BlockSupportSlotContainer( {
Slot,
fillProps,
...props
} ) {
// Add the toolspanel context provider and value to existing fill props
const toolsPanelContext = useContext( ToolsPanelContext );
const computedFillProps = useMemo(
() => ( {
...( fillProps ?? {} ),
forwardedContext: [
...( fillProps?.forwardedContext ?? [] ),
[ ToolsPanelContext.Provider, { value: toolsPanelContext } ],
],
} ),
[ toolsPanelContext, fillProps ]
);

return (
<Slot { ...props } fillProps={ toolsPanelContext } bubblesVirtually />
<Slot { ...props } fillProps={ computedFillProps } bubblesVirtually />
);
}
42 changes: 28 additions & 14 deletions packages/block-editor/src/components/inspector-controls/fill.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from '@wordpress/components';
import warning from '@wordpress/warning';
import deprecated from '@wordpress/deprecated';
import { useEffect } from '@wordpress/element';
import { useEffect, useContext } from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -60,28 +60,42 @@ export default function InspectorControlsFill( {
);
}

function ToolsPanelInspectorControl( { children, resetAllFilter, fillProps } ) {
const { registerResetAllFilter, deregisterResetAllFilter } = fillProps;
function RegisterResetAll( { resetAllFilter, children } ) {
const { registerResetAllFilter, deregisterResetAllFilter } =
useContext( ToolsPanelContext );
useEffect( () => {
if ( resetAllFilter && registerResetAllFilter ) {
if (
resetAllFilter &&
registerResetAllFilter &&
deregisterResetAllFilter
) {
registerResetAllFilter( resetAllFilter );
}
return () => {
if ( resetAllFilter && deregisterResetAllFilter ) {
return () => {
deregisterResetAllFilter( resetAllFilter );
}
};
};
}
}, [ resetAllFilter, registerResetAllFilter, deregisterResetAllFilter ] );
ciampo marked this conversation as resolved.
Show resolved Hide resolved
return children;
}

function ToolsPanelInspectorControl( { children, resetAllFilter, fillProps } ) {
// `fillProps.forwardedContext` is an array of context provider entries, provided by slot,
// that should wrap the fill markup.
const { forwardedContext = [] } = fillProps;

// Children passed to InspectorControlsFill will not have
// access to any React Context whose Provider is part of
// the InspectorControlsSlot tree. So we re-create the
// Provider in this subtree.
const value =
fillProps && Object.keys( fillProps ).length > 0 ? fillProps : null;
return (
<ToolsPanelContext.Provider value={ value }>
const innerMarkup = (
<RegisterResetAll resetAllFilter={ resetAllFilter }>
{ children }
</ToolsPanelContext.Provider>
</RegisterResetAll>
);
return forwardedContext.reduce(
( inner, [ Provider, props ] ) => (
<Provider { ...props }>{ inner }</Provider>
),
innerMarkup
);
}
31 changes: 28 additions & 3 deletions packages/block-editor/src/components/inspector-controls/slot.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/**
* WordPress dependencies
*/
import { __experimentalUseSlotFills as useSlotFills } from '@wordpress/components';
import {
__experimentalUseSlotFills as useSlotFills,
__unstableMotionContext as MotionContext,
} from '@wordpress/components';
import { useContext, useMemo } from '@wordpress/element';
import warning from '@wordpress/warning';
import deprecated from '@wordpress/deprecated';

Expand All @@ -16,6 +20,7 @@ export default function InspectorControlsSlot( {
__experimentalGroup,
group = 'default',
label,
fillProps,
...props
} ) {
if ( __experimentalGroup ) {
Expand All @@ -31,6 +36,20 @@ export default function InspectorControlsSlot( {
}
const Slot = groups[ group ]?.Slot;
const fills = useSlotFills( Slot?.__unstableName );

const motionContextValue = useContext( MotionContext );

const computedFillProps = useMemo(
() => ( {
...( fillProps ?? {} ),
forwardedContext: [
...( fillProps?.forwardedContext ?? [] ),
[ MotionContext.Provider, { value: motionContextValue } ],
],
} ),
[ motionContextValue, fillProps ]
);

if ( ! Slot ) {
warning( `Unknown InspectorControls group "${ group }" provided.` );
return null;
Expand All @@ -43,10 +62,16 @@ export default function InspectorControlsSlot( {
if ( label ) {
return (
<BlockSupportToolsPanel group={ group } label={ label }>
<BlockSupportSlotContainer { ...props } Slot={ Slot } />
<BlockSupportSlotContainer
{ ...props }
fillProps={ computedFillProps }
Slot={ Slot }
/>
</BlockSupportToolsPanel>
);
}

return <Slot { ...props } bubblesVirtually />;
return (
<Slot { ...props } fillProps={ computedFillProps } bubblesVirtually />
);
}
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Enhancements

- Making Circular Option Picker a `listbox`. Note that while this changes some public API, new props are optional, and currently have default values; this will change in another patch ([#52255](https://github.com/WordPress/gutenberg/pull/52255)).
- `ToggleGroupControl`: Rewrite backdrop animation using framer motion shared layout animations, add better support for controlled and uncontrolled modes ([#50278](https://github.com/WordPress/gutenberg/pull/50278)).
- `Popover`: Add the `is-positioned` CSS class only after the popover has finished animating ([#54178](https://github.com/WordPress/gutenberg/pull/54178)).

### Bug Fix
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/animation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
export {
motion as __unstableMotion,
AnimatePresence as __unstableAnimatePresence,
MotionContext as __unstableMotionContext,
} from 'framer-motion';
6 changes: 5 additions & 1 deletion packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ export {
default as Animate,
getAnimateClassName as __unstableGetAnimateClassName,
} from './animate';
export { __unstableMotion, __unstableAnimatePresence } from './animation';
export {
__unstableMotion,
__unstableAnimatePresence,
__unstableMotionContext,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: we may want to export the motion context differently? (ie. stable, or as private API)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's export all the providers (style, components, toolbar context, motion) consistently the same way, as private APIs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we can remove existing exports from the package — even if they are prefixed with __unstable, removing them would cause breaking changes in plugin and themes using them (I ran a quick search on wpdirectory and there are unfortunately some matches).

@youknowriad do you have any suggestions on how we may want to approach this? Given how "de facto" stable are __unstableMotion and __unstableAnimatePresence, should we just export them without the __unstable alias too?

} from './animation';
export { default as AnglePickerControl } from './angle-picker-control';
export {
default as Autocomplete,
Expand Down
Loading
Loading