{"version":3,"file":"form-item.mjs","sources":["../../../../../../packages/components/form/src/form-item.vue"],"sourcesContent":["<template>\n  <hl-row\n    ref=\"formItemRef\"\n    :role=\"isGroup ? 'group' : undefined\"\n    :aria-labelledby=\"isGroup ? labelId : undefined\"\n    :class=\"[formItemClass]\"\n    :gap=\"itemGap\"\n    :gap-x=\"formContext?.itemGapX\"\n    :gap-y=\"formContext?.itemGapY\"\n  >\n    <hl-col v-if=\"label || $slots.label\" :class=\"[labelClass, 'form-label']\" :style=\"{ width: labelStyle }\">\n      <component\n        :is=\"labelFor ? 'label' : 'div'\"\n        v-if=\"hasLabel\"\n        :id=\"labelId\"\n        :for=\"labelFor\"\n      >\n        <slot name=\"label\" :label=\"currentLabel\">{{ currentLabel }}</slot>\n      </component>\n    </hl-col>\n    <hl-col class=\"form-content\" :class=\"[contentClass, offset]\" :style=\"contentStyle\">\n      <slot></slot>\n      <transition-group name=\"zoom-in-top\">\n        <slot v-if=\"shouldShowError\" name=\"error\" :error=\"validateMessage\">\n          <div class=\"form-content-info\">\n            {{ validateMessage }}\n          </div>\n        </slot>\n      </transition-group>\n    </hl-col>\n  </hl-row>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, provide, inject, ref, watch, computed, onMounted, onBeforeUnmount, toRefs, reactive, nextTick } from 'vue'\nimport AsyncValidator from 'async-validator'\nimport { clone } from 'lodash-unified'\nimport { refDebounced } from '@vueuse/core'\nimport { ensureArray, getProp, isFunction, isString } from '@hongluan-ui/utils'\nimport { useGlobalConfig, useId, useNamespace } from '@hongluan-ui/hooks'\nimport { formContextKey, formItemContextKey } from '@hongluan-ui/tokens'\nimport HlRow from '@hongluan-ui/components/row'\nimport HlCol from '@hongluan-ui/components/col'\nimport { formItemProps } from './form-item'\n\nimport type { CSSProperties } from 'vue'\nimport type { RuleItem } from 'async-validator'\nimport type { ComponentSize } from '@hongluan-ui/constants'\nimport type { Arrayable } from '@hongluan-ui/utils'\nimport type { FormItemContext, FormItemRule, FormValidateFailure } from '@hongluan-ui/tokens'\nimport type { FormItemValidateState } from './form-item'\n\nexport default defineComponent({\n  name: 'FormItem',\n  components: { HlRow, HlCol },\n  props: formItemProps,\n  setup(props, { slots }) {\n    const HL = useGlobalConfig()\n    const { namespace } = useNamespace('form-item')\n\n    const formContext = inject(formContextKey, undefined)\n\n    const labelId = useId().value\n    const inputIds = ref<string[]>([])\n\n    const validateState = ref<FormItemValidateState>('')\n    const validateStateDebounced = refDebounced(validateState, 100)\n    const validateMessage = ref('')\n\n    const formItemRef = ref<{ $el: HTMLElement; }>()\n\n    // special inline value.\n    let initialValue: any = undefined\n    let isResettingField = false\n\n    const propString = computed(() => {\n      if (!props.prop) return ''\n      return isString(props.prop) ? props.prop : props.prop.join('.')\n    })\n\n    const hasLabel = computed<boolean>(() => {\n      return !!(props.label || slots.label)\n    })\n\n    const labelFor = computed<string | undefined>(() => {\n      return (\n        props.for || (inputIds.value.length === 1 ? inputIds.value[0] : undefined)\n      )\n    })\n\n    const isGroup = computed<boolean>(() => {\n      return !labelFor.value && hasLabel.value\n    })\n\n    const labelStyle = computed(() => {\n      let width = props.width || formContext?.width\n      width = Array.isArray(width) ? width : [width]\n      const labelWidth = width && (width[0] as string)\n      return labelWidth\n    })\n\n    const contentStyle = computed(() => {\n      let width = props.width || formContext?.width\n      width = Array.isArray(width) ? width : [width]\n      const contentWidth = width && (width[1] as string)\n      const style = {} as CSSProperties\n      if (contentWidth && !Number.isNaN(Number.parseInt(contentWidth, 10))) {\n        style.width = contentWidth\n      }\n      return style\n    })\n\n    const labelClass = computed(() => {\n      let width = props.width || formContext?.width\n      width = Array.isArray(width) ? width : [width]\n      const labelClazz = width && (width[0] as string)\n      let labelPosition = props.labelPosition || formContext?.labelPosition\n      let clazz = ''\n      if (labelPosition) {\n        labelPosition = Array.isArray(labelPosition) ? labelPosition : [labelPosition]\n        clazz = labelPosition.join(' ')\n      }\n      if (labelClazz && Number.isNaN(Number.parseInt(labelClazz, 10))) {\n        clazz += ' ' + labelClazz\n      }\n      return clazz\n    })\n\n    const contentClass = computed(() => {\n      let width = props.width || formContext?.width\n      width = Array.isArray(width) ? width : [width]\n      const contentClazz = width && (width[1] as string)\n      if (contentClazz && Number.isNaN(Number.parseInt(contentClazz, 10))) {\n        return contentClazz\n      }\n      return ''\n    })\n\n    const itemGap = computed(() => {\n      return props.gap || formContext?.itemGap\n    })\n\n    const sizeClass = computed<ComponentSize>(() => {\n      return props.size || formContext?.size || HL.value.size\n    })\n\n    const formItemClass = computed(() => [\n      {\n        [namespace.value]: true,\n        'form-item-feedback': formContext?.statusIcon,\n        'is-error': validateState.value === 'error',\n        'is-validating': validateState.value === 'validating',\n        'is-success': validateState.value === 'success',\n        'is-required': isRequired.value || props.required,\n        'is-no-asterisk': formContext?.hideRequiredAsterisk,\n      },\n      sizeClass.value ? sizeClass.value : '',\n      formContext?.requireAsteriskPosition === 'right' ? 'asterisk-right' : 'asterisk-left',\n    ])\n\n    const fieldValue = computed(() => {\n      const model = formContext?.model\n      if (!model || !props.prop) {\n        return\n      }\n\n      return getProp(model, props.prop).value\n    })\n\n    const normalizedRules = computed(() => {\n      const { required } = props\n\n      const rules: FormItemRule[] = []\n\n      if (props.rules) {\n        rules.push(...ensureArray(props.rules))\n      }\n\n      const formRules = formContext?.rules\n      if (formRules && props.prop) {\n        const _rules = getProp<Arrayable<FormItemRule> | undefined>(\n          formRules,\n          props.prop,\n        ).value\n        if (_rules) {\n          rules.push(...ensureArray(_rules))\n        }\n      }\n\n      if (required !== undefined) {\n        const requiredRules = rules\n          .map((rule, i) => [rule, i] as const)\n          .filter(([rule]) => Object.keys(rule).includes('required'))\n\n        if (requiredRules.length > 0) {\n          for (const [rule, i] of requiredRules) {\n            if (rule.required === required) continue\n            rules[i] = { ...rule, required }\n          }\n        } else {\n          rules.push({ required })\n        }\n      }\n\n      return rules\n    })\n\n    const validateEnabled = computed(() => normalizedRules.value.length > 0)\n\n    const getFilteredRule = (trigger: string) => {\n      const rules = normalizedRules.value\n      return (\n        rules\n          .filter(rule => {\n            if (!rule.trigger || !trigger) return true\n            if (Array.isArray(rule.trigger)) {\n              return rule.trigger.includes(trigger)\n            } else {\n              return rule.trigger === trigger\n            }\n          })\n        // exclude trigger\n        // eslint-disable-next-line @typescript-eslint/no-unused-vars\n          .map(({ trigger, ...rule }): RuleItem => rule)\n      )\n    }\n\n    const isRequired = computed(() =>\n      normalizedRules.value.some(rule => rule.required),\n    )\n\n    const shouldShowError = computed(() => {\n      return validateStateDebounced.value === 'error' && props.showMessage && formContext.showMessage\n    })\n\n    const currentLabel = computed(() => (formContext?.labelPrefix || '') + (props.label || '') + (formContext?.labelSuffix || ''))\n\n    const setValidationState = (state: FormItemValidateState) => {\n      validateState.value = state\n    }\n\n    const onValidationFailed = (error: FormValidateFailure) => {\n      const { errors, fields } = error\n      if (!errors || !fields) {\n        console.error(error)\n      }\n\n      setValidationState('error')\n      validateMessage.value = errors\n        ? errors?.[0]?.message ?? `${props.prop} is required`\n        : ''\n\n      formContext?.emit('validate', props.prop, false, validateMessage.value)\n    }\n    const onValidationSucceeded = () => {\n      setValidationState('success')\n      formContext?.emit('validate', props.prop, true, '')\n    }\n\n    const doValidate = async (rules: RuleItem[]): Promise<true> => {\n      const modelName = propString.value\n      const validator = new AsyncValidator({\n        [modelName]: rules,\n      })\n      return validator\n        .validate({ [modelName]: fieldValue.value }, { firstFields: true })\n        .then(() => {\n          onValidationSucceeded()\n          return true as const\n        })\n        .catch((err: FormValidateFailure) => {\n          onValidationFailed(err as FormValidateFailure)\n          return Promise.reject(err)\n        })\n    }\n    const validate: FormItemContext['validate'] = async (trigger, callback) => {\n      // skip validation if its resetting\n      if (isResettingField || !props.prop) {\n        return false\n      }\n\n      const hasCallback = isFunction(callback)\n      if (!validateEnabled.value) {\n        callback?.(false)\n        return false\n      }\n\n\n      const rules = getFilteredRule(trigger)\n      if (rules.length === 0) {\n        callback?.(true)\n        return true\n      }\n\n      setValidationState('validating')\n\n      return doValidate(rules)\n        .then(() => {\n          callback?.(true)\n          return true as const\n        })\n        .catch((err: FormValidateFailure) => {\n          const { fields } = err\n          callback?.(false, fields)\n          return hasCallback ? false : Promise.reject(fields)\n        })\n    }\n\n    const clearValidate: FormItemContext['clearValidate'] = () => {\n      setValidationState('')\n      validateMessage.value = ''\n      isResettingField = false\n    }\n\n    const resetField: FormItemContext['resetField'] = async () => {\n      const model = formContext?.model\n      if (!model || !props.prop) return\n\n      const computedValue = getProp(model, props.prop)\n      // prevent validation from being triggered\n      isResettingField = true\n\n      computedValue.value = clone(initialValue)\n\n      await nextTick()\n      clearValidate()\n      isResettingField = false\n    }\n\n    const addInputId: FormItemContext['addInputId'] = (id: string) => {\n      if (!inputIds.value.includes(id)) {\n        inputIds.value.push(id)\n      }\n    }\n\n    const removeInputId: FormItemContext['removeInputId'] = (id: string) => {\n      inputIds.value = inputIds.value.filter(listId => listId !== id)\n    }\n\n    watch(\n      () => props.error,\n      val => {\n        validateMessage.value = val || ''\n        setValidationState(val ? 'error' : '')\n      },\n      { immediate: true },\n    )\n\n    watch(\n      () => props.validateStatus,\n      val => setValidationState(val || ''),\n    )\n\n    const formItemContext: FormItemContext = reactive({\n      ...toRefs(props),\n      size: sizeClass,\n      labelId,\n      inputIds,\n      isGroup,\n      fieldValue,\n      addInputId,\n      removeInputId,\n      validateState,\n      $el: formItemRef,\n      resetField,\n      clearValidate,\n      validate,\n    })\n\n    provide(formItemContextKey, formItemContext)\n\n    onMounted(() => {\n      if (props.prop) {\n        formContext?.addField(formItemContext)\n        initialValue = clone(fieldValue.value)\n      }\n    })\n    onBeforeUnmount(() => {\n      formContext?.removeField(formItemContext)\n    })\n\n    return {\n      formItemRef,\n      formItemClass,\n      validate,\n      resetField,\n      clearValidate,\n      validateState,\n      hasLabel,\n      labelId,\n      inputIds,\n      isGroup,\n      shouldShowError,\n      formContext,\n      labelStyle,\n      contentStyle,\n      labelClass,\n      contentClass,\n      validateMessage,\n      labelFor,\n      itemGap,\n      currentLabel,\n    }\n  },\n})\n</script>\n"],"names":["ensureArray"],"mappings":"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"}