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
fix(slider): added filled offset variant #3876
Changes from 14 commits
3e2bc1e
c067b70
fafa81c
0023dec
2e74cbb
cc80656
81f3637
752e8ef
f7b922d
0558aad
b8192f0
7a4521d
4efe2e3
5a2992d
524493d
e3176f2
09583f8
e279f8a
986bd3c
d73578e
3b32275
d203804
20cff87
35b1816
9af3468
095fd7d
c9b4801
1b802da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ import { | |
CSSResultArray, | ||
html, | ||
nothing, | ||
PropertyValues, | ||
SizedMixin, | ||
TemplateResult, | ||
} from '@spectrum-web-components/base'; | ||
|
@@ -91,6 +92,9 @@ export class Slider extends SizedMixin(ObserveSlotText(SliderHandle, ''), { | |
@property() | ||
public type = ''; | ||
|
||
@property({ reflect: true }) | ||
public override dir!: 'ltr' | 'rtl'; | ||
|
||
@property({ type: String }) | ||
public set variant(variant: string) { | ||
const oldVariant = this.variant; | ||
|
@@ -160,6 +164,11 @@ export class Slider extends SizedMixin(ObserveSlotText(SliderHandle, ''), { | |
@property({ type: Boolean, reflect: true }) | ||
public override disabled = false; | ||
|
||
@property({ type: Boolean, reflect: true, attribute: 'fill-start' }) | ||
public fillStart = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this is supposed to be a boolean. I think it is supposed to represent where the fill starts from. By default it would equal the same as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, maybe be unneeded work, but should we also surface a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should min the start value or the initial value represented as 'value' ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I may be misunderstand, so let's check with the design team, but I understand the workflow to be:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure I was wondering if fill-start="5" and value="6" then how will the slider behave? which takes precendence? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it would look like this where the
When There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
User moves handle to 20
User moves handle to 0
User moves to 0, fill size is 1/4 of the track starting at the beginning of the track.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Attached video recording for preview and review. Let me know how this solution looks now. |
||
|
||
@property({ type: Number }) | ||
public fillStartPoint: number | undefined; | ||
/** | ||
* Applies `quiet` to the underlying `sp-number-field` when `editable === true`. | ||
*/ | ||
|
@@ -348,6 +357,60 @@ export class Slider extends SizedMixin(ObserveSlotText(SliderHandle, ''), { | |
`; | ||
} | ||
|
||
private _cachedValue: number | undefined; | ||
|
||
/** | ||
* @description calculates the fill width | ||
* @param fillStartValue | ||
* @param currentValue | ||
* @param cachedValue | ||
* @returns | ||
*/ | ||
private getOffsetWidth( | ||
fillStartValue: number, | ||
currentValue: number, | ||
cachedValue: number | ||
): number { | ||
const distance = | ||
fillStartValue === cachedValue | ||
? Math.abs(currentValue - fillStartValue) | ||
: Math.abs( | ||
Math.min(currentValue, cachedValue) - fillStartValue | ||
); | ||
|
||
return (distance / (this.max - this.min)) * 100; | ||
} | ||
|
||
private getOffsetPosition(v: number): number { | ||
const val = ((v - this.min) / (this.max - this.min)) * 100; | ||
return val; | ||
} | ||
|
||
private renderFillOffset(): TemplateResult { | ||
if (!this.fillStart || !this.fillStartPoint || !this._cachedValue) { | ||
return html``; | ||
} | ||
return html` | ||
<div | ||
class=${`fill ${ | ||
!!(this.value > this.fillStartPoint) ? 'offset' : '' | ||
}`} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using |
||
style=${styleMap({ | ||
[this.dir === 'rtl' ? 'right' : 'left']: `${ | ||
this.value > this.fillStartPoint | ||
? this.getOffsetPosition(this.fillStartPoint) | ||
: this.getOffsetPosition(this.value) | ||
}%`, | ||
width: `${this.getOffsetWidth( | ||
this.fillStartPoint, | ||
this.value, | ||
this._cachedValue | ||
)}%`, | ||
})} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With a complex map like this, we may want to create it as a variable outside of the template, so that it is easier to read. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has been updated to make it more modular |
||
></div> | ||
`; | ||
} | ||
|
||
private renderTrack(): TemplateResult { | ||
const segments = this.handleController.trackSegments(); | ||
const handleItems = [ | ||
|
@@ -360,6 +423,7 @@ export class Slider extends SizedMixin(ObserveSlotText(SliderHandle, ''), { | |
id: `track${index + 1}`, | ||
html: this.renderTrackSegment(start, end), | ||
})), | ||
{ id: 'fill', html: this.renderFillOffset() }, | ||
]; | ||
|
||
return html` | ||
|
@@ -438,8 +502,12 @@ export class Slider extends SizedMixin(ObserveSlotText(SliderHandle, ''), { | |
const size = end - start; | ||
const styles: StyleInfo = { | ||
width: `${size * 100}%`, | ||
'--spectrum-slider-track-background-size': `${(1 / size) * 100}%`, | ||
'--spectrum-slider-track-segment-position': `${start * 100}%`, | ||
...(this.handleController.size > 1 && { | ||
'--spectrum-slider-track-background-size': `${ | ||
(1 / size) * 100 | ||
}%`, | ||
'--spectrum-slider-track-segment-position': `${start * 100}%`, | ||
}), | ||
Rajdeepc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
return styles; | ||
} | ||
|
@@ -455,4 +523,18 @@ export class Slider extends SizedMixin(ObserveSlotText(SliderHandle, ''), { | |
await this.handleController.handleUpdatesComplete(); | ||
return complete; | ||
} | ||
|
||
protected override updated(changes: PropertyValues<this>): void { | ||
super.updated(changes); | ||
if (changes.has('value') && changes.has('fillStart')) { | ||
this._cachedValue = Number(this.value); | ||
if (typeof this.fillStart === 'number') { | ||
this.fillStartPoint = this.fillStart; | ||
} else { | ||
this.fillStartPoint = | ||
(Number(this.max) - Number(this.min)) / 2 + | ||
Number(this.min); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this just be a getter instead? That would allow us to not place There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now using the
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,6 +132,69 @@ export const Default = (args: StoryArgs = {}): TemplateResult => { | |
`; | ||
}; | ||
|
||
export const Filled = (args: StoryArgs = {}): TemplateResult => { | ||
return html` | ||
<div style="width: 500px; margin-inline: 20px;"> | ||
<sp-slider | ||
max="1" | ||
variant="filled" | ||
min="0" | ||
value=".5" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, can we use a value other than the middle of the range so that this story shows the fill by default in VRT so that we can test that the output stays the same over time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sorry, I put this comment on the wrong story. 😞 I meant for https://bug-slider-filled--spectrum-web-components.netlify.app/storybook/?path=/story/slider--fill-start for all the same reasons. I swear this is the last thing! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
step="0.01" | ||
@input=${handleEvent(args)} | ||
@change=${handleEvent(args)} | ||
.formatOptions=${{ style: 'percent' }} | ||
...=${spreadProps(args)} | ||
> | ||
Slider Label | ||
</sp-slider> | ||
</div> | ||
`; | ||
}; | ||
|
||
export const withOnlyFillStart = (args: StoryArgs = {}): TemplateResult => { | ||
return html` | ||
<div style="width: 500px; margin-inline: 20px;"> | ||
<sp-slider | ||
max="1" | ||
fill-start | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we still want There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we cannot use variant="fiiled" when using this property
If fill-start has value then the track will be filled even if it is not starting from 0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That means we're opening a fail state in the API There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing this use case. This should be handled now |
||
min="0" | ||
value=".5" | ||
step="0.01" | ||
@input=${handleEvent(args)} | ||
@change=${handleEvent(args)} | ||
.formatOptions=${{ style: 'percent' }} | ||
...=${spreadProps(args)} | ||
> | ||
Slider label | ||
</sp-slider> | ||
</div> | ||
`; | ||
}; | ||
|
||
export const withFillStartValue = (args: StoryArgs = {}): TemplateResult => { | ||
return html` | ||
<div style="width: 500px; margin-inline: 20px;"> | ||
<sp-slider | ||
max="1" | ||
min="0" | ||
value=".7" | ||
step="0.1" | ||
@input=${handleEvent(args)} | ||
@change=${handleEvent(args)} | ||
.formatOptions=${{ style: 'percent' }} | ||
...=${spreadProps(args)} | ||
> | ||
Slider label | ||
</sp-slider> | ||
</div> | ||
`; | ||
}; | ||
|
||
withFillStartValue.args = { | ||
fillStart: 0.3, | ||
}; | ||
|
||
export const autofocus = (args: StoryArgs = {}): TemplateResult => { | ||
return html` | ||
<div style="width: 500px; margin-inline: 20px;"> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not apply this with the
fill-start
attribute?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjusted the logic to add fill-start as an empty attribute as well as with a value