Skip to content

Commit

Permalink
fix(ui): ui/input,checkbox,checkbox-group,radio,radio-group原型完成 优化父子组件通信
Browse files Browse the repository at this point in the history
affects: @varlet/cli, @varlet/icons, @varlet/ui
  • Loading branch information
haoziqaq committed Jan 18, 2021
1 parent 8c9ba91 commit 3af4a62
Show file tree
Hide file tree
Showing 59 changed files with 1,810 additions and 913 deletions.
1 change: 1 addition & 0 deletions packages/varlet-cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"module": "commonjs",
"sourceMap": false,
"strict": true,
"downlevelIteration": true,
"declaration": true,
"skipLibCheck": true,
"esModuleInterop": true,
Expand Down
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF008-checkbox-blank-outline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF009-checkbox-marked.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF010-radio-blank.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF011-radio-marked.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions packages/varlet-ui/src/checkbox-group/CheckboxGroup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<template>
<div class="var-checkbox-group" :class="[`var-checkbox-group--${direction}`]" v-bind="$attrs">
<slot />
</div>
</template>

<script lang="ts">
import { defineComponent, computed, ComputedRef, watch } from 'vue'
import { props } from './props'
import { useAtChildrenCounter, useChildren } from '../utils/components'
import { CHECKBOX_GROUP_BIND_CHECKBOX_KEY, CHECKBOX_GROUP_COUNT_CHECKBOX_KEY, CheckboxGroupProvider } from './provide'
import { CheckboxProvider } from '../checkbox/provide'
export default defineComponent({
name: 'VarCheckboxGroup',
inheritAttrs: false,
props,
setup(props) {
const { bindChildren, childProviders: checkboxProviders } = useChildren<CheckboxGroupProvider, CheckboxProvider>(
CHECKBOX_GROUP_BIND_CHECKBOX_KEY
)
const { length } = useAtChildrenCounter(CHECKBOX_GROUP_COUNT_CHECKBOX_KEY)
const checkedCount: ComputedRef<number> = computed(() => props.modelValue.length)
const max: ComputedRef<number | string | undefined> = computed(() => props.max)
const onChecked = (changedValue: any) => {
if (!props.modelValue.includes(changedValue)) {
const changedModelValue = [...props.modelValue, changedValue]
props['onUpdate:modelValue']?.(changedModelValue)
props.onChange?.(changedModelValue)
}
}
const onUnchecked = (changedValue: any) => {
if (!props.modelValue.includes(changedValue)) {
return
}
const changedModelValue = props.modelValue.filter((value) => value !== changedValue)
props['onUpdate:modelValue']?.(changedModelValue)
props.onChange?.(changedModelValue)
}
const syncAllCheckbox = () => {
checkboxProviders.forEach(({ sync }) => sync(props.modelValue))
}
const checkAll = () => {
const checkedValues: any[] = checkboxProviders.map(({ checkedValue }) => checkedValue.value)
const changedModelValue: any[] = [...new Set(checkedValues)]
props['onUpdate:modelValue']?.(changedModelValue)
return changedModelValue
}
const uncheckAll = () => {
const changedModelValue: any[] = []
props['onUpdate:modelValue']?.(changedModelValue)
return changedModelValue
}
const inverseAll = () => {
const checkedValues: any[] = checkboxProviders
.filter(({ checked }) => !checked.value)
.map(({ checkedValue }) => checkedValue.value)
const changedModelValue: any[] = [...new Set(checkedValues)]
props['onUpdate:modelValue']?.(changedModelValue)
return changedModelValue
}
watch(
() => props.modelValue,
() => syncAllCheckbox(),
{ deep: true }
)
// checkbox insert or remove
watch(
() => length.value,
() => syncAllCheckbox()
)
bindChildren({
checkedCount,
max,
onChecked,
onUnchecked,
})
return {
checkAll,
uncheckAll,
inverseAll,
}
},
})
</script>

<style lang="less">
@import './checkboxGroup';
</style>
7 changes: 7 additions & 0 deletions packages/varlet-ui/src/checkbox-group/__tests__/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const CheckboxGroup = require('../../../cjs/checkbox-group').default
const { render } = require('@testing-library/vue')

test('test checkboxGroup', async () => {
const wrapper = render(CheckboxGroup)
console.log(wrapper)
})
12 changes: 12 additions & 0 deletions packages/varlet-ui/src/checkbox-group/checkboxGroup.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.var-checkbox-group {
display: flex;
flex-wrap: wrap;

&--horizontal {
flex-direction: row;
}

&--vertical {
flex-direction: column;
}
}
Empty file.
Empty file.
21 changes: 21 additions & 0 deletions packages/varlet-ui/src/checkbox-group/example/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<var-checkbox-group />
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import CheckboxGroup from '..'
export default defineComponent({
name: 'CheckboxGroupExample',
components: {
[CheckboxGroup.name]: CheckboxGroup,
},
})
</script>

<style scoped>
.example {
background: antiquewhite;
}
</style>
8 changes: 8 additions & 0 deletions packages/varlet-ui/src/checkbox-group/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { App } from 'vue'
import CheckboxGroup from './CheckboxGroup.vue'

CheckboxGroup.install = function (app: App) {
app.component(CheckboxGroup.name, CheckboxGroup)
}

export default CheckboxGroup
25 changes: 25 additions & 0 deletions packages/varlet-ui/src/checkbox-group/props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { PropType } from 'vue'

export function directionValidator(direction: string) {
return ['horizontal', 'vertical'].includes(direction)
}

export const props = {
modelValue: {
type: Array as PropType<Array<any>>,
default: [],
},
max: {
type: [String, Number],
},
direction: {
type: String,
default: 'horizontal',
},
onChange: {
type: Function,
},
'onUpdate:modelValue': {
type: Function,
},
}
11 changes: 11 additions & 0 deletions packages/varlet-ui/src/checkbox-group/provide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ComputedRef } from 'vue'

export interface CheckboxGroupProvider {
checkedCount: ComputedRef<number>
max: ComputedRef<number | string | undefined>
onChecked(value: any): void
onUnchecked(value: any): void
}

export const CHECKBOX_GROUP_BIND_CHECKBOX_KEY = Symbol('CHECKBOX_GROUP_BIND_CHECKBOX_KEY')
export const CHECKBOX_GROUP_COUNT_CHECKBOX_KEY = Symbol('CHECKBOX_GROUP_COUNT_CHECKBOX_KEY')
144 changes: 144 additions & 0 deletions packages/varlet-ui/src/checkbox/Checkbox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<template>
<div class="var-checkbox" @click="handleClick" v-bind="$attrs">
<div
class="var-checkbox__action"
v-ripple="{ disabled: disabled || !ripple }"
:class="[
checked ? 'var-checkbox--checked' : 'var-checkbox--unchecked',
disabled ? 'var-checkbox--disabled' : null,
]"
:style="{
color: checked ? checkedColor : uncheckedColor,
}"
>
<slot name="checked-icon" v-if="checked">
<var-icon
class="var-checkbox__icon"
name="checkbox-marked"
:style="{
fontSize: iconSize,
}"
/>
</slot>
<slot name="unchecked-icon" v-else>
<var-icon
class="var-checkbox__icon"
name="checkbox-blank-outline"
:class="[disabled ? 'var-checkbox--disabled' : null]"
:style="{
fontSize: iconSize,
}"
/>
</slot>
</div>
<div class="var-checkbox__text" :class="[disabled ? 'var-checkbox--disabled' : null]">
<slot />
</div>
</div>
</template>

<script lang="ts">
import { defineComponent, ref, Ref, computed, ComputedRef, watch } from 'vue'
import { props } from './props'
import Icon from '../icon'
import Ripple from '../ripple'
import { useAtParentIndex, useParent } from '../utils/components'
import {
CHECKBOX_GROUP_BIND_CHECKBOX_KEY,
CHECKBOX_GROUP_COUNT_CHECKBOX_KEY,
CheckboxGroupProvider,
} from '../checkbox-group/provide'
import { CheckboxProvider } from './provide'
export default defineComponent({
name: 'VarCheckbox',
directives: { Ripple },
components: {
[Icon.name]: Icon,
},
inheritAttrs: false,
props,
setup(props) {
const { bindParent, parentProvider: checkboxGroupProvider } = useParent<CheckboxGroupProvider, CheckboxProvider>(
CHECKBOX_GROUP_BIND_CHECKBOX_KEY
)
useAtParentIndex(CHECKBOX_GROUP_COUNT_CHECKBOX_KEY)
const value: Ref<any> = ref(false)
const checked: ComputedRef<boolean> = computed(() => value.value === props.checkedValue)
const checkedValue: ComputedRef<boolean> = computed(() => props.checkedValue)
watch(
() => props.modelValue,
(newValue) => {
value.value = newValue
},
{ immediate: true }
)
const toggle = (changedValue?: any) => {
if (props.disabled) {
return
}
// force toggle validate value
const isInvalidValue = changedValue !== props.uncheckedValue && changedValue !== props.checkedValue
if (changedValue != null && (isInvalidValue || changedValue === value.value)) {
return
}
// has parent check max
const forbidCheck = checkboxGroupProvider.checkedCount.value >= Number(checkboxGroupProvider.max.value)
if (checkboxGroupProvider && !checked.value && forbidCheck) {
return
}
if (changedValue == null) {
changedValue = checked.value ? props.uncheckedValue : props.checkedValue
}
value.value = changedValue
props['onUpdate:modelValue']?.(value.value)
props.onChange?.(value.value)
changedValue === props.checkedValue
? checkboxGroupProvider?.onChecked(props.checkedValue)
: checkboxGroupProvider?.onUnchecked(props.checkedValue)
}
const handleClick = (e: Event) => {
if (props.disabled) {
return
}
props.onClick?.(e)
toggle()
}
const sync = (values: Array<any>) => {
value.value = values.includes(props.checkedValue) ? props.checkedValue : props.uncheckedValue
}
const checkboxProvider: CheckboxProvider = {
checkedValue,
checked,
sync,
}
bindParent?.(checkboxProvider)
return {
checked,
handleClick,
toggle,
}
},
})
</script>

<style lang="less">
@import './checkbox';
</style>
7 changes: 7 additions & 0 deletions packages/varlet-ui/src/checkbox/__tests__/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const Checkbox = require('../../../cjs/checkbox').default
const { render } = require('@testing-library/vue')

test('test checkbox', async () => {
const wrapper = render(Checkbox)
console.log(wrapper)
})
Loading

0 comments on commit 3af4a62

Please sign in to comment.