feat(component): [time-select] add include end time attribute (#19253)

* feat: [time-select] init includeEndTime 🚧

* test: time-select includeEndTime 🚧

* refactor: renaming & cleanup

* test(components): [time-select] add includeEndTime cases 

* docs(components): [time-select] add `includeEndTime` attribute

* chore: change release version

* chore: set `includeEndTime` default to false

* docs: fix props typo

* chore: remove useless assignment

* chore: rename optionValue to currentTime

* chore: update release version
This commit is contained in:
Noblet Ouways 2025-01-10 08:46:13 +01:00 committed by GitHub
parent c976e945f5
commit 22c3bd8e72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 95 additions and 26 deletions

View File

@ -51,26 +51,27 @@ time-select/time-range
### Attributes
| Name | Description | Type | Default |
| ----------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------- |
| model-value / v-model | binding value | ^[string] | — |
| disabled | whether TimeSelect is disabled | ^[boolean] | false |
| editable | whether the input is editable | ^[boolean] | true |
| clearable | whether to show clear button | ^[boolean] | true |
| size | size of Input | ^[enum]`'large' \| 'default' \| 'small'` | default |
| placeholder | placeholder in non-range mode | ^[string] | — |
| name | same as `name` in native input | ^[string] | — |
| effect | Tooltip theme, built-in theme: `dark` / `light` | ^[string] / ^[enum]`'dark' \| 'light'` | light |
| prefix-icon | custom prefix icon component | ^[string] / ^[Component] | Clock |
| clear-icon | custom clear icon component | ^[string] / ^[Component] | CircleClose |
| start | start time | ^[string] | 09:00 |
| end | end time | ^[string] | 18:00 |
| step | time step | ^[string] | 00:30 |
| min-time | minimum time, any time before this time will be disabled | ^[string] | — |
| max-time | maximum time, any time after this time will be disabled | ^[string] | — |
| format | set format of time | ^[string] see [formats](https://day.js.org/docs/en/display/format#list-of-all-available-formats) | HH:mm |
| empty-values ^(2.7.0) | empty values of component, [see config-provider](/en-US/component/config-provider#empty-values-configurations) | ^[array] | — |
| value-on-clear ^(2.7.0) | clear return value, [see config-provider](/en-US/component/config-provider#empty-values-configurations) | ^[string] / ^[number] / ^[boolean] / ^[Function] | — |
| Name | Description | Type | Default |
| ------------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------- |
| model-value / v-model | binding value | ^[string] | — |
| disabled | whether TimeSelect is disabled | ^[boolean] | false |
| editable | whether the input is editable | ^[boolean] | true |
| clearable | whether to show clear button | ^[boolean] | true |
| include-end-time ^(2.9.3) | whether `end` is included in options | ^[boolean] | false |
| size | size of Input | ^[enum]`'large' \| 'default' \| 'small'` | default |
| placeholder | placeholder in non-range mode | ^[string] | — |
| name | same as `name` in native input | ^[string] | — |
| effect | Tooltip theme, built-in theme: `dark` / `light` | ^[string] / ^[enum]`'dark' \| 'light'` | light |
| prefix-icon | custom prefix icon component | ^[string] / ^[Component] | Clock |
| clear-icon | custom clear icon component | ^[string] / ^[Component] | CircleClose |
| start | start time | ^[string] | 09:00 |
| end | end time | ^[string] | 18:00 |
| step | time step | ^[string] | 00:30 |
| min-time | minimum time, any time before this time will be disabled | ^[string] | — |
| max-time | maximum time, any time after this time will be disabled | ^[string] | — |
| format | set format of time | ^[string] see [formats](https://day.js.org/docs/en/display/format#list-of-all-available-formats) | HH:mm |
| empty-values ^(2.7.0) | empty values of component, [see config-provider](/en-US/component/config-provider#empty-values-configurations) | ^[array] | — |
| value-on-clear ^(2.7.0) | clear return value, [see config-provider](/en-US/component/config-provider#empty-values-configurations) | ^[string] / ^[number] / ^[boolean] / ^[Function] | — |
### Events

View File

@ -132,6 +132,53 @@ describe('TimeSelect', () => {
expect(select.props().filterable).toBe(true)
})
it('should include end time', async () => {
const wrapper = mount(() => (
<TimeSelect
start="00:00"
step="00:05"
end="23:59"
includeEndTime={true}
/>
))
const select = wrapper.findComponent({ name: 'ElTimeSelect' })
const input = wrapper.find('input')
await input.trigger('click')
const items = document.querySelectorAll('.el-select-dropdown__item>span')
expect(select.props().includeEndTime).toBe(true)
expect(items).toHaveLength(289)
expect([...items].at(-1)?.textContent).toBe('23:59')
})
it('should not include end time', async () => {
const wrapper = mount(() => (
<TimeSelect start="00:00" step="00:05" end="23:59" />
))
const select = wrapper.findComponent({ name: 'ElTimeSelect' })
const input = wrapper.find('input')
await input.trigger('click')
const items = document.querySelectorAll('.el-select-dropdown__item>span')
expect(select.props().includeEndTime).toBe(false)
expect(items).toHaveLength(288)
expect([...items].at(-1)?.textContent).toBe('23:55')
})
it('should include end whenever includeEndTime is false', async () => {
const wrapper = mount(() => (
<TimeSelect start="00:10" end="00:20" step="00:02" />
))
const select = wrapper.findComponent({ name: 'ElTimeSelect' })
const input = wrapper.find('input')
await input.trigger('click')
const items = document.querySelectorAll('.el-select-dropdown__item>span')
expect(select.props().includeEndTime).toBe(false)
expect(items).toHaveLength(6)
expect([...items].at(-1)?.textContent).toBe('00:20')
})
it('ref focus', async () => {
const wrapper = mount(() => <TimeSelect />, {
attachTo: document.body,

View File

@ -79,6 +79,13 @@ export const timeSelectProps = buildProps({
* @description maximum time, any time after this time will be disabled
*/
maxTime: String,
/**
* @description whether `end` is included in options
*/
includeEndTime: {
type: Boolean,
default: false,
},
/**
* @description same as `name` in native input
*/

View File

@ -90,6 +90,15 @@ const maxTime = computed(() => {
const items = computed(() => {
const result: { value: string; disabled: boolean }[] = []
const push = (formattedValue: string, rawValue: string) => {
result.push({
value: formattedValue,
disabled:
compareTime(rawValue, minTime.value || '-1:-1') <= 0 ||
compareTime(rawValue, maxTime.value || '100:100') >= 0,
})
}
if (props.start && props.end && props.step) {
let current = start.value
let currentTime: string
@ -97,14 +106,19 @@ const items = computed(() => {
currentTime = dayjs(current, 'HH:mm')
.locale(lang.value)
.format(props.format)
result.push({
value: currentTime,
disabled:
compareTime(current, minTime.value || '-1:-1') <= 0 ||
compareTime(current, maxTime.value || '100:100') >= 0,
})
push(currentTime, current)
current = nextTime(current, step.value!)
}
if (
props.includeEndTime &&
end.value &&
result[result.length - 1]?.value !== end.value
) {
const formattedValue = dayjs(end.value, 'HH:mm')
.locale(lang.value)
.format(props.format)
push(formattedValue, end.value)
}
}
return result
})