Skip to content

Commit

Permalink
feat(VTimePicker): updating to M3 design
Browse files Browse the repository at this point in the history
  • Loading branch information
blalan05 committed Oct 25, 2023
1 parent 97581a2 commit befca67
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 87 deletions.
46 changes: 17 additions & 29 deletions packages/vuetify/src/labs/VTimePicker/VTimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint-disable */

// Components
import { VTimePickerTitle } from './VTimePickerTitle'
import { makeVTimePickerTitleProps, VTimePickerTitle } from './VTimePickerTitle'
import { VTimePickerClock } from './VTimePickerClock'
import { makeVPickerProps, VPicker } from '@/labs/VPicker/VPicker'

Expand Down Expand Up @@ -59,10 +59,9 @@ export const makeVTimePickerProps = propsFactory({
readonly: Boolean,
scrollable: Boolean,
useSeconds: Boolean,
// value: null as any as PropType<any>,
modelValue: null as any as PropType<any>,
ampmInTitle: Boolean,
...makeVPickerProps({ title: ''})
...makeVPickerProps({ title: '' })
}, 'VTimePicker')

export const VTimePicker = genericComponent()({
Expand Down Expand Up @@ -202,18 +201,7 @@ export const VTimePicker = genericComponent()({
return props.format === 'ampm'
})

const titleSlotProps = computed(() => ({
ampm: props.ampm,
ampmReadonly: props.ampmReadonly && !props.ampmInTitle,
disabled: props.disabled,
hour: props.hour,
minute: props.minute,
second: props.second,
period: period.value,
readonly: props.readonly,
useSeconds: props.useSeconds,
selecting: selecting.value,
}))

const titleRef = ref<typeof VTimePickerTitle>(null)
const clockRef = ref<typeof VTimePickerClock>(null)

Expand All @@ -234,10 +222,10 @@ export const VTimePicker = genericComponent()({
const value = genValue()
if (value !== null) emit('update:modelValue', value)
}
const setPeriod = (period: Period) => {
period.value = period
const setPeriod = (val: Period) => {
period.value = val
if (inputHour.value != null) {
const newHour = inputHour.value! + (period === 'am' ? -12 : 12)
const newHour = inputHour.value! + (period.value === 'am' ? -12 : 12)
inputHour.value = firstAllowed('hour', newHour)
emitValue()
}
Expand All @@ -252,7 +240,7 @@ export const VTimePicker = genericComponent()({
inputMinute.value = value.getMinutes()
inputSecond.value = value.getSeconds()
} else {
const [, hour, minute, , second, period] = value.trim().toLowerCase().match(/^(\d+):(\d+)(:(\d+))?([ap]m)?$/) || new Array(6)
const [hour, minute, , second, period] = value.trim().toLowerCase().match(/^(\d+):(\d+)(:(\d+))?([ap]m)?$/) || new Array(6)

inputHour.value = period ? convert12to24(parseInt(hour, 10), period as Period) : parseInt(hour, 10)
inputMinute.value = parseInt(minute, 10)
Expand All @@ -278,7 +266,6 @@ export const VTimePicker = genericComponent()({
emitValue()
}
const onChange = (value: number) => {
console.log(selecting.value, value)
emit(`click:${selectingNames[selecting.value]}`, value)

const emitChange = selecting.value === (props.useSeconds ? SelectingTimes.Second : SelectingTimes.Minute)
Expand Down Expand Up @@ -323,6 +310,7 @@ export const VTimePicker = genericComponent()({

useRender(() => {
const [pickerProps] = VPicker.filterProps(props)
// const [titleSlotProps] = makeVTimeTitleSlotProps.filterProps(props)
return (
<VPicker
class={[ 'v-time-picker', props.class ]}
Expand All @@ -333,24 +321,24 @@ export const VTimePicker = genericComponent()({
title: () => (
<VTimePickerTitle
key="header"
ampm={ isAmPm.value || props.ampmInTitle }
ampmReadonly={ props.ampmReadonly && !props.ampmInTitle }
color={ props.color }
disabled={ props.disabled }
hour={ inputHour.value }
minute={ inputMinute.value }
period={ period.value }
readonly={ props.readonly }
second={ inputSecond.value }
selecting={ selecting.value }
useSeconds={ props.useSeconds}
onUpdate:selecting={ (value: 1 | 2 | 3) => (selecting.value = value) }
onUpdate:period={ (period: string) => setPeriod(period) && emit('update:period', period) }
onUpdate:period={ (val: string) => setPeriod(val) && emit('update:period', val) }
ref={ titleRef }
></VTimePickerTitle>
),
default: () => (
<div class="v-time-picker-clock__container" key={selecting.value}>
{
!props.ampmInTitle && isAmPm.value ? (
<div class="v-time-picker-clock__ampm" style={ `color: ${props.color || 'primary'}`}>
<span>{ t('$vuetify.timePicker.am') }</span>
<span>{ t('$vuetify.timePicker.pm') }</span>
</div>
) : ''
}
<VTimePickerClock
allowedValues={
selecting.value === SelectingTimes.Hour
Expand Down
42 changes: 23 additions & 19 deletions packages/vuetify/src/labs/VTimePicker/VTimePickerClock.sass
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
@import './_variables.scss'

// Theme
.v-time-picker-clock
background: rgb(var(--v-theme-background))

.v-time-picker-clock__item--disabled
color: rgb(var(--v-theme-primary))

&.v-time-picker-clock__item--active
color: rgb(var(--v-theme-primary))


.v-time-picker-clock__hand
background-color: rgb(var(--v-theme-primary))

&:after
color: rgb(var(--v-theme-primary))

.v-time-picker-clock__item--active
background-color: rgb(var(--v-theme-primary))

.v-time-picker-clock
border-radius: 100%
background: rgb(var(--v-theme-on-surface-variant))
border-radius: 50%
position: relative
transition: none
user-select: none
width: 100%
padding-top: 100%
width: 90%
padding-top: 90%
margin-left: 5%
flex: 1 0 auto

&__container
Expand All @@ -18,19 +38,6 @@
justify-content: center
padding: $time-picker-clock-padding

&__ampm
display: flex
flex-direction: row
justify-content: space-between
align-items: flex-end
position: absolute
width: 100%
height: 100%
top: 0
left: 0
margin: 0
padding: $time-picker-ampm-padding

&__hand
height: $time-picker-clock-hand-height
width: $time-picker-clock-hand-width
Expand Down Expand Up @@ -125,6 +132,3 @@
.v-time-picker-clock
&__container
flex-direction: row

&__ampm
flex-direction: column
11 changes: 5 additions & 6 deletions packages/vuetify/src/labs/VTimePicker/VTimePickerClock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const makeVTimePickerClockProps = propsFactory({
format: {
type: Function,
default: (val: string | number) => val,
} as PropValue<(val: string | number) => string | number>,
} as PropType<(val: string | number) => string | number>,
max: {
type: Number,
required: true,
Expand Down Expand Up @@ -155,18 +155,15 @@ export const VTimePickerClock = genericComponent()({
const handAngle = Math.round(angle(center, coords) - props.rotate + 360) % 360
const insideClick = props.double && euclidean(center, coords) < (innerWidth + innerWidth * innerRadiusScale.value) / 4
const checksCount = Math.ceil(15 / degreesPerUnit.value)
console.log(center, coords, angle(center, coords), handAngle, insideClick, checksCount)
let value

for (let i = 0; i < checksCount; i++) {
value = angleToValue(handAngle + i * degreesPerUnit.value, insideClick)
console.log(value, isAllowed(value))
if (isAllowed(value)) return setMouseDownValue(value)

value = angleToValue(handAngle - i * degreesPerUnit.value, insideClick)
if (isAllowed(value)) return setMouseDownValue(value)
}
console.log(value)
}
const angleToValue = (angle: number, insideClick: boolean): number => {
const value = (
Expand Down Expand Up @@ -231,8 +228,10 @@ export const VTimePickerClock = genericComponent()({
>
<div class="v-time-picker-clock__inner" ref={ innerClockRef }>
<div
class={['v-time-picker-clock__hand', {'v-time-picker-clock__hand--inner': isInner(props.modelValue) } ]}
style={ `background: ${(props.modelValue != null) && (props.color || 'accent')}; transform: rotate(${props.rotate + degreesPerUnit.value * (displayedValue.value - props.min)}deg ${`scaleY(${handScale(displayedValue.value)})`})` }
class={['v-time-picker-clock__hand', { 'v-time-picker-clock__hand--inner': isInner(props.modelValue) } ]}
style={{
background: props.modelValue != null ? props.color ? props.color : 'accent' : '',
transform: `rotate(${props.rotate + degreesPerUnit.value * (displayedValue.value - props.min)}deg) scaleY(${handScale(displayedValue.value)})` }}
></div>
{
genChildren.value.map(value => (
Expand Down
56 changes: 35 additions & 21 deletions packages/vuetify/src/labs/VTimePicker/VTimePickerTitle.sass
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@
@import '../VPicker/_variables.scss'

.v-time-picker-title
color: $time-picker-title-color
display: flex
line-height: 1
justify-content: flex-end

.v-time-picker-title__time
white-space: nowrap
direction: ltr

.v-picker__title__btn,
span
align-items: center
display: inline-flex
height: $time-picker-title-btn-height
font-size: $time-picker-title-btn-height
justify-content: center
&__text
padding-bottom: 12px

&__time
display: flex
white-space: nowrap
direction: ltr

&__btn
align-items: center
display: inline-flex
// overridden
height: $time-picker-title-btn-height
font-size: $time-picker-title-btn-height
justify-content: center

&.v-btn.v-btn--density-default
height: initial
&.v-btn.v-btn--size-default
padding: 0 6px

&__active
background: rgb(var(--v-theme-primary))
&--with-seconds__btn
// overridden
height: $time-picker-title-seconds-btn-height
font-size: $time-picker-title-seconds-btn-height

.v-time-picker-title__ampm
align-self: flex-end
Expand All @@ -26,15 +37,18 @@
font-size: $time-picker-ampm-title-font-size
text-transform: uppercase

// LTR
div:only-child
flex-direction: row

&--readonly
.v-picker__title__btn.v-picker__title__btn--active
opacity: $picker-inactive-btn-opacity

&__btn
font-size: $time-picker-ampm-title-font-size
padding: 0 8px
min-width: 48px

&__active
background: rgb(var(--v-theme-primary))

.v-picker__title--landscape
.v-time-picker-title
flex-direction: column
Expand Down
74 changes: 64 additions & 10 deletions packages/vuetify/src/labs/VTimePicker/VTimePickerTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { genericComponent, propsFactory, useRender } from '@/util'
export const makeVTimePickerTitleProps = propsFactory({
ampm: Boolean,
ampmReadonly: Boolean,
color: String,
disabled: Boolean,
hour: Number,
minute: Number,
Expand All @@ -42,6 +43,7 @@ export const VTimePickerTitle = genericComponent()({
props: makeVTimePickerTitleProps(),

emits: [
'update:period',
'update:selecting',
],

Expand All @@ -55,16 +57,54 @@ export const VTimePickerTitle = genericComponent()({
}
return (
<div class="v-time-picker-title">
<div class="v-time-picker-title__time">
<v-btn variant="flat" onClick={ () => emit('update:selecting', SelectingTimes.Hour) }>{ props.hour == null ? '--' : props.ampm ? String(hour) : pad(hour) }</v-btn>
<v-btn disabled={true}>:</v-btn>
<v-btn variant="flat" onClick={ () => emit('update:selecting', SelectingTimes.Minute) }>{ props.minute == null ? '--' : pad(props.minute) }</v-btn>
<div class="v-time-picker-title__text" style="width: 100%">
{ t('$vuetify.timePicker.select') }
</div>
<div
class="v-time-picker-title__time"
class={{ 'v-time-picker-title__time--with-seconds': props.useSeconds }}
>
<v-btn
variant="tonal"
onClick={ () => emit('update:selecting', SelectingTimes.Hour) }
class="v-time-picker-title__time__btn"
class={{
'v-time-picker-title__time__btn__active': props.selecting === 1,
'v-time-picker-title__time--with-seconds__btn': props.useSeconds
}}
>
{ props.hour == null ? '--' : pad(hour) }
</v-btn>
<span class="v-time-picker-title__time__btn">:</span>
<v-btn
variant="tonal"
onClick={ () => emit('update:selecting', SelectingTimes.Minute) }
class="v-time-picker-title__time__btn"
class={{
'v-time-picker-title__time__btn__active': props.selecting === 2,
'v-time-picker-title__time--with-seconds__btn': props.useSeconds
}}
>
{ props.minute == null ? '--' : pad(props.minute) }
</v-btn>
{
props.useSeconds && (
<span class="v-time-picker-title__time__btn">:</span>
)
}
{
props.useSeconds && (
<template>
<span>:</span>
<v-btn variant="flat" onClick={ emit('update:selecting', SelectingTimes.Second) }>{ props.second == null ? '--' : pad(props.second) }</v-btn>
</template>
<v-btn
variant="tonal"
onClick={ () => emit('update:selecting', SelectingTimes.Second) }
class="v-time-picker-title__time__btn"
class={{
'v-time-picker-title__time__btn__active': props.selecting === 3,
'v-time-picker-title__time--with-seconds__btn': props.useSeconds
}}
>
{ props.second == null ? '--' : pad(props.second) }
</v-btn>
)
}
{
Expand All @@ -74,8 +114,22 @@ export const VTimePickerTitle = genericComponent()({
'v-time-picker-title__ampm--readonly': props.ampmReadonly,
}]}
>
{ (!props.ampmReadonly || props.period === 'am') ?<span>{ t('$vuetify.timePicker.am') }</span> : '' }
{ (!props.ampmReadonly || props.period === 'pm') ? <span>{ t('$vuetify.timePicker.pm') }</span> : '' }
<v-btn
variant="tonal"
onClick={ () => emit('update:period', 'am') }
class="v-time-picker-title__ampm__btn"
class={{ 'v-time-picker-title__ampm__btn__active': props.period === 'am' }}
>
{ t('$vuetify.timePicker.am') }
</v-btn>
<v-btn
variant="tonal"
onClick={ () => emit('update:period', 'pm') }
class="v-time-picker-title__ampm__btn"
class={{ 'v-time-picker-title__ampm__btn__active': props.period === 'pm' }}
>
{ t('$vuetify.timePicker.pm') }
</v-btn>
</div>
)
}
Expand Down
Loading

0 comments on commit befca67

Please sign in to comment.