Closed enagy27 closed 5 years ago
I've taken out the polyfill in favor
Awesome. Regarding taking the best API tradeoff, I believe implementing the filled variant at the same time would allow to have the big picture. I'm having a closer look at the pull request.
I believe implementing the filled variant at the same time would allow to have the big picture.
Yeah, in my implementation, I started with the filled variant, then added the outlined. The filled is mercifully straightforward compared to the Outlined.
Cool. I'm working on an implementation using fieldset
now. It's going very well- should have it ready for review by the end of next week! Will include both variants in that PR. Going this direction will make it very simple to apply the variant
, and I'm feeling good about the top-level API ๐
Cool. I'm working on an implementation using fieldset now.
We have some examples in the documentation doing such. I haven't looked into the topic. From my perspective, the fieldset is useful to group multiples fields. Here, we have a single input. What makes you think it's more appropriate?
@oliviertassinari in one of your earlier comments you mentioned this component as being a possible alternative to the svg, which seems appropriate given that its default styling is similar to the svg. It also has the benefit of being styled more easily than the svg, where its width and height are 100% of the corresponding input, and its border radius and other properties can be set, whereas they cannot be set without sending them down as a property on the svg.
Understandably, this is not its intended purpose which means it's not exactly semantic, but it seems like a better route than the svg.
Which route do you think is most appropriate?
To be clear, this is not leveraging fieldset
from the form control, but instead changing the notched outline to use fieldset
internally like this:
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { withStyles } from '../styles';
export const styles = theme => {
const light = theme.palette.type === 'light';
return {
/* Styles applied to the root element. */
root: {
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
left: 0,
margin: 0,
padding: 0,
pointerEvents: 'none',
borderRadius: theme.shape.borderRadius,
borderStyle: 'solid',
borderWidth: '1px',
borderColor: light ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)',
// Match the Input Label
transition: theme.transitions.create(['borderColor', 'border-width'], {
duration: theme.transitions.duration.shorter,
easing: theme.transitions.easing.easeOut,
}),
},
/* Styles applied to the legend element. */
legend: {
marginLeft: 8,
padding: 0,
transition: theme.transitions.create('width', {
duration: theme.transitions.duration.shorter,
easing: theme.transitions.easing.easeOut,
}),
},
/* Styles applied to the root element if the form control is focused. */
focused: {
borderColor: theme.palette.primary.main,
borderWidth: '2px',
},
/* Styles applied to the root element if `error={true}` for the form control. */
error: {
borderColor: theme.palette.error.main,
},
/* Styles applied to the root element if `disabled={true}` for the form control. */
disabled: {
borderColor: theme.palette.action.disabled,
},
};
};
/**
* An outline for form control elements which opens to fit a label.
*/
function NotchedOutline(props, context) {
const {
adornedStart: adornedStartProp,
disabled: disabledProp,
error: errorProp,
children,
classes,
className,
filled: filledProp,
focused: focusedProp,
notched: notchedProp,
notchWidth,
theme,
...other
} = props;
const { muiFormControl } = context;
let adornedStart = adornedStartProp;
let disabled = disabledProp;
let error = errorProp;
let filled = filledProp;
let focused = focusedProp;
if (muiFormControl) {
if (typeof adornedStart === 'undefined') {
adornedStart = muiFormControl.adornedStart;
}
if (typeof disabled === 'undefined') {
disabled = muiFormControl.disabled;
}
if (typeof error === 'undefined') {
error = muiFormControl.error;
}
if (typeof filled === 'undefined') {
filled = muiFormControl.filled;
}
if (typeof focused === 'undefined') {
focused = muiFormControl.focused;
}
}
const notched = notchedProp || focused || filled || adornedStart;
return (
<fieldset
className={classNames(
classes.root,
{
[classes.focused]: focused,
[classes.error]: error,
[classes.disabled]: disabled,
},
className,
)}
{...other}
>
<legend
align={theme.direction === 'rtl' ? 'right' : 'left'}
style={{ width: notched ? notchWidth : 0 }}
className={classes.legend}
/>
</fieldset>
);
}
NotchedOutline.propTypes = {
/**
* The content of the outline.
*/
children: PropTypes.node,
/**
* Override or extend the styles applied to the component.
* See [CSS API](#css-api) below for more details.
*/
classes: PropTypes.object.isRequired,
/** @ignore */
className: PropTypes.string,
/** If `true`, the outline is notched to accommodate text. */
notched: PropTypes.bool,
/** The width of the notch, where a label will be placed. */
notchWidth: PropTypes.number.isRequired,
/**
* Render outline for a select component.
*/
select: PropTypes.bool,
/**
* @ignore
*/
theme: PropTypes.object,
};
NotchedOutline.contextTypes = {
muiFormControl: PropTypes.object,
};
NotchedOutline.muiName = 'NotchedOutline';
export default withStyles(styles, { withTheme: true, name: 'MuiNotchedOutline' })(NotchedOutline);
Which would be consumed as a sibling of the InputComponent
in Input.js
@enagy27 My only fear with the fieldset route is around accessibility & semantic. We need to make sure it's OK.
Gotcha. To address accessibility, my intent is to mark the outline as aria-hidden
. In this implementation the label will remain the same and will just be positioned appropriately within the opening. I believe this should cover any concerns there, but I'm not well versed in accessibility. Will this be sufficient?
On the semantic note I believe the ease of styling and the existence of a native solution outweighs this drawback for me. Is that a deal breaker for you?
@enagy-earnup The discussion here start to be too long for my computer to display it correctly. Can we chat on gitter? Or reset it with a new pull request?
I think that aria-hidden
will be enough. To try, we also need to make sure the output is HTML valid and that it works with the older browsers. Yeah, It's all good to me if we can make the implementation much simpler. How do you think the animation can work?
Just thought I'd say this is looking really good! I'd love to use this in prod material-ui... Any idea of when this could be merged in?
@Michael-M-Judd It will most likely be released mid-September.
@enagy-earnup A couple of small things:
filled: {
cursor: 'text',
borderRadius: '4px 4px 0 0',
backgroundColor: 'rgba(0,0,0,0.045)',
'&:hover': {
backgroundColor: 'rgba(0,0,0,0.07)',
},
transition: theme.transitions.create('background-color', {
duration: theme.transitions.duration.shortest,
}),
},
focusedFilled: {
backgroundColor: 'rgba(0,0,0,0.11)',
transition: theme.transitions.create('background-color', {
duration: theme.transitions.duration.shortest,
}),
},
For the multiline text fileds, it should ideally be possible for the user to focus the input by clicking anywhere in it. At the moment it gets the hover color, but only part (the taxtarea) is clickable as indicated by the cursor style. I had the textarea the full size of the textfiled, with appropriate padding, but that isn't the right solution, as the text overflows into the padding for some reason. (That was that point at which I moved on to outlined!). We might need to have a click on the outer component to programmatically focus the textarea?
For some reason we don't have examples of disabled text fields. I had added those to each of the demos, right after the "error" example - would be great if you could do the same.
@mbrookes Thanks for that!
The spec threw me off a little on the filled variant because active was light, but focused was dark. We are not distinguishing between the focused and active states, so that seems to make the most sense- I'll change that. This also helps with some styling cases for the select
where the input itself does not fill the container and causes odd shading presentation.
Good call, I'll see what I can do about using interactions on the outer div for more of these interactions. I'll also need to move some of the padding back to the outer div for the start and end adornments, so this looks like it'll help in a number of cases.
On the examples- you got it!
@mbrookes
The more I look at these states, the more puzzled I get. When I take a sample of these states, the active typing and inactive states seem to have the same shading ๐ค I've just realized also that I'm missing a lack of underline in the inactive state. I wonder if this is why it looks off.
The more I look at these states, the more puzzled I get.
ISWYM! I hadn't even noticed the "activated" state - to me it's the same as focused.
Looking at MCW, thay seem to have followed the same three-shade approach as ours: https://material-components.github.io/material-components-web-catalog/#/component/text-field
Regarding the underline, I had noticed that before - there are contradictory examples throughout that page, and while the states don't include it, the spec does.
Again, looking at MCW, they include it. That's also the simplest option.
@mbrookes Cool, I've added back the underline and will darken on focus. Absolutely makes the most sense. Also added cursor: text
and forced focused for the root onClick
.
The last challenge I'm having is the placement of the adornments. Ideally the input should fill the entire container, which helps to account for input-specific styling, such as the yellow autocomplete coloring. Unfortunately this means that the input adornments are not positioned properly. Part of the challenge here I guess is that in the spec the label also moves to accommodate the adornments.
In order to position the adornments properly, my options seem a bit limited:
FormControl
context, I could add the variant
or margin
prop to the InputAdornment
. This seems like an unwieldy or unintuitive solution.These all seem like not great options. Wondering if you've got thoughts how we might tackle this?
It looks like the style change that's needed in InputAdornment root
style is to disable display: flex
, and apply margin-top
; but only when the TextField variant is outlined.
Given the choice between conditionally applying a class to the adornments in Input, or checking context in InputAdornment, if feels like the latter would be the least messy.
Thanks for adding the disabled examples. Could you tweak the ordering for the default variant?
Sounds great! There's one minor snag that I'm seeing. Input
is setting the form control context to null
, which means that it is not accessible from this level. This is also a challenge for the outline, but given that it is only used in this context and rendered directly within Input
this was ok, as we could still pass focused
as a prop.
Seeing a few different solutions, and I'm not sure which is most in-line with future work.
startAdornment
and the endAdornment
and inject the variant
propvariant
prop if using the render prop APImuiFormControl
context to null
in Input
In what way do you mean for tweaking the order of the default variant? Are you referring to showing the adornments sections immediately after their corresponding sections?
Input is setting the form control context to null, which means that it is not accessible from this level.
@enagy27 The Input is setting the context to null
for its children to avoid infinite rendering cycles.
I'm not sure which is most in-line with future work
For now, I would say add a variant
property to the InputAdornment
component. It's consistent with asking for a position
property.
Thanks for adding the disabled examples. Could you tweak the ordering for the default variant?
In what way do you mean for tweaking the order of the default variant? Are you referring to showing the adornments sections immediately after their corresponding sections?
I was referring to the disabled examples. The order is different for the default variant โ it comes before the error example. Not a big deal, but might be nice to be consistent.
Oh, my mistake. Fixed!
I've added the variant
prop to the InputAdornment
. Questioning if doing this via cloneElement
will constitute a breaking change and therefore that this should be a prop that's manually applied ๐ค
Questioning if doing this via cloneElement will constitute a breaking change and therefore that this should be a prop that's manually applied ๐ค
@enagy27 I don't think that it really matters now. I think that we can focus on merging the pull request, sort that out after. cloneElement
isn't a breaking change. The issue is more about cloneElement
being an anti-pattern, it's unpredictable from a user point of view. I know we are already using it at a lot of different places, the fewer, the better.
Absolutely. Let me know if there's anything further you need from me ๐
I'm expecting people to open issues regarding the new variants once we release them. It's a major undertaking. Let's hope for the best ๐ค๐.
@enagy27 Thanks for the solid contribution, and for your perseverance given all the back and forth to arrive at the best approach!
@oliviertassinari
I'm expecting people to open issues
The only small issue I can see right now is the height of the select text fields, as mentioned in chat. But as you say, let's see! Nice job on the InputBase.
Closes #11962