Skip to content

Commit

Permalink
inital working
Browse files Browse the repository at this point in the history
  • Loading branch information
blalan05 committed Oct 24, 2023
1 parent f454fba commit 97581a2
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 60 deletions.
1 change: 0 additions & 1 deletion packages/vuetify/dev/vuetify.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export default createVuetify({
},
directives,
ssr: !!process.env.VITE_SSR,
date,
defaults,
icons,
locale,
Expand Down
56 changes: 34 additions & 22 deletions packages/vuetify/src/labs/VTimePicker/VTimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import pad from '../VDatePicker/util/pad'
// Types
// import { VNode, PropType } from 'vue'
import { SelectingTimes } from './SelectingTimes'
interface options extends Vue {
$refs: {
clockRef: HTMLElement
titleRef: HTMLElement
}
}

// Utilities
import { computed, onMounted, ref, shallowRef, watch } from 'vue'
Expand Down Expand Up @@ -53,7 +59,8 @@ export const makeVTimePickerProps = propsFactory({
readonly: Boolean,
scrollable: Boolean,
useSeconds: Boolean,
value: null as any as PropType<any>,
// value: null as any as PropType<any>,
modelValue: null as any as PropType<any>,
ampmInTitle: Boolean,
...makeVPickerProps({ title: ''})
}, 'VTimePicker')
Expand All @@ -65,10 +72,11 @@ export const VTimePicker = genericComponent()({

emits: [
'input',
'click:hours',
'click:minutes',
'click:seconds',
'click:hour',
'click:minute',
'click:second',
'update:period',
'update:modelValue',
'change'
],

Expand All @@ -91,23 +99,23 @@ export const VTimePicker = genericComponent()({
return selecting.value === SelectingTimes.Hour
},
set (v: boolean) {
this.selecting = SelectingTimes.Hour
selecting.value = SelectingTimes.Hour
},
})
const selectingMinute = computed({
get (): boolean {
return this.selecting === SelectingTimes.Minute
return selecting.value === SelectingTimes.Minute
},
set (v: boolean) {
this.selecting = SelectingTimes.Minute
selecting.value = SelectingTimes.Minute
},
})
const selectingSecond = computed({
get (): boolean {
return this.selecting === SelectingTimes.Second
return selecting.value === SelectingTimes.Second
},
set (v: boolean) {
this.selecting = SelectingTimes.Second
selecting.value = SelectingTimes.Second
},
})
const isAllowedHourCb = computed((): AllowFunction => {
Expand All @@ -133,7 +141,7 @@ export const VTimePicker = genericComponent()({
const isAllowedMinuteCb = computed((): AllowFunction => {
let cb: AllowFunction

const isHourAllowed = !isAllowedHourCb.value || inputHour.value === null || isAllowedHourCb.value(this.inputHour)
const isHourAllowed = !isAllowedHourCb.value || inputHour.value === null || isAllowedHourCb.value(inputHour.value)
if (props.allowedMinutes instanceof Array) {
cb = (val: number) => (props.allowedMinutes as number[]).includes(val)
} else {
Expand Down Expand Up @@ -206,12 +214,13 @@ export const VTimePicker = genericComponent()({
useSeconds: props.useSeconds,
selecting: selecting.value,
}))
const titleRef = ref<typeof VTimePickerTitle>(null)
const clockRef = ref<typeof VTimePickerClock>(null)

watch(props.value, val => setInputData(val))
watch(props.modelValue, val => setInputData(val))

onMounted(() => {
setInputData(props.value)
// this.$on('update:period', this.setPeriod)
setInputData(props.modelValue)
})

const genValue = () => {
Expand All @@ -223,7 +232,7 @@ export const VTimePicker = genericComponent()({
}
const emitValue = () => {
const value = genValue()
if (value !== null) emit('input', value)
if (value !== null) emit('update:modelValue', value)
}
const setPeriod = (period: Period) => {
period.value = period
Expand All @@ -245,7 +254,7 @@ export const VTimePicker = genericComponent()({
} else {
const [, hour, minute, , second, period] = value.trim().toLowerCase().match(/^(\d+):(\d+)(:(\d+))?([ap]m)?$/) || new Array(6)

inputHour.value = period ? this.convert12to24(parseInt(hour, 10), period as Period) : parseInt(hour, 10)
inputHour.value = period ? convert12to24(parseInt(hour, 10), period as Period) : parseInt(hour, 10)
inputMinute.value = parseInt(minute, 10)
inputSecond.value = parseInt(second || 0, 10)
}
Expand All @@ -269,6 +278,7 @@ 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 @@ -315,7 +325,6 @@ export const VTimePicker = genericComponent()({
const [pickerProps] = VPicker.filterProps(props)
return (
<VPicker
{ ...pickerProps }
class={[ 'v-time-picker', props.class ]}
style={ props.style }
title={ title.value }
Expand All @@ -324,10 +333,12 @@ export const VTimePicker = genericComponent()({
title: () => (
<VTimePickerTitle
key="header"
{ ...titleSlotProps.value }
hour={ inputHour.value }
minute={ inputMinute.value }
second={ inputSecond.value }
onUpdate:selecting={ (value: 1 | 2 | 3) => (selecting.value = value) }
onUpdate:period={ (period: string) => emit('update:period', period) }
ref="title"
onUpdate:period={ (period: string) => setPeriod(period) && emit('update:period', period) }
ref={ titleRef }
></VTimePickerTitle>
),
default: () => (
Expand Down Expand Up @@ -362,14 +373,15 @@ export const VTimePicker = genericComponent()({
scrollable={ props.scrollable }
size={20}
step={ selecting.value === SelectingTimes.Hour ? 1 : 5 }
value={ selecting.value === SelectingTimes.Hour
modelValue={ selecting.value === SelectingTimes.Hour
? inputHour.value
: (selecting.value === SelectingTimes.Minute
? inputMinute.value
: inputSecond.value) }
onInput={ onInput }
OnChange={ onChange }
ref="clock"
onUpdate:modelValue={ onInput }
onChange={ onChange }
ref={ clockRef }
></VTimePickerClock>
</div>
)
Expand Down
59 changes: 30 additions & 29 deletions packages/vuetify/src/labs/VTimePicker/VTimePickerClock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ interface Point {

interface options extends Vue {
$refs: {
clock: HTMLElement
innerClock: HTMLElement
clockRef: HTMLElement
innerClockRef: HTMLElement
}
}

Expand All @@ -38,7 +38,7 @@ export const makeVTimePickerClockProps = propsFactory({
format: {
type: Function,
default: (val: string | number) => val,
} as PropValidator<(val: string | number) => string | number>,
} as PropValue<(val: string | number) => string | number>,
max: {
type: Number,
required: true,
Expand All @@ -57,7 +57,7 @@ export const makeVTimePickerClockProps = propsFactory({
type: Number,
default: 1,
},
value: Number,
modelValue: Number,

...makeDateProps(),
}, 'VTimePickerClock')
Expand All @@ -76,21 +76,20 @@ export const VTimePickerClock = genericComponent()({
],

setup (props, { emit, slots }) {
const clock = ref(null)
const innerClock = ref(null)
const inputValue = ref(props.value)
const clockRef = ref(null)
const innerClockRef = ref(null)
const inputValue = ref(props.modelValue)
const isDragging = ref(false)
const valueOnMouseDown = ref(null as number | null)
const valueOnMouseUp = ref(null as number | null)

const count = computed(() => props.max - props.min + 1)
const degreesPerUnit = computed(() => 360 / roundCount.value)
const degrees = computed(() => degreesPerUnit.value * Math.PI / 180)
const displayedValue = computed(() => props.value == null ? props.min : props.value)
const displayedValue = computed(() => props.modelValue == null ? props.min : props.modelValue)
const innerRadiusScale = computed(() => 0.62)
const roundCount = computed(() => props.double ? (count.value / 2) : count.value)


const wheel = (e: WheelEvent) => {
e.preventDefault()

Expand All @@ -101,8 +100,8 @@ export const VTimePickerClock = genericComponent()({
value = (value - props.min + count.value) % count.value + props.min
} while (!isAllowed(value) && value !== displayedValue.value)

if (value !== this.displayedValue) {
this.update(value)
if (value !== props.displayedValue) {
update(value)
}
}
const isInner = (value: number) => {
Expand Down Expand Up @@ -147,25 +146,27 @@ export const VTimePickerClock = genericComponent()({
}
const onDragMove = (e: MouseEvent | TouchEvent) => {
e.preventDefault()
if ((!isDragging.value && e.type !== 'click') || !clock.value) return

const { width, top, left } = clock.value.getBoundingClientRect()
const { width: innerWidth } = innerClock.value.getBoundingClientRect()
if ((!isDragging.value && e.type !== 'click') || !clockRef.value) return
const { width, top, left } = clockRef.value.getBoundingClientRect()
const { width: innerWidth } = innerClockRef.value.getBoundingClientRect()
const { clientX, clientY } = 'touches' in e ? e.touches[0] : e
const center = { x: width / 2, y: -width / 2 }
const coords = { x: clientX - left, y: top - clientY }
const handAngle = Math.round(angle(center, coords) - this.rotate + 360) % 360
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 @@ -211,27 +212,27 @@ export const VTimePickerClock = genericComponent()({
return children
})

watch(props.value, val => {
watch(props.modelValue, val => {
inputValue.value = val
})

useRender(() => {
return (
<div class={['v-time-picker-clock', { 'v-time-picker-clock--indeterminate': props.value == null } ]}
onMousedown={ onMouseDown }
onMouseup={ onMouseUp }
<div class={['v-time-picker-clock', { 'v-time-picker-clock--indeterminate': props.modelValue == null } ]}
onMousedown={ (e: MouseEvent) => onMouseDown(e) }
onMouseup={ (e: MouseEvent) => onMouseUp(e) }
onMouseleave={ (e: MouseEvent) => (isDragging && onMouseUp(e)) }
onTouchstart={ onMouseDown }
onTouchend={ onMouseUp }
onMousemove={ onDragMove }
onTouchmove={ onDragMove }
onTouchstart={ (e: MouseEvent) => onMouseDown(e) }
onTouchend={ (e: MouseEvent) => onMouseUp(e) }
onMousemove={ (e: DragEvent) => onDragMove(e) }
onTouchmove={ (e: DragEvent) => onDragMove(e) }
onWheel={ (e: WheelEvent) => (props.scrollable && wheel(e)) }
ref="clock"
ref={ clockRef }
>
<div class="v-time-picker-clock__inner" ref="innerClock">
<div class="v-time-picker-clock__inner" ref={ innerClockRef }>
<div
class={['v-time-picker-clock__hand', {'v-time-picker-clock__hand--inner': isInner(props.value) } ]}
style={ `background: ${(props.value != 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 || 'accent')}; transform: rotate(${props.rotate + degreesPerUnit.value * (displayedValue.value - props.min)}deg ${`scaleY(${handScale(displayedValue.value)})`})` }
></div>
{
genChildren.value.map(value => (
Expand All @@ -242,7 +243,7 @@ export const VTimePickerClock = genericComponent()({
'v-time-picker-clock__item--disabled': props.disabled || !isAllowed(value)
}
]}
style={ { ...getTransform(value), color: value === props.value && (props.color || 'accent')} }
style={ { ...getTransform(value), color: value === props.modelValue && (props.color || 'accent')} }
><span>{ props.format(value) }</span></div>
))
}
Expand Down
20 changes: 12 additions & 8 deletions packages/vuetify/src/labs/VTimePicker/VTimePickerTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ export const VTimePickerTitle = genericComponent()({

props: makeVTimePickerTitleProps(),

setup (props, { slots }) {
emits: [
'update:selecting',
],

setup (props, { emit, slots }) {
const { t } = useLocale()

useRender(() => {
Expand All @@ -52,26 +56,26 @@ export const VTimePickerTitle = genericComponent()({
return (
<div class="v-time-picker-title">
<div class="v-time-picker-title__time">
<span>{ props.hour == null ? '--' : props.ampm ? String(hour) : pad(hour) }</span>
<span>:</span>
<span>{ props.minute == null ? '--' : pad(props.minute) }</span>
<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>
{
props.useSeconds && (
<template>
<span>:</span>
<span>{ props.second == null ? '--' : pad(props.second) }</span>
<v-btn variant="flat" onClick={ emit('update:selecting', SelectingTimes.Second) }>{ props.second == null ? '--' : pad(props.second) }</v-btn>
</template>
)
}
{
props.ampm && (
<div
class={['v-time-picker-title__ampm', {
'v-time-picker-title__ampm--readonly': this.ampmReadonly,
'v-time-picker-title__ampm--readonly': props.ampmReadonly,
}]}
>
{ (!this.ampmReadonly || this.period === 'am') ?<span>{ t('$vuetify.timePicker.am') }</span> : '' }
{ (!this.ampmReadonly || this.period === 'pm') ? <span>{ t('$vuetify.timePicker.pm') }</span> : '' }
{ (!props.ampmReadonly || props.period === 'am') ?<span>{ t('$vuetify.timePicker.am') }</span> : '' }
{ (!props.ampmReadonly || props.period === 'pm') ? <span>{ t('$vuetify.timePicker.pm') }</span> : '' }
</div>
)
}
Expand Down

0 comments on commit 97581a2

Please sign in to comment.