Closed TrySpace closed 8 years ago
Disabling the height
, width
and border-radius
on the button would fix this actually.
But, the animation would break, so the height
and width
should be changed with the iconStyle
styles.
So in conclusion, I think the iconStyle
just needs to be applied to the button in this case, this way I could also overwrite the borderRadius
to 0
My code for the curious:
Just adding iconStyle
to the EnhancedButton
solved this (in floating-action-button.jsx):
style={this.mergeAndPrefix(
styles.container,
this.props.mini && styles.containerWhenMini,
iconStyle
)}
the animation might need some tweaking, because the bottom has some delay though.
Where I am now:
getDefaultProps: ->
floatyAddButton:
floatyAddButtonStyle:
position: 'fixed'
right: 16
bottom: 16
height: 56
width: 56
borderRadius: '50%'
floatyAddButtonStyleExpanded:
position: 'fixed'
right: 16
bottom: 16
height: 256
width: 356
borderRadius: 0
floatyAddButtonIconStyle:
height: 56
width: 56
borderRadius: '50%'
floatyAddButtonIconStyleExpanded:
height: 256
width: 356
borderRadius: 0
floatyAppButton:
floatyAppButtonStyle:
position: 'fixed'
left: 16
bottom: 16
height: 56
width: 56
borderRadius: '50%'
floatyAppButtonStyleExpanded:
position: 'fixed'
left: 16
bottom: 16
height: 256
width: 356
borderRadius: 0
floatyAppButtonIconStyle:
height: 56
width: 56
borderRadius: '50%'
floatyAppButtonIconStyleExpanded:
height: 256
width: 356
borderRadius: 0
getInitialState: ->
floatyAddButtonExpanded: false
floatyAddButtonStyle: @props.floatyAddButton.floatyAddButtonStyle
floatyAddButtonIconStyle: @props.floatyAddButton.floatyAddButtonIconStyle
floatyAppButtonExpanded: false
floatyAppButtonStyle: @props.floatyAppButton.floatyAppButtonStyle
floatyAppButtonIconStyle: @props.floatyAppButton.floatyAppButtonIconStyle
floatyAppButton: @props.floatyAppButton
expandAdd: ->
if !@state.floatyAddButtonExpanded
@setState
floatyAddButtonExpanded: true
floatyAddButtonStyle: @props.floatyAddButton.floatyAddButtonStyleExpanded
floatyAddButtonIconStyle: @props.floatyAddButton.floatyAddButtonIconStyleExpanded
else
@setState
floatyAddButtonExpanded: false
floatyAddButtonStyle: @props.floatyAddButton.floatyAddButtonStyle
floatyAddButtonIconStyle: @props.floatyAddButton.floatyAddButtonIconStyle
expandApps: ->
if !@state.floatyAppButtonExpanded
@setState
floatyAppButtonExpanded: true
floatyAppButtonStyle: @props.floatyAppButton.floatyAppButtonStyleExpanded
floatyAppButtonIconStyle: @props.floatyAppButton.floatyAppButtonIconStyleExpanded
else
@setState
floatyAppButtonExpanded: false
floatyAppButtonStyle: @props.floatyAppButton.floatyAppButtonStyle
floatyAppButtonIconStyle: @props.floatyAppButton.floatyAppButtonIconStyle
render: ->
<div>
<FloatingActionButton onClick={@expandAdd} style={@state.floatyAddButtonStyle} iconStyle={@state.floatyAddButtonIconStyle} secondary={true} >
{if @state.floatyAddButtonExpanded then <div className="app-add"> much wow </div> else <FontIcon className="material-icons">add</FontIcon>}
</FloatingActionButton>
<FloatingActionButton onClick={@expandApps} style={@state.floatyAppButtonStyle} iconStyle={@state.floatyAppButtonIconStyle} >
{if @state.floatyAppButtonExpanded then <div className="app-app"> much wow </div> else <FontIcon className="material-icons">apps</FontIcon>}
</FloatingActionButton>
</div>
It is getting a little repetitious after adding a second button. And I'm thinking about maybe needing a background div/shade, so that when you click outside the box it will 'dismiss' the expansion and revert to a button. Sort of like how the dialogue or sidebar works. And the ripple would need some tweaking.
Not sure right now how to use less state
variables right now.
I put in a Card
I set the height of the expanded styles to auto
And can stop the button click from closing it by using: e.stopPropagation()
on the onClick
of FlatButton
But if I use 80%
as height, the animation is smoother, but the CardText
element doesn't show up:
But we're getting there..
Also, the CardHeader
elements get centered.
Next problem, when putting a TextInput
element inside, it triggers the onClick
on parent element FloatingActionButton
, when pressing space
:
Also e.stopPropagation()
doesn't help.
And the FloatingActionButton
should "only listen to left clicks" it says in the source at the _handleMouseDown
method
I think it might be loosely related to: https://github.com/callemall/material-ui/issues/1595 , not directly, but in the way that events are handled in mui
, without keeping edge cases in sight. What I'm trying to say is that the FloatingButton
has a very singular purpose right now and is not very dynamic.
Update: I solved it by using onMouseDown
instead of onClick
have you considered having separate elements and animating between them? using something like http://kushagragour.in/lab/ctajs/
@chrismcv Not yet, but good tip, thanks!
Any progression on implementing animations natively with ctajs
or react-motion
?
No, still a dream away right now. The focus at the moment is on getting core cleaned up to make those sorts of changes easier.
I hadn't come across this post before, but I have to say, that FAB Morph is pretty nifty! :heart_eyes: Have you developed them further since?
This issue is closed, however for simply animating the MuiFab
component transitioning between an "open" and "closed" state (ie. showing and hiding the text/description) below is a slim wrapper which will animate the opening and closing action
"use client";
import { HTMLAttributeAnchorTarget, useEffect, useState } from "react";
import MuiFab, { FabProps as MuiFabProps } from "@mui/material/Fab";
import MuiCollapse from "@mui/material/Collapse";
import MuiTypography from "@mui/material/Typography";
export interface FabProps extends React.PropsWithChildren {
icon?: React.ReactNode;
iconPosition?: "start" | "end";
size?: MuiFabProps["size"];
href?: MuiFabProps["href"];
target?: HTMLAttributeAnchorTarget;
"aria-label"?: MuiFabProps["aria-label"];
open?: boolean;
expandable?: boolean | "hover" | "click";
onClick?: MuiFabProps["onClick"];
sx?: MuiFabProps["sx"];
disablePadding?: boolean;
}
export function Fab({
icon,
iconPosition = "start",
size,
onClick,
href: defaultHref,
target: defaultTarget,
"aria-label": ariaLabel,
open,
expandable,
disablePadding,
children,
}: FabProps) {
const [ expanded, setExpanded ] = useState(false);
const hover = expandable === "hover" || expandable === true;
const click = expandable === "click";
const isHovered =
(hover || click) && (open || expanded);
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
if (isHovered && onClick) {
onClick(e);
}
// kinda a shitty hack
// but without this, the href will never fire
// no idea why...
window.setTimeout(_ => {
setExpanded(prev => !prev);
}, 0);
}
function handleHoverIn() {
setExpanded(true);
}
function handleHoverOut() {
setExpanded(false);
}
/**
* Pseudo ClickAwayListener
*
* The MuiClickAwayListener has a delay when clicking
* away from the fab button causing a need to double-click
* to re-collapse the fab button
*/
useEffect(() => {
// hovering is not set to click
if (!click) {
return;
}
function handleClickAway() {
setExpanded(false);
}
const documentEvents: (keyof DocumentEventMap)[] = [
"click",
"touchstart"
];
const eventOptions: (boolean | AddEventListenerOptions) = false;
documentEvents.forEach(e =>
document.addEventListener(e, handleClickAway, eventOptions)
);
return () => {
documentEvents.forEach(e =>
document.removeEventListener(e, handleClickAway, eventOptions)
);
};
}, [ click ]);
const startIcon = iconPosition === "start" && icon;
const endIcon = iconPosition === "end" && icon;
const href = defaultHref ? (!click || isHovered ? defaultHref : "#") : undefined;
const target = href && href === "#" ? undefined : defaultTarget;
return (
<MuiFab
size={size}
variant="extended"
aria-label={ariaLabel}
href={href}
{...{
// directly setting this value will cause
// typescript errors
target: target
}}
onClick={click ? handleClick : onClick}
onMouseOver={hover ? handleHoverIn : undefined}
onMouseOut={hover ? handleHoverOut : undefined}
sx={{
paddingX: disablePadding || isHovered ? undefined : 0
}}
>
{startIcon}
<MuiCollapse
in={isHovered}
orientation="horizontal"
sx={{
alignSelf: "center"
}}>
<MuiTypography
component="span"
sx={{
ml: Boolean(startIcon) ? 1 : 0,
mr: Boolean(endIcon) ? 1 : 0,
fontSize: "inherit" }}
>
{children}
</MuiTypography>
</MuiCollapse>
{endIcon}
</MuiFab>
);
}
Usage:
export function DonateFab() {
return (
<Fab
size="medium"
icon={<VolunteerActivismIcon />}
href="example.com"
target="_blank"
expandable
>
Donate Now!
</Fab>);
}
export function DonateFab() {
return (
<Fab
size="medium"
icon={<VolunteerActivismIcon />}
href="example.com"
target="_blank"
expandable="click"
>
Donate Now!
</Fab>);
}
I'm trying to expand the
FloatingActionButton
withstyle
(height&width++) but when trying to do this for the inner element withiconStyle
with theFontIcon
it won't apply to the background (EnhancedButton
), only the icon itself. And there will still be a floating smaller button in theFloatingActionButton
Even when not using
FontIcon
(which the documentation implies it would work on) but just adiv
, theEnhancedButton
won't adhere to my overwrite styles:Also, the
TouchRipple
doesn't seem to accept the newwidth
:What I'm trying to achieve here is animating the
FloatingActionButton
to a particular size, change theborderRadius
to 0, then replacing it's content with some other element:The animation works very nicely already, I just need to be freed from the restrictions of it always being a button.
In the end I think there should be two extra options like:
expandStyle
to apply to the enhancedButton (which wouldn't function as a button anymore) and theFloatingActionButton
'sPaper
element to resize them uniformly on expand; And anexpandButton
function or state true/false, or preferably both. Or maybe make a seperate element likeExpandingFloatingActionButton
to keep the code clean.