diff --git a/packages/vuetify/src/components/VDivider/VDivider.sass b/packages/vuetify/src/components/VDivider/VDivider.sass index 5b4aad59b66..f96a27b066c 100644 --- a/packages/vuetify/src/components/VDivider/VDivider.sass +++ b/packages/vuetify/src/components/VDivider/VDivider.sass @@ -1,39 +1,36 @@ @import './_variables.scss' -+theme(v-divider) using ($material) - border-color: map-get($material, 'dividers') - .v-divider + @include border($divider-query) + display: block - flex: 1 1 0px - max-width: 100% + flex: $divider-flex height: 0px max-height: 0px - border: solid - border-width: thin 0 0 0 transition: inherit - &--inset:not(.v-divider--vertical) - max-width: calc(100% - #{$divider-inset-margin}) - +ltr() - margin-left: $divider-inset-margin - - +rtl() - margin-right: $divider-inset-margin - &--vertical align-self: stretch - border: solid - border-width: 0 thin 0 0 + border-width: $divider-vertical-border-width display: inline-flex height: inherit - min-height: 100% + margin-left: $divider-vertical-margin-left max-height: 100% max-width: 0px - width: 0px vertical-align: text-bottom + width: 0px + + &--inset + &:not(.v-divider--vertical) + max-width: $divider-inset-max-width + + @include ltr() + margin-left: $divider-inset-margin + + @include rtl() + margin-right: $divider-inset-margin - &.v-divider--inset - margin-top: $divider-inset-margin-top - min-height: 0 - max-height: $divider-inset-max-height + &.v-divider--vertical + margin-bottom: $divider-vertical-inset-margin-bottom + margin-top: $divider-vertical-inset-margin-top + max-height: $divider-vertical-inset-max-height diff --git a/packages/vuetify/src/components/VDivider/VDivider.ts b/packages/vuetify/src/components/VDivider/VDivider.ts index 1d32b4d1bec..ac50550fd98 100644 --- a/packages/vuetify/src/components/VDivider/VDivider.ts +++ b/packages/vuetify/src/components/VDivider/VDivider.ts @@ -1,42 +1,64 @@ -// @ts-nocheck -/* eslint-disable */ - // Styles import './VDivider.sass' -// Types -import { VNode } from 'vue' +// Utilities +import { computed, defineComponent, h } from 'vue' +import { convertToUnit } from '@/util/helpers' +import makeProps from '@/util/makeProps' -// Mixins -import Themeable from '../../mixins/themeable' +// Composables +import { useTheme } from '@/composables' + +// Types +type DividerKey = 'borderRightWidth' | 'borderTopWidth' | 'maxHeight' | 'maxWidth' +type DividerStyles = Partial> -export default Themeable.extend({ - name: 'v-divider', +export default defineComponent({ + name: 'VDivider', props: { - inset: Boolean, - vertical: Boolean, + ...makeProps({ + inset: Boolean, + length: [Number, String], + thickness: [Number, String], + vertical: Boolean, + }), }, - render (h): VNode { - // WAI-ARIA attributes - let orientation - if (!this.$attrs.role || this.$attrs.role === 'separator') { - orientation = this.vertical ? 'vertical' : 'horizontal' - } - return h('hr', { - class: { - 'v-divider': true, - 'v-divider--inset': this.inset, - 'v-divider--vertical': this.vertical, - ...this.themeClasses, - }, - attrs: { - role: 'separator', - 'aria-orientation': orientation, - ...this.$attrs, - }, - on: this.$listeners, + setup (props, { attrs }) { + const { themeClasses } = useTheme() + const dividerStyles = computed(() => { + const styles: DividerStyles = {} + + if (props.length) { + styles[props.vertical ? 'maxHeight' : 'maxWidth'] = convertToUnit(props.length) + } + + if (props.thickness) { + styles[props.vertical ? 'borderRightWidth' : 'borderTopWidth'] = convertToUnit(props.thickness) + } + + return styles }) + + return () => ( + h('hr', { + class: [ + 'v-divider', + { + 'v-divider--inset': props.inset, + 'v-divider--vertical': props.vertical, + }, + themeClasses.value, + ], + style: [ + dividerStyles.value, + ], + ariaOrientation: !attrs.role || attrs.role === 'separator' + ? props.vertical ? 'vertical' : 'horizontal' + : undefined, + role: attrs.role || 'separator', + }) + ) }, }) diff --git a/packages/vuetify/src/components/VDivider/__tests__/VDivider.spec.ts b/packages/vuetify/src/components/VDivider/__tests__/VDivider.spec.ts index 4de0b423a32..e97e619d1c3 100644 --- a/packages/vuetify/src/components/VDivider/__tests__/VDivider.spec.ts +++ b/packages/vuetify/src/components/VDivider/__tests__/VDivider.spec.ts @@ -1,105 +1,50 @@ -// @ts-nocheck -/* eslint-disable */ - -// Libraries -// import Vue from 'vue' - // Components -// import VDivider from '../VDivider' +import VDivider from '../VDivider' // Utilities -import { - createLocalVue, - mount, - Wrapper, -} from '@vue/test-utils' - -describe.skip('VDivider', () => { - let mountFunction: (options?: object) => Wrapper - let localVue: typeof Vue - - beforeEach(() => { - localVue = createLocalVue() - - mountFunction = (options = {}) => { - return mount(VDivider, { - localVue, - ...options, - }) - } - }) - - it('should render component and match snapshot', () => { - const wrapper = mountFunction() - - expect(wrapper.html()).toMatchSnapshot() - }) - - it('should render an inset component', () => { - const wrapper = mountFunction({ - propsData: { inset: true }, +import { createTheme, VuetifyThemeSymbol } from '@/composables' +import { mount } from '@vue/test-utils' +import { VuetifySymbol } from '@/framework' + +describe('VDivider', () => { + function mountFunction (options = {}) { + return mount(VDivider, { + global: { + provide: { + [VuetifySymbol as symbol]: { defaults: { global: {} } }, + [VuetifyThemeSymbol as symbol]: createTheme(), + }, + }, + ...options, }) + } - expect(wrapper.classes('v-divider--inset')).toBe(true) - }) - - it('should render a light component', () => { - const wrapper = mountFunction({ - propsData: { light: true }, - }) - - expect(wrapper.classes('theme--light')).toBe(true) - }) - - it('should render a dark component', () => { - const wrapper = mountFunction({ - propsData: { dark: true }, - }) - - expect(wrapper.classes('theme--dark')).toBe(true) - }) - - it('should render a vertical component', () => { - const wrapper = mountFunction({ - propsData: { vertical: true }, - }) - - expect(wrapper.classes('v-divider--vertical')).toBe(true) - }) - - it('should have separator role by default', () => { - const wrapper = mountFunction() - - expect(wrapper.attributes('role')).toBe('separator') - }) - - it('should have aria-orientation horizontal by default', () => { + it('should match a snapshot', () => { const wrapper = mountFunction() - expect(wrapper.attributes('aria-orientation')).toBe('horizontal') - }) - - it('should have aria-orientation vertical if vertical prop is set', () => { - const wrapper = mountFunction({ - propsData: { vertical: true }, - }) - - expect(wrapper.attributes('aria-orientation')).toBe('vertical') + expect(wrapper.html()).toMatchSnapshot() }) - it('should have presentation role if set in attrs', () => { - const wrapper = mountFunction({ - attrs: { role: 'presentation' }, - }) + it.each([ + [{ length: 256 }, 'max-width: 256px;'], + [{ length: '128', vertical: true }, 'max-height: 128px;'], + [{ thickness: 2 }, 'border-top-width: 2px;'], + [{ thickness: '5', vertical: true }, 'border-right-width: 5px;'], + ])('should have correct styles for %s', (propsData, expected) => { + const wrapper = mountFunction({ propsData }) - expect(wrapper.attributes('role')).toBe('presentation') + expect(wrapper.attributes('style')).toEqual(expected) }) - it('should have no aria-orientation if presentation role is set in attrs', () => { - const wrapper = mountFunction({ - attrs: { role: 'presentation' }, - }) + it.each([ + [{}, ['horizontal', 'separator']], + [{ vertical: true }, ['vertical', 'separator']], + [{ role: 'foo' }, [undefined, 'foo']], + ])('should have correct attributes for %s', (propsData, expected) => { + const wrapper = mountFunction({ propsData }) + const [ariaorientation, role] = expected - expect(wrapper.attributes('aria-orientation')).toBeUndefined() + expect(wrapper.attributes().ariaorientation).toBe(ariaorientation) + expect(wrapper.attributes().role).toBe(role) }) }) diff --git a/packages/vuetify/src/components/VDivider/__tests__/__snapshots__/VDivider.spec.ts.snap b/packages/vuetify/src/components/VDivider/__tests__/__snapshots__/VDivider.spec.ts.snap index 0a28d8bdcb0..3d081a84a51 100644 --- a/packages/vuetify/src/components/VDivider/__tests__/__snapshots__/VDivider.spec.ts.snap +++ b/packages/vuetify/src/components/VDivider/__tests__/__snapshots__/VDivider.spec.ts.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`VDivider should render component and match snapshot 1`] = ` - `; diff --git a/packages/vuetify/src/components/VDivider/_variables.scss b/packages/vuetify/src/components/VDivider/_variables.scss index 464bb2d9a36..13928a95318 100644 --- a/packages/vuetify/src/components/VDivider/_variables.scss +++ b/packages/vuetify/src/components/VDivider/_variables.scss @@ -1,5 +1,31 @@ @import '../../styles/styles.sass'; +// Defaults +$divider-border-color: rgba(var(--v-border-color), var(--v-border-opacity)) !default; +$divider-border-style: solid !default; +$divider-border-width: thin 0 0 0 !default; +$divider-flex: 1 1 100% !default; +$divider-margin: 8px !default; + +$divider-query: () !default; +$divider-query: map-deep-merge( + ( + 'border-color': $divider-border-color, + 'border-style': $divider-border-style, + 'border-width': $divider-border-width + ), + $divider-query +); + +// Inset $divider-inset-margin: 72px !default; -$divider-inset-margin-top: 8px !default; -$divider-inset-max-height: calc(100% - 16px) !default; +$divider-inset-max-width: calc(100% - #{$divider-inset-margin}) !default; + +// Vertical +$divider-vertical-border-width: 0 thin 0 0 !default; +$divider-vertical-margin-left: -1px !default; + +// Vertical & Inset +$divider-vertical-inset-margin-bottom: $divider-margin !default; +$divider-vertical-inset-margin-top: $divider-margin !default; +$divider-vertical-inset-max-height: calc(100% - #{$divider-margin * 2}) !default; diff --git a/packages/vuetify/src/components/index.ts b/packages/vuetify/src/components/index.ts index 88c01096021..6961a4def37 100644 --- a/packages/vuetify/src/components/index.ts +++ b/packages/vuetify/src/components/index.ts @@ -25,7 +25,7 @@ export * from './VApp' // export * from './VDataTable' // export * from './VDatePicker' // export * from './VDialog' -// export * from './VDivider' +export * from './VDivider' // export * from './VExpansionPanel' // export * from './VFileInput' // export * from './VFooter'