styles(ip-address): [ip-address] add ip-address types (#1329)

This commit is contained in:
jxhhdx 2024-01-24 12:21:32 +08:00 committed by GitHub
parent 79f2c194f0
commit 9ef209ffbd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 260 additions and 82 deletions

View File

@ -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)

View File

@ -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',

View File

@ -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>

View File

@ -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 })
}