Skip to content

Commit

Permalink
Merge pull request #110 from phoenixwong/1-1-0
Browse files Browse the repository at this point in the history
Release v1.1.0
  • Loading branch information
phoenixwong authored May 17, 2020
2 parents 3d8c805 + 3520c9f commit 89027ea
Show file tree
Hide file tree
Showing 13 changed files with 3,027 additions and 535 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

> The Change Log of Vue2 Timepicker `vue2-timepicker`
## v 1.1.0

### New

- Support manually input values with the `manual-input` toggle.
- Enable to hide the dropdown menu with `hide-dropdown` in Manual Input (`manual-input`) mode.
- Added conditional helper classes `is-empty`, `invalid` and `all-selected` to the `<input>` element.
- Change the `<input>` border to red color when user input is invalid. E.g., when it contains a disabled hour value. You can mute this auto-styling by adding `"skip-error-style"` to `input-class`.
- Add support to the `autocomplete` attribute.
- Emit `error` event when the input value becomes invalid.
- Emit `focus` and `blur` events to help to identify the focus/blur state. Useful when the dropdown is force hidden by `hide-dropdown`.

### Improvements

Enable seamless loop from the start or end of a column in `advanced-keyboard` mode.

## v 1.0.8

### Improvements
Expand Down
108 changes: 105 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

---

💡 Dead repo recharged in 2019 🔋
💡 Dead repo recharged 🔋

---

Expand Down Expand Up @@ -487,6 +487,13 @@ Advance Keyboard support (enabled with `advanced-keyboard`):

Please be aware that after putting the `advanced-keyboard` on, hundreds of additional keyboard event listeners are going to be attached to the component. The amount of listeners depends on how many hours, minutes, and seconds value you enabled in the current Timepicker.

### Manual Input Support

```html
<vue-timepicker manual-input></vue-timepicker>
```
Let users add or change values through the `<input>` box besides the dropdown picker.

### Blur Delay

```html
Expand Down Expand Up @@ -575,6 +582,7 @@ Prop | Type | Required | Default Value
**hide-disabled-seconds** | _Boolean_ | no | false
**hide-disabled-items** | _Boolean_ | no | false
**advanced-keyboard** | _Boolean_ | no | false
**manual-input** | _Boolean_ | no | false
**blur-delay** | _Number_ | no | 300
**lazy** | _Boolean_ | no | false
**auto-scroll** | _Boolean_ | no | false
Expand All @@ -589,10 +597,11 @@ Prop | Type | Required | Default Value
**name** | _String_ | no | _undefined_
**placeholder** | _String_ | no | _undefined_
**tabindex** | _Number_ | no | 0
**autocomplete** | _String_ | no | 'off'
**input-class** | _String_, _Array_, _Object_ | no | _undefined_
**input-width** | _String_ | no | '10em'

Timepicker now supports `id`, `name`, `placeholder`, and `tabindex` like common form elements. These values are assigned to the `<input type="text" class="display-time">` within the component.
Timepicker supports `id`, `name`, `placeholder`, and `tabindex` like common form elements. These values are assigned to the `<input type="text" class="display-time">` within the component.

### Input `id`, `name` and `tabindex`

Expand Down Expand Up @@ -625,6 +634,28 @@ When `placeholder` is undefined, timepicker takes the determined format string i
<!-- -> "HH:mm" -->
```

### Input `autocomplete` Attribute

> **NOTE:** To use this property, you MUST ENABLE the `manual-input` mode _(v.1.1.0+)_ in the first place.
```html
<!-- In Vue Template -->
<vue-timepicker name="starttime" autocomplete="on" manual-input></vue-timepicker>
```

```html
<!-- HTML result -->
<span class="vue__time-picker time-picker">
<input class="display-time" name="starttime" type="text" autocomplete="on">
<!-- ... -->
</span>
```

When enabled, it accepts any string value supported by the HTML input `autocomplete` attribute. The value is assigned to the embedding text `<input>`, which means it follows form autofill rules and configs set in the browser level. For example, most of the browsers require the input to have a `name` and/or `id` attribute. Some browsers, like Firefox, demand the input to be a descendant of a `<form>` element.

Please refer to the [HTML documentation](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) and the developer guideline of each browser for more information (i.e., [MDN docs here](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete)).


### The `input-class`

The `input-class` is assigned to the text input within the component as well.
Expand Down Expand Up @@ -689,13 +720,15 @@ Event | Arguments | Description
**change** | (_eventData_) | Emit after value changes
**open** | &nbsp; | Emit when the dropdown opens
**close** | &nbsp; | Emit when the dropdown closes
**focus** | &nbsp; | Emit when the user start focusing on the Timepicker
**blur** | &nbsp; | Emit when the user blurs the Timepicker
**error** | (_eventData_) | Emit when the input value becomes invalid

### The `open` and `close` Event of the Dropdown Picker

Help to identify the current status of the dropdown picker

```javascript
// Define a variable for logging the status
data () {
return {
dropdownStatus: 'closed'
Expand All @@ -709,6 +742,75 @@ data () {
<vue-timepicker @open="dropdownStatus = 'opened'" @close="dropdownStatus = 'closed'"></vue-timepicker>
```

### The `focus` and `blur` Event

Help to identify focus/blur state of the Vue Timepicker. Especially useful in cases where the dropdown is force hidden by `hide-dropdown` under the Manual Input mode.

```javascript
data () {
return {
focusState: 'blurred'
}
}
```

```html
<p>Focus State: I'm {{focusState}}!</p>

<vue-timepicker manual-input hide-dropdown @focus="focusState = 'focused'" @blur="focusState = 'blurred'"></vue-timepicker>
```

### The `error` event

Starts from `v.1.1.0+`, Timepicker will emit an `error` event when the current input value becomes invalid. E.g., when it contains an hour value that is not in the `hour-range` list or a minute value that doesn't fit in the `minute-interval`.

```html
<!-- Got the `hour-range` and `minute-interval` set -->
<!-- And add a hanlder to pick up the "error" event -->
<vue-timepicker format="H:mm:ss" v-model="erroredInputSample" :hour-range="[8, 9, 10, 11]" :minute-interval="5" @error="errorHanlder"></vue-timepicker>
```

```javascript
data () {
return {
erroredInputSample: { H: '5', mm: '03', ss: '00' }
// NOTE:
// H: '5' -> invalid. Value is not in the `hour-range` list
// mm: '03' -> invalid. Value does not fit in the `minute-interval`
// ss: '00' -> valid.
}
},

methods: {
errorHanlder (eventData) {
console.log(eventData)
// console.log outputs -> ["hour", "minute"]
}
}
```

The `error` event returns an _Array_ of invalid fields' names. When it returns an empty array `[]`, it means the current input is valid, and all previous errors are gone

> NOTE: Empty value will **not** be marked as invalid.

## Helper CSS Class Names

Started from `v.1.1.0+`, Vue Timepicker will add additional CSS classes to the `<input>` element base on the state of the current input value.

- **invalid**: One or more fields containing an invalid or disabled value.
- Additional CSS Style: The `<input>` border turns red.
- If you want to mute this red border style, add `"skip-error-style"` to `input-class`
- **is-empty**: The input value (_v-model_) is empty. No additional style.
- **all-selected**: All fields (hour/minute/second/apm) required by the `format` string are not empty. No additional style.

```html
<!-- To mute the red border style of "invalid" state -->
<timepicker input-class="skip-error-style"></timepicker>
<timepicker :input-class="['skip-error-style', 'your-other-class-names']"></timepicker>
```


## Miscellaneous Props API

Prop | Type | Required | Default Value
Expand Down
95 changes: 85 additions & 10 deletions demo/src/components/Playground.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,19 @@ export default {
disablePicker: false,
closeOnComplete: false,
advancedKeyboard: false,
manualInput: false,
hideDropdown: false,
lazyMode: false,
autoScroll: false,
skipErrorStyle: false,
debugMode: false,
customBlurDelay: false,
blurDelay: 300,
playgroundData: {},
playgroundFullValue: {},
playgroundDisplayTime: undefined,
playgroundErroredData: undefined,
scrollTop: 0,
Expand Down Expand Up @@ -131,12 +134,30 @@ export default {
return result
},
toHideDropdown () {
if (!this.manualInput) { return false }
return this.hideDropdown
},
useAdvancedKeyboard () {
if (this.toHideDropdown) { return false }
return this.advancedKeyboard
},
showErroredData () {
return Boolean(this.playgroundErroredData && this.playgroundErroredData.length)
},
htmlCodeWithVar () {
let start = '<vue-timepicker'
let end = '\n v-model="yourTimeValue">\n</vue-timepicker>'
start += (`\n format="${this.formatString}"`)
if (this.skipErrorStyle) {
start += ('\n input-class="skip-error-style"')
}
if (this.customInterval.minute) {
start += (`\n :minute-interval="${this.interval.minute}"`)
}
Expand Down Expand Up @@ -172,7 +193,15 @@ export default {
start += ('\n close-on-complete')
}
if (this.advancedKeyboard) {
if (this.manualInput) {
start += ('\n manual-input')
}
if (this.toHideDropdown) {
start += ('\n hide-dropdown')
}
if (this.useAdvancedKeyboard) {
start += ('\n advanced-keyboard')
}
Expand Down Expand Up @@ -434,11 +463,14 @@ export default {
},
changeHandler (eventData) {
this.playgroundFullValue = eventData.data
this.playgroundDisplayTime = eventData.displayTime
this.playgroundFullValue = eventData
this.updateRangeValue(eventData.data)
},
errorHandler (eventData) {
this.playgroundErroredData = eventData
},
scrollHandler (evt) {
this.scrollTop = (evt.target.scrollingElement || (document.documentElement || document.body.parentNode)).scrollTop || 0
},
Expand Down Expand Up @@ -738,7 +770,31 @@ section#playground
input(v-model="autoScroll" type="radio" id="auto_scroll_false" name="auto_scroll", :value="false")
| &nbsp;Disable

#advancedKeyboard.config-block
#manualInput.config-block
h3.subtitle
a.anchor #
| Manually Input Support
config-row(is-group)
label.options(for="manual_input_true")
input(v-model="manualInput" type="radio" id="manual_input_true" name="manual_input", :value="true")
| &nbsp;Enable
label.options(for="manual_input_false")
input(v-model="manualInput" type="radio" id="manual_input_false" name="manual_input", :value="false")
| &nbsp;Disable

#hideDropdown.config-block(v-if="manualInput")
h3.subtitle
a.anchor #
| Hide Dropdown
config-row(is-group)
label.options(for="hide_dropdown_true")
input(v-model="hideDropdown" type="radio" id="hide_dropdown_true" name="hide_dropdown", :value="true")
| &nbsp;Enable
label.options(for="hide_dropdown_false")
input(v-model="hideDropdown" type="radio" id="hide_dropdown_false" name="hide_dropdown", :value="false")
| &nbsp;Disable

#advancedKeyboard.config-block(v-if="!toHideDropdown")
h3.subtitle
a.anchor #
| Advanced Keyboard Support
Expand All @@ -762,6 +818,18 @@ section#playground
input(v-model.number="blurDelay" type="range" min="50" max="1500" step="50")
span(v-text="blurDelay")

#skipErrorStyle.config-block
h3.subtitle
a.anchor #
| Skip Error Style
config-row(is-group)
label.options(for="skip_error_true")
input(v-model="skipErrorStyle" type="radio" id="skip_error_true" name="skip_error", :value="true")
| &nbsp;Enable
label.options(for="skip_error_false")
input(v-model="skipErrorStyle" type="radio" id="skip_error_false" name="skip_error", :value="false")
| &nbsp;Disable

#debugMode.config-block
h3.subtitle
a.anchor #
Expand All @@ -779,32 +847,38 @@ section#playground
//-
aside.previews(:style="asideStyle")
#playgroundPreview.preview
b Format string:&nbsp;
span(v-text="formatString")
label(for="vueTimepickerInPlayground")
b Format string:&nbsp;
span(v-text="formatString")
p
vue-timepicker(v-model="playgroundData"
id="vueTimepickerInPlayground"
:format="formatString"
:minute-interval="interval.minute"
:second-interval="showSeconds ? interval.second : null"
:hour-range="customRange.hour ? hourRange : null"
:minute-range="customRange.minute ? minuteRange : null"
:second-range="(showSeconds && customRange.second) ? secondRange : null"
:close-on-complete="closeOnComplete"
:advanced-keyboard="advancedKeyboard"
:advanced-keyboard="useAdvancedKeyboard"
:manual-input="manualInput"
:hide-dropdown="toHideDropdown"
:blur-delay="blurDelay"
:hide-clear-button="hideClearBtn"
:disabled="disablePicker"
:lazy="lazyMode"
:auto-scroll="autoScroll"
:debug-mode="debugMode"
@change="changeHandler")
:input-class="skipErrorStyle ? 'skip-error-style' : null"
@change="changeHandler"
@error="errorHandler")

#htmlCodePreview.codes
highlight-code(lang="html" data-title="HTML") {{ htmlCodeWithVar }}

#dispatchedValue.codes
highlight-code(lang="json" data-title="@change event data") {{ playgroundFullValue }}
highlight-code(lang="html" data-title="@change event displayTime") "{{ playgroundDisplayTime || '' }}"
highlight-code(v-if="showErroredData" lang="json" data-title="@error event data") {{ playgroundErroredData }}

//-
//- Customized Range Panels
Expand Down Expand Up @@ -875,6 +949,7 @@ section#playground
#playgroundPreview
box-sizing: border-box
background: #fff
padding: 1em 1.5em
.range-item,
.invalid-range
Expand Down
Loading

0 comments on commit 89027ea

Please sign in to comment.