<script setup>
import { computed, ref, inject } from "vue";
import { useNamespace } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { radioGroupContextKey } from "./radio";
defineOptions({
  name: "YhRadio"
});
const props = defineProps({
  modelValue: { type: [String, Number, Boolean], required: false },
  value: { type: [String, Number, Boolean], required: false },
  name: { type: String, required: false },
  label: { type: String, required: false },
  size: { type: null, required: false },
  disabled: { type: Boolean, required: false, default: false },
  border: { type: Boolean, required: false, default: false },
  id: { type: String, required: false },
  tabindex: { type: [String, Number], required: false },
  themeOverrides: { type: null, required: false }
});
const emit = defineEmits(["update:modelValue", "change"]);
const ns = useNamespace("radio");
const radioGroup = inject(radioGroupContextKey, void 0);
const { themeStyle } = useComponentTheme(
  "radio",
  computed(() => props.themeOverrides || radioGroup?.themeOverrides)
);
const inputRef = ref();
const focused = ref(false);
const hovering = ref(false);
const isGroup = computed(() => !!radioGroup);
const radioSize = computed(() => {
  return props.size || radioGroup?.size || "default";
});
const isDisabled = computed(() => {
  return props.disabled || radioGroup?.disabled || false;
});
const radioName = computed(() => {
  return props.name || radioGroup?.name || "";
});
const isChecked = computed(() => {
  const value = props.value ?? props.label;
  if (isGroup.value && radioGroup) {
    return radioGroup.modelValue === value;
  }
  return props.modelValue === value;
});
const radioClasses = computed(() => [
  ns.b(),
  radioSize.value !== "default" ? ns.m(radioSize.value) : "",
  ns.is("disabled", isDisabled.value),
  ns.is("checked", isChecked.value),
  ns.is("focused", focused.value),
  ns.is("bordered", props.border)
]);
const innerClasses = computed(() => [
  ns.e("inner"),
  ns.is("checked", isChecked.value),
  ns.is("disabled", isDisabled.value)
]);
const handleChange = () => {
  if (isDisabled.value) return;
  const value = props.value;
  if (isGroup.value && radioGroup) {
    radioGroup.changeEvent?.(value);
  } else {
    emit("update:modelValue", value);
    emit("change", value);
  }
};
const handleFocus = () => {
  focused.value = true;
};
const handleBlur = () => {
  focused.value = false;
};
const focus = () => {
  inputRef.value?.focus();
};
const blur = () => {
  inputRef.value?.blur();
};
defineExpose({
  ref: inputRef.value,
  focus,
  blur
});
</script>

<template>
  <label
    :class="radioClasses"
    :style="themeStyle"
    @mouseenter="hovering = true"
    @mouseleave="hovering = false"
  >
    <span :class="ns.e('input')">
      <span :class="innerClasses">
        <!-- 选中圆点 -->
        <span v-if="isChecked" :class="ns.e('dot')" />
      </span>
      <input
        ref="inputRef"
        :class="ns.e('original')"
        type="radio"
        :name="radioName"
        :id="id"
        :tabindex="tabindex"
        :disabled="isDisabled"
        :checked="isChecked"
        :value="value"
        @change="handleChange"
        @focus="handleFocus"
        @blur="handleBlur"
      />
    </span>
    <span v-if="$slots.default || label" :class="ns.e('label')">
      <slot>{{ label }}</slot>
    </span>
  </label>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-radio {
  --yh-radio-size: 14px;
  --yh-radio-input-border: var(--yh-border-color);
  --yh-radio-checked-bg-color: var(--yh-color-primary);
  --yh-radio-checked-border-color: var(--yh-color-primary);
  --yh-radio-checked-icon-color: var(--yh-color-primary);
  --yh-radio-text-color: var(--yh-text-color-regular);
  display: inline-flex;
  align-items: center;
  position: relative;
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  margin-right: 32px;
  font-size: var(--yh-font-size-base);
  line-height: 1;
}
.yh-radio__input {
  white-space: nowrap;
  cursor: pointer;
  outline: none;
  display: inline-flex;
  position: relative;
  vertical-align: middle;
}
.yh-radio__inner {
  border: 1px solid var(--yh-radio-input-border);
  border-radius: var(--yh-radius-circle);
  width: var(--yh-radio-size);
  height: var(--yh-radio-size);
  background-color: var(--yh-fill-color-blank, #fff);
  position: relative;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  transition: border-color 0.2s, background-color 0.2s;
}
.yh-radio__inner.is-checked {
  border-color: var(--yh-radio-checked-border-color);
  background-color: var(--yh-radio-checked-bg-color);
}

.yh-radio__inner.is-disabled {
  background-color: var(--yh-fill-color-light, #f5f7fa);
  border-color: var(--yh-border-color-light, #e4e7ed);
  cursor: not-allowed;
}

.yh-radio__dot {
  width: 4px;
  height: 4px;
  border-radius: var(--yh-radius-circle);
  background-color: var(--yh-color-primary-text, var(--yh-fill-color-blank, #fff));
  content: "";
  transition: transform 0.15s ease-in;
}

.yh-radio__original {
  opacity: 0;
  outline: none;
  position: absolute;
  z-index: -1;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
}

.yh-radio.is-checked .yh-radio__label {
  color: var(--yh-radio-checked-border-color);
}

.yh-radio.is-disabled {
  cursor: not-allowed;
}
.yh-radio.is-disabled .yh-radio__label {
  color: var(--yh-text-color-disabled, #c0c4cc);
}

.yh-radio__label {
  font-size: inherit;
  padding-left: 8px;
  color: var(--yh-radio-text-color);
}

.yh-radio--large {
  --yh-radio-size: 16px;
  font-size: var(--yh-font-size-md);
}

.yh-radio--small {
  --yh-radio-size: 12px;
  font-size: var(--yh-font-size-xs);
}
</style>
