-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Creates MediaObject component using Layout component Lots of examples Some new supporting Sass mixins Some new supporting JS utilities Updated and pinned vue-tsc and typescript because of vuejs/language-tools#5018
- Loading branch information
Showing
27 changed files
with
3,302 additions
and
1,623 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
<script setup lang="ts"> | ||
import { useCssModule, computed } from 'vue'; | ||
import mapClasses from '../../utils/mapClasses'; | ||
import { MediaObject, NameValuePair, HtmlAttributes } from '../../types/interfaces'; | ||
import type { Breakpoint } from '../../types/other'; | ||
import { modifyClassName } from '../../utils/buildClass'; | ||
import { getLayoutStyling } from '../../utils/mediaObject'; | ||
import CdrLayout from '../layout/CdrLayout.vue'; | ||
import { breakpoints, spacing } from '../../utils/other'; | ||
/** Component for buttons that have a checked state. */ | ||
defineOptions({ name: 'CdrMediaObject' }); | ||
const props = withDefaults(defineProps<MediaObject>(), { | ||
align: 'start', | ||
mediaPosition: 'left', | ||
mediaWidth: '1fr', | ||
mediaHeight: 'auto', | ||
mediaCover: false, | ||
overlay: false, | ||
overlayRowAlign: 'start', | ||
overlayColumnAlign: 'start', | ||
contentPadding: 'zero', | ||
}); | ||
const style = useCssModule(); | ||
const rootProps = computed(() => { | ||
const baseClass = 'cdr-media-object'; | ||
const classes = [baseClass]; | ||
const inlineStyles: NameValuePair = {}; | ||
const { | ||
align, | ||
mediaPosition, | ||
mediaWidth, | ||
mediaHeight, | ||
mediaCover, | ||
overlay, | ||
overlayRowAlign, | ||
overlayColumnAlign, | ||
contentPadding, | ||
...otherProps | ||
} = props; | ||
const additionalProps: HtmlAttributes = { ...otherProps }; | ||
if (contentPadding !== 'zero') { | ||
if (typeof contentPadding === 'string') { | ||
inlineStyles['--cdr-media-object-content-padding'] = spacing[contentPadding]; | ||
} else { | ||
classes.push(modifyClassName(baseClass, 'content-padding-cq')); | ||
breakpoints.forEach((breakpoint: Breakpoint) => { | ||
// Add in padding styles for various breakpoints | ||
inlineStyles[`--cdr-media-object-content-padding-${breakpoint}`] = | ||
spacing[contentPadding[breakpoint]]; | ||
}); | ||
} | ||
} | ||
// Enter overlay mode, which does not use these props, because they are not relevant: | ||
// mediaPosition, mediaWidth, mediaHeight, mediaCover, align | ||
if (overlay) { | ||
classes.push(modifyClassName(baseClass, 'overlay')); | ||
Object.assign(additionalProps, { rows: 'auto', columns: 'auto' }); | ||
inlineStyles['--cdr-media-object-row-align'] = overlayRowAlign; | ||
inlineStyles['--cdr-media-object-column-align'] = overlayColumnAlign; | ||
} else { | ||
// Get layout related props and inline styles based on media measurements and | ||
// content position, both of which can be dynamic | ||
const layoutStyling = getLayoutStyling(mediaPosition, mediaWidth, mediaHeight); | ||
Object.assign(inlineStyles, layoutStyling.inlineStyles); | ||
Object.assign(additionalProps, layoutStyling.props); | ||
// Add in class for allowing dynamic content positioning | ||
if (typeof mediaPosition !== 'string') { | ||
classes.push(modifyClassName(baseClass, 'media-position-cq')); | ||
} | ||
// Add align class and inline styles for allowing dynamic align values | ||
// or set the static value | ||
if (typeof align !== 'string') { | ||
classes.push(modifyClassName(baseClass, 'align-cq')); | ||
breakpoints.forEach((breakpoint: Breakpoint) => { | ||
// Add in media position styles for various breakpoints | ||
inlineStyles[`--cdr-media-object-align-${breakpoint}`] = align[breakpoint]; | ||
}); | ||
} else { | ||
inlineStyles['--cdr-media-object-align'] = align; | ||
} | ||
// Add cover class | ||
if (mediaCover) { | ||
classes.push(modifyClassName(baseClass, 'cover')); | ||
} | ||
} | ||
return { | ||
...additionalProps, | ||
class: mapClasses(style, ...classes) || undefined, | ||
style: inlineStyles, | ||
}; | ||
}); | ||
</script> | ||
|
||
<template> | ||
<CdrLayout v-bind="rootProps"> | ||
<div :class="style['cdr-media-object__media']"> | ||
<!-- @slot Where the media should be placed. Should be a single node. --> | ||
<slot name="media" /> | ||
</div> | ||
<div :class="style['cdr-media-object__content']"> | ||
<!-- @slot Where all content should be placed. Can be multiple nodes. --> | ||
<slot name="content" /> | ||
</div> | ||
</CdrLayout> | ||
</template> | ||
|
||
<style lang="scss" module src="./styles/CdrMediaObject.module.scss"></style> |
104 changes: 104 additions & 0 deletions
104
src/components/mediaObject/__tests__/CdrMediaObject.spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { markRaw } from 'vue'; | ||
import { mount } from '../../../../test/vue-jest-style-workaround.js'; | ||
import CdrMediaObject from '../CdrMediaObject.vue'; | ||
import CdrSurface from '../../surface/CdrSurface.vue'; | ||
|
||
const CdrSurfaceRaw = markRaw(CdrSurface); | ||
|
||
export const examples = [ | ||
{ | ||
label: 'default: media position left, media width 1fr, media height auto, align start', | ||
props: {}, | ||
}, | ||
{ | ||
label: 'content padding', | ||
props: { contentPadding: 'two-x' }, | ||
}, | ||
{ | ||
label: 'content padding dynamic', | ||
props: { contentPadding: { xs: 'one-x', sm: 'one-x', md: 'three-x', lg: 'three-x' } }, | ||
}, | ||
{ | ||
label: 'media width 100px', | ||
props: { mediaWidth: '100px' }, | ||
}, | ||
{ | ||
label: 'media width dynamic', | ||
props: { mediaWidth: { xs: '100px', sm: '100px', md: '300px', lg: '300px' } }, | ||
}, | ||
{ | ||
label: 'align center', | ||
props: { mediaWidth: 'auto', align: 'center' }, | ||
}, | ||
{ | ||
label: 'dynamic align', | ||
props: { mediaWidth: 'auto', align: { xs: 'center', sm: 'center', md: 'end', lg: 'start' } }, | ||
}, | ||
{ | ||
label: 'cover', | ||
props: { mediaWidth: '125px', mediaCover: true }, | ||
}, | ||
{ | ||
label: 'media position right', | ||
props: { | ||
mediaPosition: 'right', | ||
}, | ||
}, | ||
{ | ||
label: 'media position dynamic', | ||
props: { | ||
mediaPosition: { xs: 'top', sm: 'bottom', md: 'left', lg: 'right' }, | ||
}, | ||
}, | ||
{ | ||
label: 'media bottom', | ||
props: { | ||
mediaPosition: 'bottom', | ||
}, | ||
}, | ||
{ | ||
label: 'media top, align center', | ||
props: { | ||
mediaPosition: 'top', | ||
align: 'center', | ||
}, | ||
}, | ||
{ | ||
label: 'media position dynamic, media height dynamic, media width dynamic', | ||
props: { | ||
mediaWidth: { xs: '100%', sm: '100%', md: '50%', lg: '75%' }, | ||
mediaHeight: { xs: '100px', sm: '200px', md: 'auto', lg: 'auto' }, | ||
mediaPosition: { xs: 'top', sm: 'top', md: 'left', lg: 'left' }, | ||
mediaCover: true, | ||
}, | ||
}, | ||
{ | ||
label: 'overlay, row align, column align, content configured independently to 50% width', | ||
props: { | ||
overlay: true, | ||
overlayColumnAlign: 'end', | ||
overlayRowAlign: 'center', | ||
}, | ||
}, | ||
{ | ||
label: 'pass down props to Layout and Surface', | ||
props: { | ||
background: 'brand-spruce', | ||
as: CdrSurfaceRaw, | ||
}, | ||
}, | ||
]; | ||
|
||
describe('CdrMediaObject', () => { | ||
describe('snapshot tests', () => { | ||
examples.forEach(({ label, props }) => { | ||
it(label, () => { | ||
const wrapper = mount(CdrMediaObject, { | ||
props, | ||
slots: { content: 'Some content', media: 'Some media' }, | ||
}); | ||
expect(wrapper.element).toMatchSnapshot(); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.