Skip to content

Commit

Permalink
feat: add touchOnFocus option
Browse files Browse the repository at this point in the history
  • Loading branch information
nozomuikuta committed Jan 3, 2024
1 parent b4566a7 commit f0d2d3b
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 6 deletions.
13 changes: 8 additions & 5 deletions packages/vue-v8n/src/composables/useV7d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type { RuleDefinition, UseV7dOptions } from '../types'

export function useV7d<T>(value: T, rules: MaybeRefOrGetter<RuleDefinition[]>, options?: UseV7dOptions) {
const {
immediate = false
immediate = false,
touchOnFocus = true
} = options || {}

const $el = ref<EventTarget>()
Expand All @@ -14,10 +15,12 @@ export function useV7d<T>(value: T, rules: MaybeRefOrGetter<RuleDefinition[]>, o
const _error = ref('')
const _errors = ref<string[]>([])

watch($el, () => {
$el.value?.removeEventListener('focus', $touch)
$el.value?.addEventListener('focus', $touch)
}, { immediate: true })
if (touchOnFocus) {
watch($el, () => {
$el.value?.removeEventListener('focus', $touch)
$el.value?.addEventListener('focus', $touch)
}, { immediate: true })
}

watch(_value, $validate, { immediate })

Expand Down
1 change: 1 addition & 0 deletions packages/vue-v8n/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface RuleContext {}

export interface UseV7dOptions {
immediate?: boolean
touchOnFocus?: boolean
}

export interface VueV8nOptions {}
Expand Down
40 changes: 39 additions & 1 deletion playground/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,49 @@ watch(password, () => validatedValues.passwordConfirmation = passwordConfirmatio
watch(passwordConfirmation.value, () => validatedValues.passwordConfirmation = passwordConfirmation.$validate())
watch(passwordConfirmationRuleOptions, () => validatedValues.passwordConfirmation = passwordConfirmation.$validate(), { deep: true })
const noTouchedNameRuleOptions = ref([
{ label: 'required', rule: required, selected: false },
{ label: 'min(5)', rule: min(5), selected: false },
{ label: 'max(10)', rule: max(10), selected: false }
])
const noTouchedName = useV7d('', computed(() => noTouchedNameRuleOptions.value.flatMap(({ selected, rule }) => selected ? [rule] : [])), {
touchOnFocus: false
})
watch(noTouchedNameRuleOptions, () => validatedValues.noTouchedName = noTouchedName.$validate(), { deep: true })
const state = reactive({
name,
count,
passwordConfirmation
passwordConfirmation,
noTouchedName
})
const validatedValues = reactive({} as {
name: typeof name.value.value | Error,
count: typeof count.value.value | Error,
passwordConfirmation: typeof passwordConfirmation.value.value | Error,
noTouchedName: typeof noTouchedName.value.value | Error,
})
function validate() {
validatedValues.name = name.$validate()
validatedValues.count = count.$validate()
validatedValues.passwordConfirmation = passwordConfirmation.$validate()
validatedValues.noTouchedName = noTouchedName.$validate()
}
function touch() {
name.$touch()
count.$touch()
passwordConfirmation.$touch()
noTouchedName.$touch()
}
function reset() {
name.$reset()
count.$reset()
passwordConfirmation.$reset()
noTouchedName.$reset()
}
onMounted(() => console.log(getCurrentInstance()?.appContext.config.globalProperties.vueV8n))
Expand Down Expand Up @@ -144,6 +160,28 @@ onMounted(() => console.log(getCurrentInstance()?.appContext.config.globalProper
<button @click="passwordConfirmation.$reset">Reset</button>
</div>
</div>
<div :class="['form-item', noTouchedName.$hasError.value ? 'has-error' : '']">
<label class="form-label">Name (no touched on focus):</label>
<input
:ref="noTouchedName.$el"
type="text"
v-model="noTouchedName.value.value"
class="form-input"
>
<p v-if="noTouchedName.$hasError.value" class="error-message">{{ noTouchedName.$error.value }}</p>
<div class="control-items">
<p>Rules:</p>
<label v-for="ruleOption in noTouchedNameRuleOptions">
<input type="checkbox" v-model="ruleOption.selected">
{{ ruleOption.label }}
</label>
</div>
<div class="control-items">
<button @click="validatedValues.noTouchedName = noTouchedName.$validate()">Validate</button>
<button @click="noTouchedName.$touch">Touch</button>
<button @click="noTouchedName.$reset">Reset</button>
</div>
</div>
</div>
<div class="pane pane-state">
<p>[State]</p>
Expand Down

0 comments on commit f0d2d3b

Please sign in to comment.