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

✨ RSP-631 InputGroup: add Datepicker range variant #53

Merged
merged 9 commits into from
Mar 18, 2019
59 changes: 59 additions & 0 deletions docs/inputgroup/datepicker-range-quiet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Date Picker - Range Quiet
description: A date picker uses the input group component to display a field with a button next to it
markup: |
<div class="spectrum-InputGroup spectrum-InputGroup--quiet spectrum-Datepicker spectrum-Datepicker--range" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="start" value="2018-10-01">
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="end" value="2018-10-30">
<button type="button" class="spectrum-FieldButton spectrum-FieldButton--quiet" tabindex="-1" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
</div>

<p />

<div aria-invalid="true" class="spectrum-InputGroup spectrum-InputGroup--quiet spectrum-Datepicker spectrum-Datepicker--range is-invalid" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" aria-invalid="true" placeholder="mm/dd/yyyy" name="start" value="2018-10-01">
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field is-invalid" aria-invalid="true" placeholder="mm/dd/yyyy" name="end" value="2018-10-30">
<button type="button" class="spectrum-FieldButton spectrum-FieldButton--quiet is-invalid" tabindex="-1" aria-expanded="false" aria-haspopup="dialog" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
</div>

<p />

<div aria-disabled="true" class="spectrum-InputGroup spectrum-InputGroup--quiet spectrum-Datepicker spectrum-Datepicker--range is-disabled" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="start" value="2018-10-01" disabled>
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="end" value="2018-10-30" disabled>
<button type="button" class="spectrum-FieldButton spectrum-FieldButton--quiet" tabindex="-1" disabled aria-expanded="false" aria-haspopup="dialog" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
</div>
<p/>

<div class="spectrum-InputGroup spectrum-InputGroup--quiet spectrum-Datepicker spectrum-Datepicker--range spectrum-Datepicker--datetimeRange" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" aria-invalid="false" placeholder="mm/dd/yyyy hh:mm a" name="start" value="">
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-Textfield--quiet spectrum-InputGroup-field" aria-invalid="false" placeholder="mm/dd/yyyy hh:mm a" name="end" value="">
<button type="button" class="spectrum-FieldButton spectrum-FieldButton--quiet" tabindex="-1" aria-expanded="false" aria-haspopup="dialog" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
</div>
60 changes: 60 additions & 0 deletions docs/inputgroup/datepicker-range.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Date Picker - Range
description: A date picker uses the input group component to display a field with a button next to it
markup: |
<div aria-invalid="false" class="spectrum-InputGroup spectrum-Datepicker spectrum-Datepicker--range" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="start" value="">
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="end" value="">
<button type="button" class="spectrum-FieldButton" tabindex="-1" aria-expanded="false" aria-haspopup="dialog" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
</div>

<p/>

<div aria-invalid="true" class="spectrum-InputGroup spectrum-Datepicker spectrum-Datepicker--range is-invalid" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" aria-invalid="true" placeholder="mm/dd/yyyy" name="start" value="">
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field is-invalid" aria-invalid="true" placeholder="mm/dd/yyyy" name="end" value="">
<button type="button" class="spectrum-FieldButton is-invalid" tabindex="-1" aria-expanded="false" aria-haspopup="dialog" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
Copy link
Member

Choose a reason for hiding this comment

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

Mmmm, this can't be done with :before/:after? I don't see anything using those pseudo-elements right now.

Copy link
Member

Choose a reason for hiding this comment

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

@majornista oh, I see -- it's being selected with the sibling selector, so we can't use pseudo-elements. Perhaps, instead, we should be programmatically applying .is-focused to the outer .spectrum-Datepicker and using :focus-within (for futureproofing)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only with additional javascript to check for .focus-ring className on a descendant element. And, we'd probably need an extra .focus-ring state, to distinguish between mouse a keyboard focus. With the added element, the style can be applied with pure CSS.

Copy link
Member

Choose a reason for hiding this comment

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

Got it, so we would need to know "is a child element keyboard focused?" in JavaScript, and a separate class for keyboard vs mouse focus. @GarthDB thoughts on this? This is the first component that has anything like this.

Copy link
Member

Choose a reason for hiding this comment

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

I prefer pure CSS for accessibility things like keyboard focus. It would be preferable to implement it with the same strategy as all the others, but I'm not seeing an obvious way to do that.
We could add something to the focus-ring polyfill, but that would kind of defeat the point of a standards-based polyfill.
The focus-withing strategy would be nice, it just means we're adding another polyfill requirement to focus. What would you prefer @lazd?

Copy link
Member

Choose a reason for hiding this comment

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

Though I would prefer the polyfill, I don't want to hold up this PR. I agree with your sentiments and suppose I'm fine with the current approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it, so we would need to know "is a child element keyboard focused?" in JavaScript, and a separate class for keyboard vs mouse focus. @GarthDB thoughts on this? This is the first component that has anything like this.

The Rating component has a similar issue with how the focus outline is applied to the wrapper element. Devon was somewhat resistant to the approach of evaluating for descendant input with .focus-ring. The difference for the Datepicker is that text inputs show blue border for mouse focus and border with box-shadow for keyboard focus.

</div>

<p/>

<div aria-disabled="true" class="spectrum-InputGroup spectrum-Datepicker spectrum-Datepicker--range is-disabled" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="start" value="" disabled>
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" placeholder="mm/dd/yyyy" name="end" value="" disabled>
<button type="button" class="spectrum-FieldButton" disabled tabindex="-1" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
</div>

<p/>

<div class="spectrum-InputGroup spectrum-Datepicker spectrum-Datepicker--range spectrum-Datepicker--datetimeRange" role="combobox" aria-expanded="false" aria-haspopup="dialog">
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" placeholder="mm/dd/yyyy hh:mm a" name="start" value="">
<div class="spectrum-Datepicker--rangeDash"></div>
<input type="text" class="spectrum-Textfield spectrum-InputGroup-field" placeholder="mm/dd/yyyy hh:mm a" name="end" value="">
<button type="button" class="spectrum-FieldButton" tabindex="-1" aria-expanded="false" aria-haspopup="dialog" aria-label="Calendar">
<svg class="spectrum-Icon spectrum-UIIcon-ChevronDownMedium spectrum-Dropdown-icon" focusable="false" aria-hidden="true">
<use xlink:href="#spectrum-css-icon-ChevronDownMedium" />
</svg>
</button>
<!-- To render focus ring around entire input group when one of the inputs has keyboard focus, we need this: -->
<div class="spectrum-Datepicker-focusRing" role="presentation"></div>
majornista marked this conversation as resolved.
Show resolved Hide resolved
</div>
94 changes: 94 additions & 0 deletions src/inputgroup/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@
/* topdoc
{{ inputgroup/datepicker-quiet.yml }}
*/
/* topdoc
{{ inputgroup/datepicker-range.yml }}
*/
/* topdoc
{{ inputgroup/datepicker-range-quiet.yml }}
*/

:root {
/* Todo: move to DNA */
--spectrum-combobox-quiet-fieldbutton-border-radius: 0;
--spectrum-combobox-field-border-width-right: 0;
--spectrum-combobox-quiet-fieldbutton-padding-right: 0;
--spectrum-datepicker-input-width: calc(var(--spectrum-global-dimension-size-1600) - 2 * var(--spectrum-padding));
--spectrum-datepicker-datetime-input-width: calc(var(--spectrum-datepicker-input-width) + var(--spectrum-global-dimension-size-700) - var(--spectrum-global-dimension-static-font-size-100) / 2);
--spectrum-datepicker-range-dash-margin-left: calc(-0.5 * var(--spectrum-global-dimension-static-font-size-100));
--spectrum-datepicker-range-dash-padding-top: 0;
--spectrum-datepicker-range-dash-line-height: calc(var(--spectrum-textfield-height) - var(--spectrum-global-dimension-size-100));
}

.spectrum-InputGroup {
Expand All @@ -26,6 +37,7 @@
flex-direction: row;
flex-wrap: nowrap;
min-width: var(--spectrum-component-single-line-width);
border-radius: var(--spectrum-border-radius);

.spectrum-FieldButton {
padding: 0 var(--spectrum-dropdown-padding-x);
Expand All @@ -42,6 +54,7 @@
}

.spectrum-InputGroup--quiet {
border-radius: var(--spectrum-combobox-quiet-fieldbutton-border-radius);
.spectrum-FieldButton {
border-radius: var(--spectrum-combobox-quiet-fieldbutton-border-radius);

Expand All @@ -63,3 +76,84 @@
right: 0;
}
}

.spectrum-Datepicker--range {
border-radius: var(--spectrum-border-radius);
/* Input Group */
&.spectrum-InputGroup--quiet {
border-radius: var(--spectrum-combobox-quiet-fieldbutton-border-radius);
.spectrum-FieldButton {
border-radius: var(--spectrum-combobox-quiet-fieldbutton-border-radius);
}
}
/** Datetime Range **/
&.spectrum-Datepicker--datetimeRange {
/* Inputs */
.spectrum-InputGroup-field {
width: var(--spectrum-datepicker-datetime-input-width);
min-width: var(--spectrum-datepicker-datetime-input-width);
}
}
/* Inputs */
.spectrum-InputGroup-field {
width: var(--spectrum-datepicker-input-width);
min-width: var(--spectrum-datepicker-input-width);
flex: initial;
&:nth-of-type(1) {
border-right: 0;
padding-right: var(--spectrum-padding);
&.is-invalid,
&:invalid {
background-image: none;
padding-right: var(--spectrum-padding);
}
}
&:nth-of-type(2) {
Copy link
Member

Choose a reason for hiding this comment

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

@GarthDB how does this make you feel? Do you think we should have selectors for these two bad boys instead of doing nth-of-type?

Copy link
Member

Choose a reason for hiding this comment

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

It has full browser support, so I don't really have any issue with it. https://caniuse.com/#feat=css-sel3

Copy link
Member

Choose a reason for hiding this comment

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

The only other reason we might be concerned is performance and/or code readability/maintainability, but I think it's fine on both of those.

Copy link
Member

Choose a reason for hiding this comment

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

I think the specificity is pretty high here. I'm not 100% against it, but it feels like we could throw a class on the inputs and simplify the CSS... The real question is: do we want markup simplicity (the PR, as-is), or CSS simplicity (throw an extra class on the fields)?

Copy link
Member

Choose a reason for hiding this comment

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

@majornista We talked a bit with @devongovett and think these selectors should be classes added to the markup.

Copy link
Contributor Author

@majornista majornista Mar 15, 2019

Choose a reason for hiding this comment

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

@lazd Would spectrum-Datepicker-field--start and spectrum-Datepicker-field--end work?

border-left: 0;
border-radius: 0;
padding-left: var(--spectrum-padding);
}
}
/* Em dash */
.spectrum-Datepicker--rangeDash {
line-height: var(--spectrum-datepicker-range-dash-line-height);
padding-top: var(--spectrum-datepicker-range-dash-padding-top);
flex: initial;
width: 0;
z-index: 1;
&:before {
content: '—';
display: inline-block;
margin: 0 var(--spectrum-datepicker-range-dash-margin-left);
overflow: hidden;
text-align: center;
vertical-align: middle;
width: var(--spectrum-global-dimension-static-font-size-100);
}
}
/* Focus ring */
&.is-focused {
.spectrum-Datepicker-focusRing {
position: absolute;
border-radius: var(--spectrum-border-radius);
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
}
}
&.spectrum-InputGroup--quiet {
&.is-focused {
.spectrum-Datepicker-focusRing {
border-radius: var(--spectrum-combobox-quiet-fieldbutton-border-radius);
top: auto;
}
}
.spectrum-Datepicker--rangeDash {
&:before {
margin-left: var(--spectrum-datepicker-range-dash-margin-left);
}
}
}
}
106 changes: 99 additions & 7 deletions src/inputgroup/skin.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
.spectrum-InputGroup {
&.is-focused {
&:not(.is-invalid) {
.spectrum-InputGroup-field:not(:disabled):not(.is-invalid) {
border-color: var(--spectrum-textfield-border-color-key-focus);
~ .spectrum-FieldButton {
border-color: var(--spectrum-textfield-border-color-key-focus);
}
}
}
}
&:hover {
.spectrum-InputGroup-field:not(:disabled):not(.is-invalid):not(:focus) {
&,
& ~ .spectrum-FieldButton {
&:not(.is-invalid):not(.is-focused) {
.spectrum-InputGroup-field:not(:disabled):not(.is-invalid) {
border-color: var(--spectrum-textfield-border-color-hover);
~ .spectrum-FieldButton {
border-color: var(--spectrum-textfield-border-color-hover);
}
&:focus {
border-color: var(--spectrum-textfield-border-color-key-focus);
~ .spectrum-FieldButton {
border-color: var(--spectrum-textfield-border-color-key-focus);
}
}
}
}
}
Expand Down Expand Up @@ -51,10 +69,9 @@
}
}

&:hover {
&:hover:not(.is-invalid) {
.spectrum-InputGroup-field:not(:disabled):not(.is-invalid):not(:focus) {
&,
& ~ .spectrum-FieldButton {
~ .spectrum-FieldButton {
border-color: var(--spectrum-textfield-quiet-border-color-hover);
}
}
Expand All @@ -63,7 +80,6 @@
.spectrum-InputGroup-field {
&.is-invalid,
&:invalid {
&,
~ .spectrum-FieldButton {
border-color: var(--spectrum-textfield-border-color-error);
}
Expand All @@ -86,3 +102,79 @@
}
}
}

.spectrum-Datepicker--range {
.spectrum-InputGroup-field {
&:focus-ring {
box-shadow: none !important;
}
&[disabled] {
~ .spectrum-Datepicker--rangeDash {
color: var(--spectrum-textfield-text-color-disabled);
}
}
}

/* Focus ring: When one of the inputs or the button has keyboard focus, render the focus ring border around the entire input group by styling an adjacent descendant element. */
:focus-ring {
majornista marked this conversation as resolved.
Show resolved Hide resolved
~ .spectrum-Datepicker-focusRing {
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-key-focus);
}
&:invalid,
&.is-invalid {
~ .spectrum-FieldButton {
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-error);
}
~ .spectrum-Datepicker-focusRing {
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-error);
}
}
}

&.is-invalid {
.spectrum-InputGroup-field {
border-color: var(--spectrum-dropdown-border-color-error) !important;
}

/* Focus ring: When one of the inputs or the button has keyboard focus, render the focus ring border around the entire input group by styling an adjacent descendant element. */
:focus-ring {
majornista marked this conversation as resolved.
Show resolved Hide resolved
~ .spectrum-Datepicker-focusRing {
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-error);
}
~ .spectrum-FieldButton {
border-color: var(--spectrum-dropdown-border-color-error);
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-error);
}
}
.spectrum-FieldButton {
border-color: var(--spectrum-dropdown-border-color-error);
&.is-invalid {
&:focus-ring {
border-color: var(--spectrum-dropdown-border-color-error);
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-error);
}
}
}
}
&.spectrum-InputGroup--quiet {
&.is-focused {
.spectrum-Datepicker-focusRing {
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-key-focus);
}
&.is-invalid {
.spectrum-FieldButton {
box-shadow: none;
border-color: var(--spectrum-dropdown-border-color-error);
&.is-invalid {
&:focus-ring {
box-shadow: 0 2px 0 0 var(--spectrum-dropdown-border-color-error);
}
}
}
.spectrum-Datepicker-focusRing {
box-shadow: 0 0 0 1px var(--spectrum-dropdown-border-color-error);
}
}
}
}
}
Loading