Skip to content

Commit

Permalink
feat: expansion-panels
Browse files Browse the repository at this point in the history
  • Loading branch information
BeADre committed Jan 10, 2021
1 parent af88e04 commit 61c2694
Show file tree
Hide file tree
Showing 24 changed files with 536 additions and 71 deletions.
127 changes: 64 additions & 63 deletions packages/varlet-eslint-config/index.js
Original file line number Diff line number Diff line change
@@ -1,64 +1,65 @@
module.exports = {
extends: [
'airbnb-base',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-recommended',
'prettier',
'prettier/vue',
],
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
extraFileExtensions: ['.vue'],
},
plugins: ['@typescript-eslint'],
env: {
es6: true,
node: true,
browser: true,
},
rules: {
'no-new': 'off',
'no-shadow': 'off',
'no-bitwise': 'off',
'func-names': 'off',
'no-console': 'off',
'no-plusplus': 'off',
'default-case': 'off',
'prefer-template': 'off',
'consistent-return': 'off',
'no-param-reassign': 'off',
'no-nested-ternary': 'off',
'no-underscore-dangle': 'off',
'no-unused-expressions': 'off',
'no-restricted-globals': 'off',
'no-use-before-define': 'off',
'class-methods-use-this': 'off',
'global-require': 'off',
'prefer-destructuring': ['error', { object: true, array: false }],
// eslint-plugin-import
'import/order': 'off',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-dynamic-require': 'off',
// eslint-plugin-vue
'vue/comment-directive': 'off',
'vue/no-v-html': 'off',
'vue/attributes-order': 'off',
'vue/require-default-prop': 'off',
'vue/no-unused-components': 'off',
'vue/require-explicit-emits': 'off',
// typescript-eslint
'@typescript-eslint/camelcase': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off'
},
};
extends: [
'airbnb-base',
'plugin:@typescript-eslint/recommended',
'plugin:vue/vue3-recommended',
'prettier',
'prettier/vue',
],
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
extraFileExtensions: ['.vue'],
},
plugins: ['@typescript-eslint'],
env: {
es6: true,
node: true,
browser: true,
},
rules: {
'no-new': 'off',
'no-shadow': 'off',
'no-bitwise': 'off',
'func-names': 'off',
'no-console': 'off',
'no-plusplus': 'off',
'default-case': 'off',
'prefer-template': 'off',
'consistent-return': 'off',
'no-param-reassign': 'off',
'no-nested-ternary': 'off',
'no-underscore-dangle': 'off',
'no-unused-expressions': 'off',
'no-restricted-globals': 'off',
'no-use-before-define': 'off',
'class-methods-use-this': 'off',
'global-require': 'off',
'prefer-destructuring': ['error', { object: true, array: false }],
// eslint-plugin-import
'import/order': 'off',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-dynamic-require': 'off',
// eslint-plugin-vue
'vue/comment-directive': 'off',
'vue/no-v-html': 'off',
'vue/attributes-order': 'off',
'vue/require-default-prop': 'off',
'vue/no-unused-components': 'off',
'vue/require-explicit-emits': 'off',
// typescript-eslint
'@typescript-eslint/camelcase': 'off',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-extra-semi': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
}
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF007-chevron-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
139 changes: 139 additions & 0 deletions packages/varlet-ui/src/expansion-panel/ExpansionPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<template>
<div
:class="{
'var-expansion-panel': true,
'var-expansion-panel__active': isOpen,
'var-expansion-panel__disable': disabled,
}"
>
<div class="var-expansion-panel-header" @click="toggle()">
<div class="var-expansion-panel-header__title">
<slot name="title">{{ title }}</slot>
</div>
<div class="var-expansion-panel-header__icon">
<slot name="icon">
<var-icon
:name="icon"
:transition="400"
:class="{
'var-expansion-panel-header__icon': true,
'var-expansion-panel-header__open': isOpen && icon === 'chevron-down',
'var-expansion-panel-header__disable': disabled,
}"
/>
</slot>
</div>
</div>
<div class="var-expansion-panel-content" v-show="show" ref="contentEl" @transitionend="transitionend">
<div class="var-expansion-panel__wrap">
<slot></slot>
</div>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent, ref, Ref, nextTick, watch, ComputedRef, computed } from 'vue'
import { requestAnimationFrame } from '../utils/elements'
import { isArray } from '../utils/shared'
import { useParent, useAtParentIndex } from '../utils/components'
import {
EXPANSION_PANELS_BIND_EXPANSION_PANEL_KEY,
EXPANSION_PANELS_COUNT_EXPANSION_PANEL_KEY,
ExpansionPanelsProvider,
} from '../expansion-panels/provide'
import { ExpansionPanelProvider } from './provide'
import { props } from './props'
import Icon from '../icon'
export default defineComponent({
name: 'VarExpansionPanel',
components: {
[Icon.name]: Icon,
},
props,
setup(props) {
const { parentProvider: ExpansionPanelsProvider, bindParent } = useParent<
ExpansionPanelsProvider,
ExpansionPanelProvider
>(EXPANSION_PANELS_BIND_EXPANSION_PANEL_KEY)
const { index } = useAtParentIndex(EXPANSION_PANELS_COUNT_EXPANSION_PANEL_KEY)
const contentEl: Ref<HTMLDivElement | null> = ref(null)
const show: Ref<boolean> = ref(false)
const isOpen: Ref<boolean> = ref(false)
const isLock: Ref<boolean> = ref(false)
const { active, updateItem } = ExpansionPanelsProvider
const name: ComputedRef<number | string | undefined> = computed(() => props.name)
const init = (accordion: boolean) => {
Array.prototype.slice()
if (!active.value || (accordion && isArray(active.value))) return
const isShow = isArray(active.value)
? (active.value as Array<number | string | undefined>).includes(props.name)
: active.value === props.name
toggle(isShow, true)
}
const toggle = (isShow?: boolean, initOrAccordion?: boolean) => {
if (isLock.value || props.disabled || isOpen.value === isShow) return
isLock.value = true
isOpen.value = isShow === undefined ? !isOpen.value : isShow
if (!initOrAccordion) updateItem(props.name, isOpen.value)
}
const openPanel = () => {
if (!contentEl.value) return
show.value = true
nextTick(() => {
const { offsetHeight } = contentEl.value as HTMLDivElement
;(contentEl.value as HTMLDivElement).style.height = 0 + 'px'
requestAnimationFrame(() => {
;(contentEl.value as HTMLDivElement).style.height = offsetHeight + 'px'
})
})
}
const closePanel = () => {
if (!contentEl.value) return
;(contentEl.value as HTMLDivElement).style.height = 0 + 'px'
}
const transitionend = () => {
if (!isOpen.value) {
show.value = false
;(contentEl.value as HTMLDivElement).style.height = ''
}
isLock.value = false
}
const expansionPanelProvider: ExpansionPanelProvider = {
index,
name,
init,
toggle,
}
bindParent(expansionPanelProvider)
watch(isOpen, (value) => {
if (value) openPanel()
else closePanel()
})
return {
show,
isOpen,
toggle,
contentEl,
closePanel,
transitionend,
}
},
})
</script>

<style lang="less">
@import './expansionPanel';
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const ExpansionPanel = require('../../../cjs/expansion-panel').default
const { render } = require('@testing-library/vue')

test('test expansionPanel', async () => {
const wrapper = render(ExpansionPanel)
console.log(wrapper)
})
Empty file.
Empty file.
21 changes: 21 additions & 0 deletions packages/varlet-ui/src/expansion-panel/example/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<var-expansion-panel />
</template>

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

<style scoped>
.example {
background: antiquewhite;
}
</style>
75 changes: 75 additions & 0 deletions packages/varlet-ui/src/expansion-panel/expansionPanel.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
@import '../styles/var';

.var-expansion-panel {
box-sizing: border-box;
position: relative;
margin-top: 0;
background: #fff;
color: rgba(0, 0, 0, 0.87);
transition: margin-top 0.4s, color 0.4s;

&:before {
bottom: 0;
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: -1;
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}

&:not(:first-child):after {
border-top: thin solid rgba(0, 0, 0, 0.12);
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}

&-header {
align-items: center;
display: flex;
font-size: @font-size-md;
outline: none;
padding: 10px 16px;
justify-content: space-between;
position: relative;
width: 100%;

&__icon {
transform: rotate(0deg);
opacity: 1;
}

&__disable {
opacity: 0;
}

&__open {
transform: rotate(-180deg);
}
}

&-content {
transition: height 0.4s;
display: flex;
overflow: hidden;
}

&__wrap {
padding: 0 16px 10px;
word-break: break-all;
flex: 1;
}

&__active + &,
&__active:not(:first-child) {
margin-top: 16px;
}

&__disable {
color: rgba(0, 0, 0, 0.38);
}
}
8 changes: 8 additions & 0 deletions packages/varlet-ui/src/expansion-panel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { App } from 'vue'
import ExpansionPanel from './ExpansionPanel.vue'

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

export default ExpansionPanel
Loading

0 comments on commit 61c2694

Please sign in to comment.