Skip to content

Commit

Permalink
feat(comp:*): all input components support setting status
Browse files Browse the repository at this point in the history
  • Loading branch information
danranVm committed Sep 28, 2022
1 parent 43b0802 commit 997293c
Show file tree
Hide file tree
Showing 48 changed files with 287 additions and 306 deletions.
3 changes: 2 additions & 1 deletion packages/components/_private/input/src/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ export default defineComponent({
expose({ getInputElement })

const classes = computed(() => {
const { borderless, clearable, disabled, focused, size, addonAfter, addonBefore, prefix, suffix } = props
const { borderless, clearable, disabled, focused, size, status, addonAfter, addonBefore, prefix, suffix } = props
const prefixCls = mergedPrefixCls.value
return normalizeClass({
[prefixCls]: true,
[`${prefixCls}-${size}`]: true,
[`${prefixCls}-${status}`]: !!status,
[`${prefixCls}-borderless`]: borderless,
[`${prefixCls}-clearable`]: clearable,
[`${prefixCls}-disabled`]: disabled,
Expand Down
2 changes: 2 additions & 0 deletions packages/components/_private/input/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { ValidateStatus } from '@idux/cdk/forms'
import type { ExtractInnerPropTypes, ExtractPublicPropTypes } from '@idux/cdk/utils'
import type { FormSize } from '@idux/components/form'
import type { DefineComponent, InputHTMLAttributes, PropType } from 'vue'
Expand Down Expand Up @@ -35,6 +36,7 @@ export const inputProps = {
},
prefix: String,
size: String as PropType<FormSize>,
status: String as PropType<ValidateStatus>,
suffix: String,
onClear: Function as PropType<(evt: MouseEvent) => void>,
} as const
Expand Down
9 changes: 5 additions & 4 deletions packages/components/_private/selector/src/Selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,23 @@ export default defineComponent({

const classes = computed(() => {
const config = props.config
const { allowInput, className, borderless = config.borderless, multiple } = props
const { allowInput, className, borderless = config.borderless, multiple, status } = props
const prefixCls = mergedPrefixCls.value
return normalizeClass({
[className]: true,
[prefixCls]: true,
[`${prefixCls}-${mergedSize.value}`]: true,
[`${prefixCls}-${status}`]: !!status,
[`${prefixCls}-allow-input`]: allowInput,
[`${prefixCls}-borderless`]: borderless,
[`${prefixCls}-clearable`]: mergedClearable.value,
[`${prefixCls}-disabled`]: props.disabled,
[`${prefixCls}-focused`]: isFocused.value,
[`${prefixCls}-multiple`]: multiple,
[`${prefixCls}-opened`]: props.opened,
[`${prefixCls}-readonly`]: props.readonly,
[`${prefixCls}-single`]: !multiple,
[`${prefixCls}-searchable`]: mergedSearchable.value,
[`${prefixCls}-allow-input`]: allowInput,
[`${prefixCls}-${mergedSize.value}`]: true,
[`${prefixCls}-single`]: !multiple,
})
})

Expand Down
5 changes: 3 additions & 2 deletions packages/components/_private/selector/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { ValidateStatus } from '@idux/cdk/forms'
import type { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray } from '@idux/cdk/utils'
import type { FormSize } from '@idux/components/form'
import type { DefineComponent, HTMLAttributes, PropType } from 'vue'

import { type FormSize } from '@idux/components/form'

export const selectorProps = {
allowInput: { type: Boolean, required: true },
autocomplete: { type: String, required: true },
Expand All @@ -32,6 +32,7 @@ export const selectorProps = {
readonly: { type: Boolean, required: true },
searchable: { type: [Boolean, String] as PropType<boolean | 'overlay'>, required: true },
size: { type: String as PropType<FormSize>, default: undefined },
status: String as PropType<ValidateStatus>,
suffix: { type: String, default: undefined },
value: { type: Array, required: true },

Expand Down
16 changes: 14 additions & 2 deletions packages/components/_private/selector/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,26 @@
.borderless();
}

&-searchable &-content
&-allow-input &-content {
&-searchable &-content &-allow-input &-content {
cursor: text;

.@{selector-prefix}-input-inner {
cursor: auto;
}
}

// form status
&&-invalid {
&:hover .@{selector-prefix}-content,
.@{selector-prefix}-content {
border-color: @form-item-invalid-color;
}

&.@{selector-prefix}-active .@{selector-prefix}-content {
border-color: @form-item-invalid-color;
box-shadow: @form-item-invalid-box-shadow;
}
}
}

.selector-icon() {
Expand Down
24 changes: 12 additions & 12 deletions packages/components/_private/trigger/src/Trigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ export default defineComponent({
const common = useGlobalConfig('common')
const mergedPrefixCls = computed(() => `${common.prefixCls}-trigger`)

const isDisabled = computed(() => props.disabled)

const focusMonitor = useSharedFocusMonitor()
const triggerRef = ref<HTMLElement>()
onMounted(() => {
Expand All @@ -41,35 +39,37 @@ export default defineComponent({

const classes = computed(() => {
const prefixCls = mergedPrefixCls.value
const { className, size, status, borderless, disabled, focused, readonly } = props
return normalizeClass({
[`${props.className}`]: !!props.className,
[`${className}`]: !!className,
[prefixCls]: true,
[`${prefixCls}-disabled`]: isDisabled.value,
[`${prefixCls}-borderless`]: props.borderless,
[`${prefixCls}-readonly`]: props.readonly,
[`${prefixCls}-focused`]: props.focused,
[`${prefixCls}-${props.size}`]: props.size,
[`${prefixCls}-${size}`]: true,
[`${prefixCls}-${status}`]: !!status,
[`${prefixCls}-borderless`]: borderless,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-focused`]: focused,
[`${prefixCls}-readonly`]: readonly,
})
})

const handleClick = (evt: Event) => {
if (isDisabled.value) {
if (props.disabled) {
return
}

callEmit(props.onClick, evt)
}

const handleKeyDown = (evt: KeyboardEvent) => {
if (isDisabled.value) {
if (props.disabled) {
return
}

callEmit(props.onKeyDown, evt)
}

const handleClear = (evt: MouseEvent) => {
if (isDisabled.value) {
if (props.disabled) {
return
}

Expand All @@ -88,7 +88,7 @@ export default defineComponent({
)
}
const renderClearIcon = () => {
if (!props.clearable || isDisabled.value || (!props.clearIcon && !slots.clearIcon)) {
if (!props.clearable || props.disabled || (!props.clearIcon && !slots.clearIcon)) {
return null
}

Expand Down
5 changes: 3 additions & 2 deletions packages/components/_private/trigger/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { ValidateStatus } from '@idux/cdk/forms'
import type { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray } from '@idux/cdk/utils'
import type { FormSize } from '@idux/components/form'
import type { DefineComponent, HTMLAttributes, PropType } from 'vue'

import { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray } from '@idux/cdk/utils'

export const triggerProps = {
borderless: Boolean as PropType<boolean>,
clearable: Boolean as PropType<boolean>,
Expand All @@ -19,6 +19,7 @@ export const triggerProps = {
focused: Boolean as PropType<boolean>,
readonly: Boolean as PropType<boolean>,
size: String as PropType<FormSize>,
status: String as PropType<ValidateStatus>,
suffix: String as PropType<string>,
onClick: [Array, Function] as PropType<MaybeArray<(evt: Event) => void>>,
onClear: [Array, Function] as PropType<MaybeArray<(evt: MouseEvent) => void>>,
Expand Down
16 changes: 15 additions & 1 deletion packages/components/_private/trigger/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,18 @@
font-size: inherit;
.placeholder(@trigger-placeholder-color);
}
}

// form status
&&-invalid {
border-color: @form-item-invalid-color;

&:hover {
border-color: @form-item-invalid-color;
}

&.@{idux-prefix}-trigger-focused {
border-color: @form-item-invalid-color;
box-shadow: @form-item-invalid-box-shadow;
}
}
}
1 change: 1 addition & 0 deletions packages/components/cascader/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
| `searchable` | 是否可搜索 | `boolean \| 'overlay'` | `false` | - | 当为 `true` 时搜索功能集成在选择器上,当为 `overlay` 时,搜索功能集成在悬浮层上 |
| `searchFn` | 根据搜索的文本进行筛选 | `boolean \| SelectSearchFn` | `true` | - |`true` 时使用默认的搜索规则, 如果使用远程搜索,应该设置为 `false` |
| `size` | 设置选择器大小 | `'sm' \| 'md' \| 'lg'` | `md` || - |
| `status` | 手动指定校验状态 | `valid \| invalid \| validating` | - | - | - |
| `strategy` | 设置级联策略 | `'all' \| 'parent' \| 'child'` | `'off'` | - | 具体用法参见 [级联策略](#components-cascader-demo-Strategy) |
| `suffix` | 设置后缀图标 | `string \| #suffix` | `down` || - |
| `virtual` | 是否开启虚拟滚动 | `boolean` | `false` | - | 需要设置 `height` |
Expand Down
7 changes: 5 additions & 2 deletions packages/components/cascader/src/Cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { type VKey, useState } from '@idux/cdk/utils'
import { ɵOverlay } from '@idux/components/_private/overlay'
import { ɵSelector, type ɵSelectorInstance } from '@idux/components/_private/selector'
import { useGlobalConfig } from '@idux/components/config'
import { useFormItemRegister } from '@idux/components/form'
import { useFormItemRegister, useFormSize, useFormStatus } from '@idux/components/form'
import { ɵUseOverlayState } from '@idux/components/select'
import { useGetKey, useOverlayContainer } from '@idux/components/utils'

Expand Down Expand Up @@ -58,6 +58,8 @@ export default defineComponent({

const { accessor, control } = useAccessorAndControl()
useFormItemRegister(control)
const mergedSize = useFormSize(props, config)
const mergedStatus = useFormStatus(props, control)

const { mergedData, mergedDataMap } = useDataSource(
props,
Expand Down Expand Up @@ -150,7 +152,8 @@ export default defineComponent({
placeholder={props.placeholder}
readonly={props.readonly}
searchable={props.searchable}
size={props.size}
size={mergedSize.value}
status={mergedStatus.value}
suffix={props.suffix}
value={selectedStateContext.selectedKeys.value}
onBlur={handleBlur}
Expand Down
3 changes: 2 additions & 1 deletion packages/components/cascader/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/* eslint-disable @typescript-eslint/no-explicit-any */

import type { AbstractControl } from '@idux/cdk/forms'
import type { AbstractControl, ValidateStatus } from '@idux/cdk/forms'
import type { PortalTargetType } from '@idux/cdk/portal'
import type { ExtractInnerPropTypes, ExtractPublicPropTypes, MaybeArray, VKey } from '@idux/cdk/utils'
import type { EmptyProps } from '@idux/components/empty'
Expand Down Expand Up @@ -55,6 +55,7 @@ export const cascaderProps = {
searchable: { type: [Boolean, String] as PropType<boolean | 'overlay'>, default: false },
searchFn: { type: [Boolean, Function] as PropType<boolean | CascaderSearchFn>, default: true },
size: { type: String as PropType<FormSize>, default: undefined },
status: String as PropType<ValidateStatus>,
strategy: { type: String as PropType<CascaderStrategy>, default: 'all' },
suffix: { type: String, default: undefined },
virtual: { type: Boolean, default: false },
Expand Down
1 change: 1 addition & 0 deletions packages/components/date-picker/docs/Api.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
| `overlayRender` | 自定义日期面板内容的渲染 | `(children:VNode[]) => VNodeChild` | - | - | - |
| `readonly` | 只读模式 | `boolean` | - | - | - |
| `size` | 设置选择器大小 | `'sm' \| 'md' \| 'lg'` | `md` || - |
| `status` | 手动指定校验状态 | `valid \| invalid \| validating` | - | - | - |
| `suffix` | 设置后缀图标 | `string \| #suffix` | `'calendar'` || - |
| `type` | 设置选择器类型 | `'date' \| 'week' \| 'month' \| 'quarter' \| 'year' \| 'datetime'` | `'date'` | - | - |
| `onClear` | 清除图标被点击后的回调 | `(evt: MouseEvent) => void` | - | - | - |
Expand Down
2 changes: 1 addition & 1 deletion packages/components/date-picker/src/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default defineComponent({

const inputEnableStatus = useInputEnableStatus(props, config)
const formatContext = useFormat(props, config)
const pickerStateContext = usePickerState(props, dateConfig, formatContext.formatRef)
const pickerStateContext = usePickerState(props, config, dateConfig, formatContext.formatRef)

const { accessor, handleChange } = pickerStateContext

Expand Down
2 changes: 1 addition & 1 deletion packages/components/date-picker/src/DateRangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default defineComponent({

const inputEnableStatus = useInputEnableStatus(props, config)
const formatContext = useFormat(props, config)
const pickerStateContext = usePickerState(props, dateConfig, formatContext.formatRef)
const pickerStateContext = usePickerState(props, config, dateConfig, formatContext.formatRef)

const { accessor, handleChange } = pickerStateContext

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { type ComputedRef, toRaw } from 'vue'

import { isArray } from 'lodash-es'

import { type FormAccessor, useAccessorAndControl } from '@idux/cdk/forms'
import { type FormAccessor, ValidateStatus, useAccessorAndControl } from '@idux/cdk/forms'
import { callEmit, convertArray, useState } from '@idux/cdk/utils'
import { type DateConfig } from '@idux/components/config'
import { useFormItemRegister } from '@idux/components/form'
import { FormSize, useFormItemRegister, useFormSize, useFormStatus } from '@idux/components/form'

import { type DatePickerProps, type DateRangePickerProps } from '../types'
import { convertToDate, sortRangeValue } from '../utils'
Expand All @@ -23,6 +23,8 @@ type StateValueType<T extends DatePickerProps | DateRangePickerProps> = T extend

export interface PickerStateContext<T extends DatePickerProps | DateRangePickerProps> {
accessor: FormAccessor<T['value']>
mergedSize: ComputedRef<FormSize>
mergedStatus: ComputedRef<ValidateStatus | undefined>
isFocused: ComputedRef<boolean>
handleChange: (value: StateValueType<T>) => void
handleClear: (evt: MouseEvent) => void
Expand All @@ -32,11 +34,14 @@ export interface PickerStateContext<T extends DatePickerProps | DateRangePickerP

export function usePickerState<T extends DatePickerProps | DateRangePickerProps>(
props: T,
config: { size: FormSize },
dateConfig: DateConfig,
formatRef: ComputedRef<string>,
): PickerStateContext<T> {
const { accessor, control } = useAccessorAndControl<T['value']>()
useFormItemRegister(control)
const mergedSize = useFormSize(props, config)
const mergedStatus = useFormStatus(props, control)

const [isFocused, setFocused] = useState(false)

Expand Down Expand Up @@ -75,6 +80,8 @@ export function usePickerState<T extends DatePickerProps | DateRangePickerProps>

return {
accessor,
mergedSize,
mergedStatus,
isFocused,
handleChange,
handleClear,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@

import type { DatePickerContext, DateRangePickerContext } from '../token'
import type { ɵTriggerProps } from '@idux/components/_private/trigger'
import type { FormContext } from '@idux/components/form'

import { type ComputedRef, computed } from 'vue'

export function useTriggerProps(
context: DatePickerContext | DateRangePickerContext,
formContext: FormContext | null,
): ComputedRef<ɵTriggerProps> {
export function useTriggerProps(context: DatePickerContext | DateRangePickerContext): ComputedRef<ɵTriggerProps> {
const {
props,
config,
accessor,
mergedSize,
mergedStatus,
isFocused,
handleFocus,
handleBlur,
Expand Down Expand Up @@ -46,7 +44,8 @@ export function useTriggerProps(
disabled: accessor.disabled,
focused: isFocused.value,
readonly: props.readonly || inputEnableStatus.value.enableInput === false,
size: props.size ?? formContext?.size.value ?? config.size,
size: mergedSize.value,
status: mergedStatus.value,
suffix: props.suffix ?? config.suffix,
onClick: handleClick,
onClear: handleClear,
Expand Down
4 changes: 1 addition & 3 deletions packages/components/date-picker/src/trigger/RangeTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { computed, defineComponent, inject } from 'vue'

import { callEmit } from '@idux/cdk/utils'
import { ɵTrigger } from '@idux/components/_private/trigger'
import { FORM_TOKEN } from '@idux/components/form'

import { useTriggerProps } from '../composables/useTriggerProps'
import { dateRangePickerToken } from '../token'
Expand All @@ -29,14 +28,13 @@ export default defineComponent({
inputEnableStatus,
renderSeparator,
} = context
const formContext = inject(FORM_TOKEN, null)

const placeholders = computed(() => [
props.placeholder?.[0] ?? locale.dateRangePicker[`${props.type}Placeholder`][0],
props.placeholder?.[1] ?? locale.dateRangePicker[`${props.type}Placeholder`][1],
])
const inputSize = computed(() => Math.max(10, formatRef.value.length) + 2)
const triggerProps = useTriggerProps(context, formContext)
const triggerProps = useTriggerProps(context)

const handleFromInput = (evt: Event) => {
fromControl.handleInput(evt)
Expand Down
Loading

0 comments on commit 997293c

Please sign in to comment.