{"version":3,"file":"captcha-slider.vue2.mjs","sources":["../../../components/captcha/captcha-slider.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { Icon } from '@/components/icon'\nimport { useFieldStore } from '@/components/form'\nimport { Renderer } from '@/components/renderer'\n\nimport { computed, nextTick, ref, watch } from 'vue'\n\nimport {\n  createIconProp,\n  createSizeProp,\n  emitEvent,\n  useIcons,\n  useLocale,\n  useNameHelper,\n  useProps\n} from '@vexip-ui/config'\nimport { useMoving, useSetTimeout } from '@vexip-ui/hooks'\nimport { boundRange, toFixed } from '@vexip-ui/utils'\nimport { captchaSliderProps } from './props'\n\nimport type { CaptchaSliderSlots } from './symbol'\n\ndefineOptions({ name: 'CaptchaSlider' })\n\nconst { idFor, labelId, disabled, loading, size, validateField, getFieldValue, setFieldValue } =\n  useFieldStore<boolean>(focus)\n\nconst _props = defineProps(captchaSliderProps)\nconst props = useProps('captcha', _props, {\n  size: createSizeProp(size),\n  target: {\n    default: 100,\n    validator: value => value >= 0 && value <= 100\n  },\n  tip: null,\n  successTip: null,\n  tolerance: {\n    default: 1,\n    validator: value => value >= 0\n  },\n  disabled: () => disabled.value,\n  loading: () => loading.value,\n  loadingIcon: createIconProp(),\n  loadingLock: false,\n  loadingEffect: null,\n  onBeforeTest: {\n    default: null,\n    isFunc: true\n  },\n  slots: () => ({})\n})\n\ndefineSlots<CaptchaSliderSlots>()\n\nconst nh = useNameHelper('captcha')\nconst locale = useLocale('captcha')\nconst icons = useIcons()\n\nconst { timer } = useSetTimeout()\n\nconst currentLeft = ref(0)\nconst testing = ref(false)\nconst resetting = ref(false)\nconst isSuccess = ref(false)\nconst testLoading = ref(false)\n\nconst track = ref<HTMLElement>()\n\nconst readonly = computed(() => props.disabled || (props.loading && props.loadingLock))\n\nlet widthLimit: number\n\nconst { target: trigger, moving: dragging } = useMoving({\n  onStart: (_, event) => {\n    if (\n      testing.value ||\n      readonly.value ||\n      !track.value ||\n      !trigger.value ||\n      isSuccess.value ||\n      resetting.value ||\n      event.button > 0\n    ) {\n      return false\n    }\n\n    widthLimit = track.value.getBoundingClientRect().width\n    currentLeft.value = 0\n    verifyPosition()\n    trigger.value.focus()\n    emitEvent(props.onDragStart, currentLeft.value)\n  },\n  onMove: state => {\n    if (testing.value || readonly.value || isSuccess.value || resetting.value) {\n      return false\n    }\n\n    currentLeft.value = (state.deltaX / widthLimit) * 100\n    verifyPosition()\n    emitEvent(props.onDrag, currentLeft.value)\n  },\n  onEnd: async () => {\n    if (testing.value || readonly.value) return\n\n    testing.value = true\n\n    const matched = matchTarget(currentLeft.value)\n    let customResult: unknown\n\n    if (typeof props.onBeforeTest === 'function') {\n      nextTick(() => {\n        testLoading.value = true\n      })\n      customResult = await props.onBeforeTest(currentLeft.value, matched)\n      nextTick(() => {\n        testLoading.value = false\n      })\n    }\n\n    if (currentLeft.value && (customResult === false || (!matched && customResult !== true))) {\n      resetting.value = true\n      currentLeft.value = 0\n      isSuccess.value = false\n\n      setFieldValue(false)\n      emitEvent(props.onFail)\n    } else if (matched || customResult === true) {\n      isSuccess.value = true\n\n      if (customResult && !matched) {\n        resetting.value = true\n        currentLeft.value = props.target\n      }\n\n      setFieldValue(true)\n      emitEvent(props.onSuccess, currentLeft.value)\n    }\n\n    validateField()\n    trigger.value?.blur()\n    emitEvent(props.onDragEnd, currentLeft.value)\n\n    clearTimeout(timer.testing)\n    testing.value = false\n  }\n})\n\nconst isLoading = computed(() => props.loading || testLoading.value)\nconst className = computed(() => {\n  const baseCls = nh.be('slider')\n\n  return {\n    [baseCls]: true,\n    [nh.bs('vars')]: true,\n    [`${baseCls}--success`]: isSuccess.value,\n    [`${baseCls}--disabled`]: props.disabled,\n    [`${baseCls}--loading`]: isLoading.value,\n    [`${baseCls}--${props.size}`]: props.size !== 'default'\n  }\n})\nconst fillerStyle = computed(() => {\n  return {\n    [nh.cv('filler-transition')]: resetting.value ? 'transform 250ms ease' : undefined,\n    transform: `scaleX(${currentLeft.value / 100})`\n  }\n})\nconst tipStyle = computed(() => {\n  return {\n    [nh.cv('tip-transition')]: resetting.value ? 'background-position 250ms ease' : undefined,\n    backgroundPosition: `-${currentLeft.value}%`\n  }\n})\nconst triggerStyle = computed(() => {\n  return {\n    left: `${currentLeft.value}%`,\n    [nh.cv('trigger-transition')]: resetting.value ? 'left 250ms ease' : undefined\n  }\n})\n\nwatch(\n  () => getFieldValue(),\n  value => {\n    if (!value) {\n      reset()\n    } else {\n      if (!matchTarget(currentLeft.value)) {\n        resetting.value = true\n        currentLeft.value = props.target\n      }\n\n      isSuccess.value = true\n    }\n  }\n)\nwatch(readonly, value => value && reset())\n\ndefineExpose({\n  idFor,\n  currentLeft,\n  resetting,\n  isSuccess,\n  dragging,\n  isLoading,\n  track,\n  trigger,\n  focus,\n  reset\n})\n\nfunction verifyPosition() {\n  currentLeft.value = toFixed(boundRange(currentLeft.value, 0, 100), 3)\n}\n\nfunction reset() {\n  resetting.value = true\n  currentLeft.value = 0\n  isSuccess.value = false\n}\n\nfunction afterReset() {\n  resetting.value = false\n}\n\nfunction matchTarget(value: number) {\n  return Math.abs(props.target - value) <= props.tolerance\n}\n\nfunction focus(options?: FocusOptions) {\n  trigger.value?.focus(options)\n}\n</script>\n\n<template>\n  <div\n    :id=\"idFor\"\n    ref=\"wrapper\"\n    :class=\"className\"\n    tabindex=\"-1\"\n    role=\"group\"\n    :aria-labelledby=\"labelId\"\n  >\n    <div\n      :class=\"{\n        [nh.be('filler')]: true,\n        [nh.bem('filler', 'loading')]: isLoading,\n        [nh.bem('filler', 'success')]: isSuccess\n      }\"\n      :style=\"fillerStyle\"\n    ></div>\n    <div\n      :class=\"{\n        [nh.be('tip')]: true,\n        [nh.bem('tip', 'focused')]: dragging,\n        [nh.bem('tip', 'loading')]: isLoading,\n        [nh.bem('tip', 'success')]: isSuccess\n      }\"\n      :style=\"tipStyle\"\n    >\n      <slot name=\"tip\" :success=\"isSuccess\">\n        <Renderer :renderer=\"props.slots.tip\" :data=\"{ success: isSuccess }\">\n          {{ isSuccess ? (props.successTip ?? locale.success) : (props.tip ?? locale.slideEnd) }}\n        </Renderer>\n      </slot>\n    </div>\n    <div ref=\"track\" :class=\"nh.be('track')\">\n      <div\n        ref=\"trigger\"\n        :class=\"{\n          [nh.be('trigger')]: true,\n          [nh.bem('trigger', 'focused')]: dragging,\n          [nh.bem('trigger', 'loading')]: isLoading,\n          [nh.bem('trigger', 'success')]: isSuccess\n        }\"\n        tabindex=\"0\"\n        :style=\"triggerStyle\"\n        @transitionend=\"afterReset\"\n      >\n        <slot name=\"trigger\" :success=\"isSuccess\">\n          <Renderer :renderer=\"props.slots.trigger\" :data=\"{ success: isSuccess }\">\n            <Icon v-if=\"isSuccess\" v-bind=\"icons.check\"></Icon>\n            <Icon\n              v-else-if=\"isLoading\"\n              v-bind=\"icons.loading\"\n              :effect=\"props.loadingEffect || icons.loading.effect\"\n              :icon=\"props.loadingIcon || icons.loading.icon\"\n            ></Icon>\n            <Icon v-else v-bind=\"icons.anglesRight\"></Icon>\n          </Renderer>\n        </slot>\n      </div>\n    </div>\n  </div>\n</template>\n"],"names":["idFor","labelId","disabled","loading","size","validateField","getFieldValue","setFieldValue","useFieldStore","focus","props","useProps","__props","createSizeProp","value","createIconProp","nh","useNameHelper","locale","useLocale","icons","useIcons","timer","useSetTimeout","currentLeft","ref","testing","resetting","isSuccess","testLoading","track","readonly","computed","widthLimit","trigger","dragging","useMoving","_","event","verifyPosition","emitEvent","state","matched","matchTarget","customResult","nextTick","_a","isLoading","className","baseCls","fillerStyle","tipStyle","triggerStyle","watch","reset","__expose","toFixed","boundRange","afterReset","options"],"mappings":"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"}