forked from opentiny/tiny-vue
styles(ip-address): [ip-address] add ip-address types (#1329)
This commit is contained in:
parent
79f2c194f0
commit
9ef209ffbd
|
@ -11,14 +11,15 @@
|
|||
*/
|
||||
|
||||
import { KEY_CODE, IPTHRESHOLD } from '../common'
|
||||
import type { IIpAddressProps, IIpAddressApi, IIpAddressRenderlessParamUtils, IIpAddressState } from '@/types'
|
||||
|
||||
export const isIP6 = (str) => /^IPv6$/i.test(str)
|
||||
export const isIP6 = (str: string) => /^IPv6$/i.test(str)
|
||||
|
||||
export const isIP4 = (str) => /^IPv4$/i.test(str)
|
||||
export const isIP4 = (str: string) => /^IPv4$/i.test(str)
|
||||
|
||||
export const ipValidator =
|
||||
({ props, api }) =>
|
||||
(value) => {
|
||||
({ props, api }: { props: IIpAddressProps; api: IIpAddressApi }) =>
|
||||
(value: string) => {
|
||||
let result = true
|
||||
|
||||
if (props.type) {
|
||||
|
@ -38,12 +39,13 @@ export const ipValidator =
|
|||
|
||||
export const getCursorPosition = (el) => {
|
||||
let cursorPos = 0
|
||||
let selectRange = null
|
||||
let selectRange: any | null = null
|
||||
type NewDocument = Document & { selection: Document }
|
||||
/* istanbul ignore if */
|
||||
if (document.selection) {
|
||||
selectRange = document.selection.createRange()
|
||||
selectRange.moveStart('character', -el.value.length)
|
||||
cursorPos = selectRange.text.length
|
||||
if ((document as NewDocument | null)?.selection) {
|
||||
selectRange = (document as NewDocument | null)?.selection?.createRange()
|
||||
selectRange?.moveStart('character', -el.value.length)
|
||||
cursorPos = selectRange?.text?.length
|
||||
}
|
||||
/* istanbul ignore if */
|
||||
if (el.selectionStart || el.selectionStart === '0') {
|
||||
|
@ -54,9 +56,9 @@ export const getCursorPosition = (el) => {
|
|||
}
|
||||
|
||||
export const getValue =
|
||||
({ api, props, state }) =>
|
||||
({ api, props, state }: { api: IIpAddressApi; props: IIpAddressProps; state: IIpAddressState }) =>
|
||||
() => {
|
||||
const valueArr = []
|
||||
const valueArr: string[] = []
|
||||
let result = ''
|
||||
|
||||
if (api.isIP6(props.type)) {
|
||||
|
@ -85,11 +87,11 @@ export const getValue =
|
|||
}
|
||||
|
||||
export const setValue =
|
||||
({ api, props, state }) =>
|
||||
(value) => {
|
||||
({ api, props, state }: { api: IIpAddressApi; props: IIpAddressProps; state: IIpAddressState }) =>
|
||||
(value: string) => {
|
||||
if (value) {
|
||||
/* istanbul ignore else */
|
||||
if (api.ipValidator(value)) {
|
||||
if (api?.ipValidator?.(value)) {
|
||||
if (api.isIP6(props.type)) {
|
||||
state.address = value.split(':').map((item) => ({ value: item }))
|
||||
if (state.address.length < 8) {
|
||||
|
@ -116,7 +118,21 @@ export const setValue =
|
|||
}
|
||||
}
|
||||
|
||||
const activeEvent = ({ emit, parent, state, index, event, type }) => {
|
||||
const activeEvent = ({
|
||||
emit,
|
||||
parent,
|
||||
state,
|
||||
index,
|
||||
event,
|
||||
type
|
||||
}: {
|
||||
emit: IIpAddressRenderlessParamUtils['emit']
|
||||
parent: IIpAddressRenderlessParamUtils['parent']
|
||||
state: IIpAddressState
|
||||
index: number
|
||||
event: any
|
||||
type: string
|
||||
}) => {
|
||||
const target = event && event.target ? event.target : parent.$el.querySelectorAll('input')[index || 0]
|
||||
|
||||
type === 'focus' && (state.active = true)
|
||||
|
@ -138,52 +154,84 @@ const activeEvent = ({ emit, parent, state, index, event, type }) => {
|
|||
}
|
||||
|
||||
export const focus =
|
||||
({ emit, parent, state }) =>
|
||||
({ index, event }) => {
|
||||
({
|
||||
emit,
|
||||
parent,
|
||||
state
|
||||
}: {
|
||||
emit: IIpAddressRenderlessParamUtils['emit']
|
||||
parent: IIpAddressRenderlessParamUtils['parent']
|
||||
state: IIpAddressState
|
||||
props?: IIpAddressProps
|
||||
}) =>
|
||||
({ index, event }: { index: number; event?: any }) => {
|
||||
activeEvent({ emit, parent, state, index, event, type: 'focus' })
|
||||
}
|
||||
|
||||
export const select =
|
||||
({ emit, parent, state }) =>
|
||||
({ index, event }) => {
|
||||
({
|
||||
emit,
|
||||
parent,
|
||||
state
|
||||
}: {
|
||||
emit: IIpAddressRenderlessParamUtils['emit']
|
||||
parent: IIpAddressRenderlessParamUtils['parent']
|
||||
state: IIpAddressState
|
||||
props?: IIpAddressProps
|
||||
}) =>
|
||||
({ index, event }: { index: number; event?: any }) => {
|
||||
activeEvent({ emit, parent, state, index, event, type: 'select' })
|
||||
}
|
||||
|
||||
export const inputEvent =
|
||||
({ api, componentName, emit, eventName, props }) =>
|
||||
({ api, componentName, emit, eventName, props }: { api: IIpAddressApi; componentName; emit; eventName; props }) =>
|
||||
({ item, index }) => {
|
||||
const val = item.value.trim()
|
||||
let value = ''
|
||||
let value: string | undefined = ''
|
||||
|
||||
if (api.isIP4(props.type)) {
|
||||
if (!index && api.ipValidator(val)) {
|
||||
api.setValue(val)
|
||||
if (!index && api?.ipValidator?.(val)) {
|
||||
api?.setValue?.(val)
|
||||
} else if (isNaN(val) || val < IPTHRESHOLD.Min || val > IPTHRESHOLD.Max) {
|
||||
item.value = ''
|
||||
}
|
||||
} else {
|
||||
if (!index && api.ipValidator(val)) {
|
||||
api.setValue(val)
|
||||
if (!index && api?.ipValidator?.(val)) {
|
||||
api?.setValue?.(val)
|
||||
} else if (val.length > 4) {
|
||||
item.value = item.value.slice(0, 4)
|
||||
}
|
||||
}
|
||||
|
||||
value = api.getValue()
|
||||
value = api?.getValue?.()
|
||||
|
||||
emit('update:modelValue', value, index)
|
||||
api.dispatch(componentName, eventName, [value])
|
||||
}
|
||||
|
||||
export const change =
|
||||
({ api, emit }) =>
|
||||
({ api, emit }: { api: IIpAddressApi; emit: IIpAddressRenderlessParamUtils['emit'] }) =>
|
||||
() => {
|
||||
const value = api.getValue()
|
||||
const value = api?.getValue?.()
|
||||
emit('change', value)
|
||||
}
|
||||
|
||||
export const blur =
|
||||
({ api, componentName, emit, eventName, props, state }) =>
|
||||
({
|
||||
api,
|
||||
componentName,
|
||||
emit,
|
||||
eventName,
|
||||
props,
|
||||
state
|
||||
}: {
|
||||
api: IIpAddressApi
|
||||
componentName: string
|
||||
emit: IIpAddressRenderlessParamUtils['emit']
|
||||
eventName: string
|
||||
props: IIpAddressProps
|
||||
state: IIpAddressState
|
||||
}) =>
|
||||
({ item, index }) => {
|
||||
state.active = false
|
||||
state.isDel = false
|
||||
|
@ -197,7 +245,7 @@ export const blur =
|
|||
}
|
||||
|
||||
export const keyup =
|
||||
({ api, props }) =>
|
||||
({ api, props }: { api: IIpAddressApi; props: IIpAddressProps; parent?: IIpAddressRenderlessParamUtils['parent'] }) =>
|
||||
({ item, index, event }) => {
|
||||
const { keyCode } = event
|
||||
const value = item.value.trim()
|
||||
|
@ -240,8 +288,21 @@ export const keyup =
|
|||
}
|
||||
}
|
||||
|
||||
const checkError1 = ({ Tab, Space, NumpadDecimal, NumpadComma, keyCode, value }) =>
|
||||
[Tab, Space, NumpadDecimal, NumpadComma].includes(keyCode) && value
|
||||
const checkError1 = ({
|
||||
Tab,
|
||||
Space,
|
||||
NumpadDecimal,
|
||||
NumpadComma,
|
||||
keyCode,
|
||||
value
|
||||
}: {
|
||||
Tab: number
|
||||
Space: number
|
||||
NumpadDecimal: number
|
||||
NumpadComma: number
|
||||
keyCode: number
|
||||
value: string
|
||||
}) => [Tab, Space, NumpadDecimal, NumpadComma].includes(keyCode) && value
|
||||
|
||||
// NEXT 屏蔽选中时,替换值大于255
|
||||
const checkError2 = (newValue) => newValue && (isNaN(newValue) || newValue > IPTHRESHOLD.Max)
|
||||
|
@ -257,7 +318,25 @@ const checkError4 = ({ isfilterKeyCodes, isSelected, value, key }) =>
|
|||
const checkError5 = ({ key, isfilterKeyCodes, value, ctrlKey, keyCode, KeyV }) =>
|
||||
isNaN(key) && !isfilterKeyCodes && !(!value && ctrlKey && keyCode === KeyV)
|
||||
|
||||
const isError = ({ key, value, isSelected, isfilterKeyCodes, ctrlKey, keyCode, newValue }) => {
|
||||
const isError = ({
|
||||
key,
|
||||
value,
|
||||
isSelected,
|
||||
isfilterKeyCodes,
|
||||
ctrlKey,
|
||||
keyCode,
|
||||
newValue
|
||||
}: {
|
||||
key: string
|
||||
value: string
|
||||
isSelected: boolean
|
||||
isfilterKeyCodes: boolean
|
||||
ctrlKey: boolean
|
||||
keyCode: number
|
||||
newValue: string | false
|
||||
api?: IIpAddressApi
|
||||
props?: IIpAddressProps
|
||||
}) => {
|
||||
const { Tab, Space, NumpadDecimal, NumpadComma, KeyV } = KEY_CODE
|
||||
|
||||
return (
|
||||
|
@ -270,12 +349,12 @@ const isError = ({ key, value, isSelected, isfilterKeyCodes, ctrlKey, keyCode, n
|
|||
}
|
||||
|
||||
export const keydown =
|
||||
({ api, props, state }) =>
|
||||
({ item, index, event }) => {
|
||||
({ api, props, state }: { api: IIpAddressApi; props: IIpAddressProps; state: IIpAddressState }) =>
|
||||
({ item, index, event }: { item; index: number; event: KeyboardEvent }) => {
|
||||
const { target, key, keyCode, ctrlKey } = event
|
||||
const value = item.value
|
||||
const selectionStart = target.selectionStart
|
||||
const selectionEnd = target.selectionEnd
|
||||
const selectionStart = (target as KeyboardEvent['target'] & { selectionStart: number })?.selectionStart
|
||||
const selectionEnd = (target as KeyboardEvent['target'] & { selectionEnd: number })?.selectionEnd
|
||||
const isSelected = selectionStart !== selectionEnd
|
||||
const cursorPosition = api.getCursorPosition(target)
|
||||
const isfilterKeyCodes = state.filterKeyCodes.includes(keyCode)
|
||||
|
|
|
@ -27,10 +27,29 @@ import {
|
|||
getHeightOfSize
|
||||
} from './index'
|
||||
import { KEY_CODE } from '../common'
|
||||
import type {
|
||||
IIpAddressProps,
|
||||
IIpAddressState,
|
||||
IIpAddressApi,
|
||||
ISharedRenderlessFunctionParams,
|
||||
IIpAddressRenderlessParamUtils
|
||||
} from '@/types'
|
||||
|
||||
export const api = ['state', 'focus', 'inputEvent', 'blur', 'keyup', 'keydown', 'change', 'select']
|
||||
|
||||
const initState = ({ reactive, computed, handleValue, parent, props }) => {
|
||||
const initState = ({
|
||||
reactive,
|
||||
computed,
|
||||
handleValue,
|
||||
parent,
|
||||
props
|
||||
}: {
|
||||
reactive: ISharedRenderlessFunctionParams<null>['reactive']
|
||||
computed: ISharedRenderlessFunctionParams<null>['computed']
|
||||
handleValue: ReturnType<typeof useHandleValue>
|
||||
parent: ISharedRenderlessFunctionParams<null>['parent']
|
||||
props: IIpAddressProps
|
||||
}) => {
|
||||
const state = reactive({
|
||||
...handleValue.state,
|
||||
active: false,
|
||||
|
@ -52,10 +71,35 @@ const initState = ({ reactive, computed, handleValue, parent, props }) => {
|
|||
allHeightStyle: computed(() => `${state.heightStyle}${state.lineHeightStyle}`)
|
||||
})
|
||||
|
||||
return state
|
||||
return state as IIpAddressState
|
||||
}
|
||||
|
||||
const initApi = ({ state, api, dispatch, handleValue, emit, broadcast, parent, componentName, props, eventName }) => {
|
||||
const initApi = ({
|
||||
state,
|
||||
api,
|
||||
dispatch,
|
||||
handleValue,
|
||||
emit,
|
||||
broadcast,
|
||||
parent,
|
||||
componentName,
|
||||
props,
|
||||
eventName
|
||||
}: {
|
||||
state: IIpAddressState
|
||||
api: IIpAddressApi
|
||||
dispatch: IIpAddressRenderlessParamUtils['dispatch']
|
||||
handleValue: ReturnType<typeof useHandleValue>
|
||||
emit: IIpAddressRenderlessParamUtils['emit']
|
||||
broadcast: IIpAddressRenderlessParamUtils['broadcast']
|
||||
parent: IIpAddressRenderlessParamUtils['parent']
|
||||
componentName: string
|
||||
props: IIpAddressProps
|
||||
eventName: {
|
||||
change: string
|
||||
blur: string
|
||||
}
|
||||
}) => {
|
||||
Object.assign(api, {
|
||||
...handleValue.api,
|
||||
state,
|
||||
|
@ -88,7 +132,7 @@ export const useHandleValue = ({ componentName, dispatch, eventName, props, reac
|
|||
const api = {
|
||||
isIP6,
|
||||
isIP4
|
||||
}
|
||||
} as IIpAddressApi
|
||||
|
||||
api.getValue = getValue({ api, props, state })
|
||||
api.setValue = setValue({ api, props, state })
|
||||
|
@ -98,7 +142,7 @@ export const useHandleValue = ({ componentName, dispatch, eventName, props, reac
|
|||
() => props.modelValue,
|
||||
(value) => {
|
||||
if (!state.isDel) {
|
||||
api.setValue(value)
|
||||
api?.setValue?.(value)
|
||||
dispatch(componentName, eventName, [value])
|
||||
}
|
||||
},
|
||||
|
@ -112,11 +156,11 @@ export const useHandleValue = ({ componentName, dispatch, eventName, props, reac
|
|||
}
|
||||
|
||||
export const renderless = (
|
||||
props,
|
||||
{ reactive, toRefs, watch, inject, computed },
|
||||
{ $prefix, emit, parent, broadcast, dispatch }
|
||||
props: IIpAddressProps,
|
||||
{ reactive, toRefs, watch, inject, computed }: ISharedRenderlessFunctionParams<null>,
|
||||
{ emit, parent, broadcast, dispatch }: IIpAddressRenderlessParamUtils
|
||||
) => {
|
||||
const api = {}
|
||||
const api = {} as IIpAddressApi
|
||||
const componentName = 'FormItem'
|
||||
const eventName = {
|
||||
change: 'form.change',
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import type { ExtractPropTypes, ComputedRef } from 'vue'
|
||||
import type { ipAddressProps } from '@/ip-address/src'
|
||||
import type { ISharedRenderlessParamUtils } from './shared.type'
|
||||
import type {
|
||||
getCursorPosition,
|
||||
select,
|
||||
focus,
|
||||
keyup,
|
||||
blur,
|
||||
change,
|
||||
keydown,
|
||||
inputEvent,
|
||||
isIP6,
|
||||
isIP4,
|
||||
getValue,
|
||||
setValue,
|
||||
ipValidator
|
||||
} from '../src/ip-address'
|
||||
|
||||
export interface IIpAddressState {
|
||||
active: boolean
|
||||
isDel: boolean
|
||||
isSelected: boolean
|
||||
filterKeyCodes: number[]
|
||||
formDisabled: ComputedRef<boolean>
|
||||
disabled: ComputedRef<boolean>
|
||||
heightStyle: ComputedRef<string>
|
||||
lineHeightStyle: ComputedRef<string>
|
||||
allHeightStyle: ComputedRef<string>
|
||||
api: Record<string, (str: any) => boolean>
|
||||
address: { value: string }[]
|
||||
}
|
||||
export type IIpAddressProps = ExtractPropTypes<typeof ipAddressProps>
|
||||
export interface IIpAddressApi {
|
||||
state: IIpAddressState
|
||||
dispatch: IIpAddressRenderlessParamUtils['dispatch']
|
||||
broadcast: IIpAddressRenderlessParamUtils['broadcast']
|
||||
getCursorPosition: typeof getCursorPosition
|
||||
focus: ReturnType<typeof focus>
|
||||
select: ReturnType<typeof select>
|
||||
blur: ReturnType<typeof blur>
|
||||
keyup: ReturnType<typeof keyup>
|
||||
change: ReturnType<typeof change>
|
||||
keydown: ReturnType<typeof keydown>
|
||||
inputEvent: ReturnType<typeof inputEvent>
|
||||
isIP6: typeof isIP6
|
||||
isIP4: typeof isIP4
|
||||
getValue?: ReturnType<typeof getValue>
|
||||
setValue?: ReturnType<typeof setValue>
|
||||
ipValidator?: ReturnType<typeof ipValidator>
|
||||
}
|
||||
|
||||
export type IIpAddressRenderlessParamUtils = ISharedRenderlessParamUtils<null>
|
|
@ -12,44 +12,46 @@
|
|||
import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common'
|
||||
import template from 'virtual-template?pc'
|
||||
|
||||
export const ipAddressProps = {
|
||||
...$props,
|
||||
size: String,
|
||||
|
||||
/**
|
||||
* @property {String} value - 显示值
|
||||
*/
|
||||
modelValue: String,
|
||||
|
||||
/**
|
||||
* @property {String} [type = IPv4] - IP地址输入组件类型('IPv4', 'IPv6',)可选择
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
default: 'IPv4',
|
||||
validator: (value: string) => Boolean(~['IPv4', 'IPv6'].indexOf(value))
|
||||
},
|
||||
|
||||
/**
|
||||
* @property {Boolean} readonly - 只读
|
||||
*/
|
||||
readonly: Boolean,
|
||||
|
||||
/**
|
||||
* @property {Boolean} disabled - 禁用
|
||||
*/
|
||||
disabled: Boolean,
|
||||
|
||||
/**
|
||||
* @property {String, Object} [delimiter = .] - 组件IP段显示的分隔符改为图标
|
||||
*/
|
||||
delimiter: {
|
||||
type: [String, Object],
|
||||
default: 'icon-dot-ipv4'
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: $prefix + 'IpAddress',
|
||||
props: {
|
||||
...$props,
|
||||
size: String,
|
||||
|
||||
/**
|
||||
* @property {String} value - 显示值
|
||||
*/
|
||||
modelValue: String,
|
||||
|
||||
/**
|
||||
* @property {String} [type = IPv4] - IP地址输入组件类型('IPv4', 'IPv6',)可选择
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
default: 'IPv4',
|
||||
validator: (value: string) => Boolean(~['IPv4', 'IPv6'].indexOf(value))
|
||||
},
|
||||
|
||||
/**
|
||||
* @property {Boolean} readonly - 只读
|
||||
*/
|
||||
readonly: Boolean,
|
||||
|
||||
/**
|
||||
* @property {Boolean} disabled - 禁用
|
||||
*/
|
||||
disabled: Boolean,
|
||||
|
||||
/**
|
||||
* @property {String, Object} [delimiter = .] - 组件IP段显示的分隔符改为图标
|
||||
*/
|
||||
delimiter: {
|
||||
type: [String, Object],
|
||||
default: 'icon-dot-ipv4'
|
||||
}
|
||||
},
|
||||
props: ipAddressProps,
|
||||
setup(props, context) {
|
||||
return $setup({ props, context, template })
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue